Implements include/exclude register lists for translation.

This allows better debugging of register encodings into
instructions, in the integrated assembler.

BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/1571433004 .
diff --git a/src/IceCfg.h b/src/IceCfg.h
index 338f8f1..47bdd04 100644
--- a/src/IceCfg.h
+++ b/src/IceCfg.h
@@ -51,7 +51,7 @@
   uint32_t getSequenceNumber() const { return SequenceNumber; }
 
   static constexpr VerboseMask defaultVerboseMask() {
-    return IceV_All & ~IceV_Status;
+    return IceV_All & ~IceV_Status & ~IceV_AvailableRegs;
   }
   /// Returns true if any of the specified options in the verbose mask are set.
   /// If the argument is omitted, it checks if any verbose options at all are
diff --git a/src/IceClFlags.cpp b/src/IceClFlags.cpp
index 6d5b30c..28db1b0 100644
--- a/src/IceClFlags.cpp
+++ b/src/IceClFlags.cpp
@@ -293,6 +293,17 @@
     "nop-insertion-percentage",
     cl::desc("Nop insertion probability as percentage"), cl::init(10));
 
+/// Restricts registers in corresponding register classes to specified list.
+cl::list<std::string> UseRestrictedRegisters(
+    "reg-use", cl::CommaSeparated,
+    cl::desc(
+        "Only use specified registers for corresponding register classes"));
+
+/// List of excluded registers.
+cl::list<std::string>
+    ExcludedRegisters("reg-exclude", cl::CommaSeparated,
+                      cl::desc("Don't use specified registers"));
+
 /// Verbose options (can be comma-separated).
 cl::list<Ice::VerboseItem> VerboseList(
     "verbose", cl::CommaSeparated,
@@ -315,6 +326,8 @@
         clEnumValN(Ice::IceV_Loop, "loop", "Loop nest depth analysis"),
         clEnumValN(Ice::IceV_Status, "status",
                    "Print the name of the function being translated"),
+        clEnumValN(Ice::IceV_AvailableRegs, "registers",
+                   "Show available registers for register allocation"),
         clEnumValN(Ice::IceV_All, "all", "Use all verbose options"),
         clEnumValN(Ice::IceV_Most, "most",
                    "Use all verbose options except 'regalloc'"),
@@ -487,6 +500,9 @@
   // size_t and 64-bit fields.
   OutFlags.NumTranslationThreads = 0;
   OutFlags.RandomSeed = 0;
+  // Unordered set fields.
+  OutFlags.clearExcludedRegisters();
+  OutFlags.clearUseRestrictedRegisters();
 }
 
 void ClFlags::getParsedClFlags(ClFlags &OutFlags) {
@@ -513,6 +529,7 @@
   OutFlags.setDisableTranslation(::DisableTranslation);
   OutFlags.setDumpStats(::DumpStats);
   OutFlags.setEnableBlockProfile(::EnableBlockProfile);
+  OutFlags.setExcludedRegisters(::ExcludedRegisters);
   OutFlags.setForceMemIntrinOpt(::ForceMemIntrinOpt);
   OutFlags.setFunctionSections(::FunctionSections);
   OutFlags.setNumTranslationThreads(::NumThreads);
@@ -542,6 +559,7 @@
   OutFlags.setTimingFocusOn(::TimingFocusOn);
   OutFlags.setTranslateOnly(::TranslateOnly);
   OutFlags.setUseNonsfi(::UseNonsfi);
+  OutFlags.setUseRestrictedRegisters(::UseRestrictedRegisters);
   OutFlags.setUseSandboxing(::UseSandboxing);
   OutFlags.setVerboseFocusOn(::VerboseFocusOn);
   OutFlags.setOutFileType(::OutFileType);
diff --git a/src/IceClFlags.h b/src/IceClFlags.h
index d89186c..ee650c4 100644
--- a/src/IceClFlags.h
+++ b/src/IceClFlags.h
@@ -28,6 +28,8 @@
   ClFlags &operator=(const ClFlags &) = delete;
 
 public:
+  using StringVector = std::vector<IceString>;
+
   /// User defined constructor.
   ClFlags() { resetClFlags(*this); }
 
@@ -115,6 +117,16 @@
   /// Set ClFlags::EnableBlockProfile to a new value
   void setEnableBlockProfile(bool NewValue) { EnableBlockProfile = NewValue; }
 
+  /// Get the restricted list of registers to use, for corresponding register
+  /// classes, in register allocation.
+  const StringVector &getUseRestrictedRegisters() const {
+    return UseRestrictedRegisters;
+  }
+  void clearUseRestrictedRegisters() { UseRestrictedRegisters.clear(); }
+  void setUseRestrictedRegisters(const StringVector &Registers) {
+    UseRestrictedRegisters = Registers;
+  }
+
   /// Get the value of ClFlags::ForceMemIntrinOpt
   bool getForceMemIntrinOpt() const { return ForceMemIntrinOpt; }
   /// Set ClFlags::ForceMemIntrinOpt to a new value
@@ -186,6 +198,13 @@
   /// Set ClFlags::UseNonsfi to a new value
   void setUseNonsfi(bool NewValue) { UseNonsfi = NewValue; }
 
+  /// Get the list of registers exluded in register allocation.
+  const StringVector &getExcludedRegisters() const { return ExcludedRegisters; }
+  void clearExcludedRegisters() { ExcludedRegisters.clear(); }
+  void setExcludedRegisters(const StringVector &Registers) {
+    ExcludedRegisters = Registers;
+  }
+
   /// Get the value of ClFlags::UseSandboxing
   bool getUseSandboxing() const { return UseSandboxing; }
   /// Set ClFlags::UseSandboxing to a new value
@@ -390,6 +409,8 @@
   bool DumpStats;
   /// see anonymous_namespace{IceClFlags.cpp}::EnableBlockProfile
   bool EnableBlockProfile;
+  /// see anonymous_namespace{IceClFlags.cpp}::ExcludedRegisters;
+  StringVector ExcludedRegisters;
   /// see anonymous_namespace{IceClFlags.cpp}::ForceMemIntrinOpt
   bool ForceMemIntrinOpt;
   /// see anonymous_namespace{IceClFlags.cpp}::FunctionSections
@@ -422,6 +443,8 @@
   bool TimeEachFunction;
   /// see anonymous_namespace{IceClFlags.cpp}::UseNonsfi
   bool UseNonsfi;
+  /// see anonymous_namespace{IceClFlags.cpp}::UseRegistrictedRegisters;
+  StringVector UseRestrictedRegisters;
   /// see anonymous_namespace{IceClFlags.cpp}::UseSandboxing
   bool UseSandboxing;
   /// see anonymous_namespace{IceClFlags.cpp}::OLevel
diff --git a/src/IceDefs.h b/src/IceDefs.h
index ceb6fd0..e2799eb 100644
--- a/src/IceDefs.h
+++ b/src/IceDefs.h
@@ -242,6 +242,7 @@
   IceV_RMW = 1 << 12,
   IceV_Loop = 1 << 13,
   IceV_Status = 1 << 14,
+  IceV_AvailableRegs = 1 << 15,
   IceV_All = ~IceV_None,
   IceV_Most = IceV_All & ~IceV_LinearScan
 };
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index 8a53271..0b1dc76 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -277,7 +277,7 @@
   ProfileBlockInfoVarDecl->setSuppressMangling();
   ProfileBlockInfoVarDecl->setLinkage(llvm::GlobalValue::ExternalLinkage);
 
-  TargetLowering::staticInit(Flags);
+  TargetLowering::staticInit(this);
 }
 
 void GlobalContext::translateFunctions() {
diff --git a/src/IceRegistersMIPS32.h b/src/IceRegistersMIPS32.h
index 8d519d7..89c4d89 100644
--- a/src/IceRegistersMIPS32.h
+++ b/src/IceRegistersMIPS32.h
@@ -58,6 +58,8 @@
   return GPRRegister(RegNum - Reg_GPR_First);
 }
 
+const char *getRegName(int32_t RegNum);
+
 } // end of namespace RegMIPS32
 
 // Extend enum RegClass with MIPS32-specific register classes (if any).
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index 04f77e6..4f19226 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -39,7 +39,7 @@
 //       createTargetDataLowering(Ice::GlobalContext*);
 //   unique_ptr<Ice::TargetHeaderLowering>
 //       createTargetHeaderLowering(Ice::GlobalContext *);
-//   void staticInit(const ::Ice::ClFlags &Flags);
+//   void staticInit(::Ice::GlobalContext *);
 // }
 #define SUBZERO_TARGET(X)                                                      \
   namespace X {                                                                \
@@ -49,7 +49,7 @@
   createTargetDataLowering(::Ice::GlobalContext *Ctx);                         \
   std::unique_ptr<::Ice::TargetHeaderLowering>                                 \
   createTargetHeaderLowering(::Ice::GlobalContext *Ctx);                       \
-  void staticInit(const ::Ice::ClFlags &Flags);                                \
+  void staticInit(::Ice::GlobalContext *Ctx);                                  \
   } // end of namespace X
 #include "llvm/Config/SZTargets.def"
 #undef SUBZERO_TARGET
@@ -116,6 +116,102 @@
   return nullptr;
 }
 
+namespace {
+
+void printRegisterSet(Ostream &Str, const llvm::SmallBitVector &Bitset,
+                      std::function<IceString(int32_t)> getRegName,
+                      const IceString &LineIndentString) {
+  constexpr size_t RegistersPerLine = 16;
+  size_t Count = 0;
+  for (int i = Bitset.find_first(); i != -1; i = Bitset.find_next(i)) {
+    if (Count == 0) {
+      Str << LineIndentString;
+    } else {
+      Str << ",";
+    }
+    if (Count > 0 && Count % RegistersPerLine == 0)
+      Str << "\n" << LineIndentString;
+    ++Count;
+    Str << getRegName(i);
+  }
+  if (Count)
+    Str << "\n";
+}
+
+} // end of anonymous namespace
+
+void TargetLowering::filterTypeToRegisterSet(
+    GlobalContext *Ctx, int32_t NumRegs,
+    llvm::SmallBitVector TypeToRegisterSet[], size_t TypeToRegisterSetSize,
+    std::function<IceString(int32_t)> getRegName) {
+  llvm::SmallBitVector ExcludeBitSet(NumRegs);
+  std::vector<llvm::SmallBitVector> UseSet(TypeToRegisterSetSize,
+                                           ExcludeBitSet);
+  ExcludeBitSet.flip();
+
+  std::unordered_map<IceString, int32_t> RegNameToIndex;
+  for (int32_t RegIndex = 0; RegIndex < NumRegs; ++RegIndex)
+    RegNameToIndex[getRegName(RegIndex)] = RegIndex;
+
+  ClFlags::StringVector BadRegNames;
+  for (const IceString &RegName : Ctx->getFlags().getUseRestrictedRegisters()) {
+    if (!RegNameToIndex.count(RegName)) {
+      BadRegNames.push_back(RegName);
+      continue;
+    }
+    const int32_t RegIndex = RegNameToIndex[RegName];
+    for (SizeT TypeIndex = 0; TypeIndex < TypeToRegisterSetSize; ++TypeIndex)
+      UseSet[TypeIndex][RegIndex] = TypeToRegisterSet[TypeIndex][RegIndex];
+  }
+
+  for (const IceString &RegName : Ctx->getFlags().getExcludedRegisters()) {
+    if (!RegNameToIndex.count(RegName)) {
+      BadRegNames.push_back(RegName);
+      continue;
+    }
+    ExcludeBitSet[RegNameToIndex[RegName]] = false;
+  }
+
+  if (!BadRegNames.empty()) {
+    std::string Buffer;
+    llvm::raw_string_ostream StrBuf(Buffer);
+    StrBuf << "Unrecognized use/exclude registers:";
+    for (const auto &RegName : BadRegNames)
+      StrBuf << " " << RegName;
+    llvm::report_fatal_error(StrBuf.str());
+  }
+
+  // Apply filters.
+  for (size_t TypeIndex = 0; TypeIndex < TypeToRegisterSetSize; ++TypeIndex) {
+    llvm::SmallBitVector *TypeBitSet = &TypeToRegisterSet[TypeIndex];
+    llvm::SmallBitVector *UseBitSet = &UseSet[TypeIndex];
+    if (UseBitSet->any())
+      *TypeBitSet = *UseBitSet;
+    *TypeBitSet &= ExcludeBitSet;
+  }
+
+  // Display filtered register sets, if requested.
+  if (BuildDefs::dump() && NumRegs &&
+      (Ctx->getFlags().getVerbose() & IceV_AvailableRegs)) {
+    Ostream &Str = Ctx->getStrDump();
+    const IceString Indent = "  ";
+    const IceString IndentTwice = Indent + Indent;
+    Str << "Registers available for register allocation:\n";
+    for (size_t TypeIndex = 0; TypeIndex < TypeToRegisterSetSize; ++TypeIndex) {
+      Str << Indent;
+      if (TypeIndex < IceType_NUM) {
+        Str << typeString(static_cast<Type>(TypeIndex));
+      } else {
+        Str << "other[" << TypeIndex << "]";
+      }
+      Str << ":\n";
+      printRegisterSet(Str, TypeToRegisterSet[TypeIndex], getRegName,
+                       IndentTwice);
+    }
+    Str << "\n";
+  }
+}
+
 std::unique_ptr<TargetLowering>
 TargetLowering::createLowering(TargetArch Target, Cfg *Func) {
   switch (Target) {
@@ -129,8 +225,8 @@
   }
 }
 
-void TargetLowering::staticInit(const ClFlags &Flags) {
-  const TargetArch Target = Flags.getTargetArch();
+void TargetLowering::staticInit(GlobalContext *Ctx) {
+  const TargetArch Target = Ctx->getFlags().getTargetArch();
   // Call the specified target's static initializer.
   switch (Target) {
   default:
@@ -142,7 +238,7 @@
       return;                                                                  \
     }                                                                          \
     InitGuard##X = true;                                                       \
-    ::X::staticInit(Flags);                                                    \
+    ::X::staticInit(Ctx);                                                      \
   } break;
 #include "llvm/Config/SZTargets.def"
 #undef SUBZERO_TARGET
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index 799872e..71536cd 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -152,9 +152,9 @@
   TargetLowering &operator=(const TargetLowering &) = delete;
 
 public:
-  static void staticInit(const ClFlags &Flags);
+  static void staticInit(GlobalContext *Ctx);
   // Each target must define a public static method:
-  //   static void staticInit(const ClFlags &Flags);
+  //   static void staticInit(GlobalContext *Ctx);
 
   static std::unique_ptr<TargetLowering> createLowering(TargetArch Target,
                                                         Cfg *Func);
@@ -299,6 +299,12 @@
 
 protected:
   explicit TargetLowering(Cfg *Func);
+  // Applies command line filters to TypeToRegisterSet array.
+  static void
+  filterTypeToRegisterSet(GlobalContext *Ctx, int32_t NumRegs,
+                          llvm::SmallBitVector TypeToRegisterSet[],
+                          size_t TypeToRegisterSetSize,
+                          std::function<IceString(int32_t)> getRegName);
   virtual void lowerAlloca(const InstAlloca *Inst) = 0;
   virtual void lowerArithmetic(const InstArithmetic *Inst) = 0;
   virtual void lowerAssign(const InstAssign *Inst) = 0;
diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp
index 3ee3ade..477fe9f 100644
--- a/src/IceTargetLoweringARM32.cpp
+++ b/src/IceTargetLoweringARM32.cpp
@@ -50,8 +50,8 @@
   return ::Ice::ARM32::TargetHeaderARM32::create(Ctx);
 }
 
-void staticInit(const ::Ice::ClFlags &Flags) {
-  ::Ice::ARM32::TargetARM32::staticInit(Flags);
+void staticInit(::Ice::GlobalContext *Ctx) {
+  ::Ice::ARM32::TargetARM32::staticInit(Ctx);
 }
 
 } // end of namespace ARM32
@@ -277,8 +277,8 @@
     : TargetLowering(Func), NeedSandboxing(Ctx->getFlags().getUseSandboxing()),
       CPUFeatures(Func->getContext()->getFlags()) {}
 
-void TargetARM32::staticInit(const ClFlags &Flags) {
-  (void)Flags;
+void TargetARM32::staticInit(GlobalContext *Ctx) {
+
   // Limit this size (or do all bitsets need to be the same width)???
   llvm::SmallBitVector IntegerRegisters(RegARM32::Reg_NUM);
   llvm::SmallBitVector I64PairRegisters(RegARM32::Reg_NUM);
@@ -331,6 +331,20 @@
   TypeToRegisterSet[IceType_v8i16] = VectorRegisters;
   TypeToRegisterSet[IceType_v4i32] = VectorRegisters;
   TypeToRegisterSet[IceType_v4f32] = VectorRegisters;
+
+  filterTypeToRegisterSet(
+      Ctx, RegARM32::Reg_NUM, TypeToRegisterSet, RegARM32::RCARM32_NUM,
+      [](int32_t RegNum) -> IceString {
+        IceString Name = RegARM32::getRegName(RegNum);
+        constexpr const char RegSeparator[] = ", ";
+        constexpr size_t RegSeparatorWidth =
+            llvm::array_lengthof(RegSeparator) - 1;
+        for (size_t Pos = Name.find(RegSeparator); Pos != std::string::npos;
+             Pos = Name.find(RegSeparator)) {
+          Name.replace(Pos, RegSeparatorWidth, ":");
+        }
+        return Name;
+      });
 }
 
 namespace {
@@ -1874,7 +1888,7 @@
                                                  RegSetMask Exclude) const {
   llvm::SmallBitVector Registers(RegARM32::Reg_NUM);
 
-  for (int i = 0; i < RegARM32::Reg_NUM; ++i) {
+  for (int32_t i = 0; i < RegARM32::Reg_NUM; ++i) {
     const auto &Entry = RegARM32::RegTable[i];
     if (Entry.Scratch && (Include & RegSet_CallerSave))
       Registers[i] = true;
diff --git a/src/IceTargetLoweringARM32.h b/src/IceTargetLoweringARM32.h
index 0d7d9ce..70c38fa 100644
--- a/src/IceTargetLoweringARM32.h
+++ b/src/IceTargetLoweringARM32.h
@@ -57,7 +57,7 @@
   TargetARM32 &operator=(const TargetARM32 &) = delete;
 
 public:
-  static void staticInit(const ClFlags &Flags);
+  static void staticInit(GlobalContext *Ctx);
   // TODO(jvoung): return a unique_ptr.
   static std::unique_ptr<::Ice::TargetLowering> create(Cfg *Func) {
     return makeUnique<TargetARM32>(Func);
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
index 57f79f6..4f1f7bf 100644
--- a/src/IceTargetLoweringMIPS32.cpp
+++ b/src/IceTargetLoweringMIPS32.cpp
@@ -45,8 +45,8 @@
   return ::Ice::MIPS32::TargetHeaderMIPS32::create(Ctx);
 }
 
-void staticInit(const ::Ice::ClFlags &Flags) {
-  ::Ice::MIPS32::TargetMIPS32::staticInit(Flags);
+void staticInit(::Ice::GlobalContext *Ctx) {
+  ::Ice::MIPS32::TargetMIPS32::staticInit(Ctx);
 }
 } // end of namespace MIPS32
 
@@ -64,8 +64,8 @@
 
 TargetMIPS32::TargetMIPS32(Cfg *Func) : TargetLowering(Func) {}
 
-void TargetMIPS32::staticInit(const ClFlags &Flags) {
-  (void)Flags;
+void TargetMIPS32::staticInit(GlobalContext *Ctx) {
+  (void)Ctx;
   llvm::SmallBitVector IntegerRegisters(RegMIPS32::Reg_NUM);
   llvm::SmallBitVector I64PairRegisters(RegMIPS32::Reg_NUM);
   llvm::SmallBitVector Float32Registers(RegMIPS32::Reg_NUM);
@@ -106,6 +106,11 @@
   TypeToRegisterSet[IceType_v8i16] = VectorRegisters;
   TypeToRegisterSet[IceType_v4i32] = VectorRegisters;
   TypeToRegisterSet[IceType_v4f32] = VectorRegisters;
+
+  filterTypeToRegisterSet(Ctx, RegMIPS32::Reg_NUM, TypeToRegisterSet,
+                          RCMIPS32_NUM, [](int32_t RegNum) -> IceString {
+                            return RegMIPS32::getRegName(RegNum);
+                          });
 }
 
 void TargetMIPS32::translateO2() {
@@ -262,19 +267,28 @@
   return false;
 }
 
-IceString TargetMIPS32::getRegName(SizeT RegNum, Type Ty) const {
-  assert(RegNum < RegMIPS32::Reg_NUM);
-  (void)Ty;
-  static const char *RegNames[] = {
+namespace {
+
+const char *RegNames[RegMIPS32::Reg_NUM] = {
 #define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt,    \
           isI64Pair, isFP32, isFP64, isVec128, alias_init)                     \
   name,
-      REGMIPS32_TABLE
+    REGMIPS32_TABLE
 #undef X
-  };
+};
+
+} // end of anonymous namespace
+
+const char *RegMIPS32::getRegName(int32_t RegNum) {
+  assert(RegNum < RegMIPS32::Reg_NUM);
   return RegNames[RegNum];
 }
 
+IceString TargetMIPS32::getRegName(SizeT RegNum, Type Ty) const {
+  (void)Ty;
+  return RegMIPS32::getRegName(RegNum);
+}
+
 Variable *TargetMIPS32::getPhysicalRegister(SizeT RegNum, Type Ty) {
   if (Ty == IceType_void)
     Ty = IceType_i32;
diff --git a/src/IceTargetLoweringMIPS32.h b/src/IceTargetLoweringMIPS32.h
index d3789f8..b91693e 100644
--- a/src/IceTargetLoweringMIPS32.h
+++ b/src/IceTargetLoweringMIPS32.h
@@ -33,7 +33,7 @@
 public:
   ~TargetMIPS32() override = default;
 
-  static void staticInit(const ClFlags &Flags);
+  static void staticInit(GlobalContext *Ctx);
   static std::unique_ptr<::Ice::TargetLowering> create(Cfg *Func) {
     return makeUnique<TargetMIPS32>(Func);
   }
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index 209db7c..f5f0d1c 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -32,8 +32,8 @@
   return ::Ice::X8632::TargetHeaderX8632::create(Ctx);
 }
 
-void staticInit(const ::Ice::ClFlags &Flags) {
-  ::Ice::X8632::TargetX8632::staticInit(Flags);
+void staticInit(::Ice::GlobalContext *Ctx) {
+  ::Ice::X8632::TargetX8632::staticInit(Ctx);
 }
 } // end of namespace X8632
 
diff --git a/src/IceTargetLoweringX8664.cpp b/src/IceTargetLoweringX8664.cpp
index e9cd1a3..9f825c9 100644
--- a/src/IceTargetLoweringX8664.cpp
+++ b/src/IceTargetLoweringX8664.cpp
@@ -32,8 +32,8 @@
   return ::Ice::X8664::TargetHeaderX8664::create(Ctx);
 }
 
-void staticInit(const ::Ice::ClFlags &Flags) {
-  ::Ice::X8664::TargetX8664::staticInit(Flags);
+void staticInit(::Ice::GlobalContext *Ctx) {
+  ::Ice::X8664::TargetX8664::staticInit(Ctx);
 }
 } // end of namespace X8664
 
diff --git a/src/IceTargetLoweringX86Base.h b/src/IceTargetLoweringX86Base.h
index 76e1445..853ae4e 100644
--- a/src/IceTargetLoweringX86Base.h
+++ b/src/IceTargetLoweringX86Base.h
@@ -78,7 +78,7 @@
 
   ~TargetX86Base() override = default;
 
-  static void staticInit(const ClFlags &Flags);
+  static void staticInit(GlobalContext *Ctx);
   static TargetX86Base *create(Cfg *Func) { return new TargetX86Base(Func); }
 
   static FixupKind getPcRelFixup() { return PcRelFixup; }
diff --git a/src/IceTargetLoweringX86BaseImpl.h b/src/IceTargetLoweringX86BaseImpl.h
index b5d8049..90df3de 100644
--- a/src/IceTargetLoweringX86BaseImpl.h
+++ b/src/IceTargetLoweringX86BaseImpl.h
@@ -324,11 +324,15 @@
 }
 
 template <typename TraitsType>
-void TargetX86Base<TraitsType>::staticInit(const ClFlags &Flags) {
-  Traits::initRegisterSet(Flags, &TypeToRegisterSet, &RegisterAliases,
+void TargetX86Base<TraitsType>::staticInit(GlobalContext *Ctx) {
+  Traits::initRegisterSet(Ctx->getFlags(), &TypeToRegisterSet, &RegisterAliases,
                           &ScratchRegs);
+  filterTypeToRegisterSet(Ctx, Traits::RegisterSet::Reg_NUM,
+                          TypeToRegisterSet.data(), TypeToRegisterSet.size(),
+                          Traits::getRegName);
   PcRelFixup = Traits::FK_PcRel;
-  AbsFixup = Flags.getUseNonsfi() ? Traits::FK_Gotoff : Traits::FK_Abs;
+  AbsFixup =
+      Ctx->getFlags().getUseNonsfi() ? Traits::FK_Gotoff : Traits::FK_Abs;
 }
 
 template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() {
diff --git a/tests_lit/assembler/arm32/vadd.ll b/tests_lit/assembler/arm32/vadd.ll
index a035103..02f94ee 100644
--- a/tests_lit/assembler/arm32/vadd.ll
+++ b/tests_lit/assembler/arm32/vadd.ll
@@ -1,24 +1,31 @@
 ; Show that we know how to translate vadd.
 
-; NOTE: We use -O2 to get rid of memory stores.
+; NOTE: Restricts S and D registers to ones that will better test S/D
+; register encodings.
 
 ; REQUIRES: allow_dump
 
 ; Compile using standalone assembler.
-; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 \
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -Om1 \
+; RUN:   -reg-use s20,s22,d20,d22 \
 ; RUN:   | FileCheck %s --check-prefix=ASM
 
 ; Show bytes in assembled standalone code.
 ; RUN: %p2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
-; RUN:   --args -O2 | FileCheck %s --check-prefix=DIS
+; RUN:   --args -Om1 \
+; RUN:   -reg-use s20,s22,d20,d22 \
+; RUN:   | FileCheck %s --check-prefix=DIS
 
 ; Compile using integrated assembler.
-; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -O2 \
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -Om1 \
+; RUN:   -reg-use s20,s22,d20,d22 \
 ; RUN:   | FileCheck %s --check-prefix=IASM
 
 ; Show bytes in assembled integrated code.
 ; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
-; RUN:   --args -O2 | FileCheck %s --check-prefix=DIS
+; RUN:   --args -Om1 \
+; RUN:   -reg-use s20,s22,d20,d22 \
+; RUN:   | FileCheck %s --check-prefix=DIS
 
 define internal float @testVaddFloat(float %v1, float %v2) {
 ; ASM-LABEL: testVaddFloat:
@@ -26,38 +33,26 @@
 ; IASM-LABEL: testVaddFloat:
 
 entry:
-; ASM-NEXT: .LtestVaddFloat$entry:
-; IASM-NEXT: .LtestVaddFloat$entry:
-
   %res = fadd float %v1, %v2
 
-; ASM-NEXT:     vadd.f32        s0, s0, s1
-; DIS-NEXT:    0:       ee300a20
-; IASM-NEXT:    .byte 0x20
-; IASM-NEXT:    .byte 0xa
-; IASM-NEXT:    .byte 0x30
-; IASM-NEXT:    .byte 0xee
+; ASM:     vadd.f32        s20, s20, s22
+; DIS:   1c:       ee3aaa0b
+; IASM-NOT:     vadd
 
   ret float %res
 }
 
 define internal double @testVaddDouble(double %v1, double %v2) {
 ; ASM-LABEL: testVaddDouble:
-; DIS-LABEL: 00000010 <testVaddDouble>:
-; IASM-LABEL: testVaddDouble:
+; DIS-LABEL: 00000040 <testVaddDouble>:
+; IASM-LABEL: .LtestVaddDouble$entry:
 
 entry:
-; ASM-NEXT: .LtestVaddDouble$entry:
-; IASM-NEXT: .LtestVaddDouble$entry:
-
   %res = fadd double %v1, %v2
 
-; ASM-NEXT:     vadd.f64        d0, d0, d1
-; DIS-NEXT:   10:       ee300b01
-; IASM-NEXT:    .byte 0x1
-; IASM-NEXT:    .byte 0xb
-; IASM-NEXT:    .byte 0x30
-; IASM-NEXT:    .byte 0xee
+; ASM:        vadd.f64        d22, d22, d20
+; DIS:      54:       ee766ba4
+; IASM-NOT:   vadd
 
   ret double %res
 }
diff --git a/tests_lit/llvm2ice_tests/unknown-arm-reg.ll b/tests_lit/llvm2ice_tests/unknown-arm-reg.ll
new file mode 100644
index 0000000..9878b34
--- /dev/null
+++ b/tests_lit/llvm2ice_tests/unknown-arm-reg.ll
@@ -0,0 +1,13 @@
+; Show that we complain if an unknown register is specified on the command line.
+
+; Compile using standalone assembler.
+; RUN: %p2i --expect-fail --filetype=asm -i %s --target=arm32 --args -Om1 \
+; RUN:   -reg-use r2,xx9x,r5,yy28 -reg-exclude s1,sq5 2>&1 \
+; RUN:   | FileCheck %s
+
+define void @foo() {
+  ret void
+}
+
+; CHECK: LLVM ERROR: Unrecognized use/exclude registers: xx9x yy28 sq5
+