Subzero: Make -reg-use and -reg-exclude specific to register class.

The main feature here is that when listing a register via the -reg-use or -reg-exclude option, we can limit the effect to a single register class, instead of applying it across all register classes.  Example:

  pnacl-sz -reg-use i32:eax,i32:ecx,i32:edx -reg-exclude f32:xmm0

Note that without the register class prefix, behavior is the same as before, specifically that the restriction applies to all register classes.

This requires a few high-level changes:

1. We need a mechanism to name *all* register classes, not just the standard ones that map to IceType values.

2. While we're at it, give standard types a more usable name, e.g. "v4i32" instead of "<4 x i32>".

3. Since we've commandeered ":" as the class/register token separator, we change ARM i64 register pair names from e.g. "r0:r1" to "r0r1".

The motivation is that for register allocator torture testing, we'd like to drastically restrict the registers available to e.g. the extensively-used i32 register class, while not overly restricting the seldom-used i32to8 register class (which reflects the set of i32 registers that may trivially truncate to i8).

BUG= none
R=kschimpf@google.com

Review URL: https://codereview.chromium.org/1614273002 .
diff --git a/src/IceOperand.h b/src/IceOperand.h
index 137d456..a32ec2b 100644
--- a/src/IceOperand.h
+++ b/src/IceOperand.h
@@ -424,23 +424,6 @@
 
 Ostream &operator<<(Ostream &Str, const LiveRange &L);
 
-/// RegClass indicates the physical register class that a Variable may be
-/// register-allocated from.  By default, a variable's register class is
-/// directly associated with its type.  However, the target lowering may define
-/// additional target-specific register classes by extending the set of enum
-/// values.
-enum RegClass : uint8_t {
-// Define RC_void, RC_i1, RC_i8, etc.
-#define X(tag, sizeLog2, align, elts, elty, str) RC_##tag = IceType_##tag,
-  ICETYPE_TABLE
-#undef X
-      RC_Target,
-  // Leave plenty of space for target-specific values.
-  RC_Max = std::numeric_limits<uint8_t>::max()
-};
-static_assert(RC_Target == static_cast<RegClass>(IceType_NUM),
-              "Expected RC_Target and IceType_NUM to be the same");
-
 /// Variable represents an operand that is register-allocated or
 /// stack-allocated. If it is register-allocated, it will ultimately have a
 /// non-negative RegNum field.
diff --git a/src/IceRegAlloc.cpp b/src/IceRegAlloc.cpp
index 38ccaa0..395c5aa 100644
--- a/src/IceRegAlloc.cpp
+++ b/src/IceRegAlloc.cpp
@@ -685,11 +685,14 @@
     // any register to it, and move it to the Handled state.
     Handled.push_back(Iter.Cur);
     if (Iter.Cur->mustHaveReg()) {
-      if (Kind == RAK_Phi)
+      if (Kind == RAK_Phi) {
         addSpillFill(Iter);
-      else
+      } else {
+        dumpLiveRangeTrace("Failing      ", Iter.Cur);
         Func->setError("Unable to find a physical register for an "
-                       "infinite-weight live range");
+                       "infinite-weight live range: " +
+                       Iter.Cur->getName(Func));
+      }
     }
   } else {
     // Evict all live ranges in Active that register number MinWeightIndex is
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index 1f459a4..8dd918e 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -138,39 +138,68 @@
     Str << "\n";
 }
 
+// Splits "<class>:<reg>" into "<class>" plus "<reg>".  If there is no <class>
+// component, the result is "" plus "<reg>".
+void splitToClassAndName(const IceString &RegName, IceString *SplitRegClass,
+                         IceString *SplitRegName) {
+  constexpr const char Separator[] = ":";
+  constexpr size_t SeparatorWidth = llvm::array_lengthof(Separator) - 1;
+  size_t Pos = RegName.find(Separator);
+  if (Pos == std::string::npos) {
+    *SplitRegClass = "";
+    *SplitRegName = RegName;
+  } else {
+    *SplitRegClass = RegName.substr(0, Pos);
+    *SplitRegName = RegName.substr(Pos + SeparatorWidth);
+  }
+}
+
 } // 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::function<IceString(int32_t)> getRegName,
+    std::function<IceString(RegClass)> getRegClassName) {
   std::vector<llvm::SmallBitVector> UseSet(TypeToRegisterSetSize,
-                                           ExcludeBitSet);
-  ExcludeBitSet.flip();
+                                           llvm::SmallBitVector(NumRegs));
+  std::vector<llvm::SmallBitVector> ExcludeSet(TypeToRegisterSetSize,
+                                               llvm::SmallBitVector(NumRegs));
 
   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;
+  // The processRegList function iterates across the RegNames vector.  Each
+  // entry in the vector is a string of the form "<reg>" or "<class>:<reg>".
+  // The register class and register number are computed, and the corresponding
+  // bit is set in RegSet[][].  If "<class>:" is missing, then the bit is set
+  // for all classes.
+  auto processRegList = [&](const ClFlags::StringVector &RegNames,
+                            std::vector<llvm::SmallBitVector> &RegSet) {
+    for (const IceString &RegClassAndName : RegNames) {
+      IceString RClass;
+      IceString RName;
+      splitToClassAndName(RegClassAndName, &RClass, &RName);
+      if (!RegNameToIndex.count(RName)) {
+        BadRegNames.push_back(RName);
+        continue;
+      }
+      const int32_t RegIndex = RegNameToIndex.at(RName);
+      for (SizeT TypeIndex = 0; TypeIndex < TypeToRegisterSetSize;
+           ++TypeIndex) {
+        if (RClass.empty() ||
+            RClass == getRegClassName(static_cast<RegClass>(TypeIndex))) {
+          RegSet[TypeIndex][RegIndex] = TypeToRegisterSet[TypeIndex][RegIndex];
+        }
+      }
     }
-    ExcludeBitSet[RegNameToIndex[RegName]] = false;
-  }
+  };
+
+  processRegList(Ctx->getFlags().getUseRestrictedRegisters(), UseSet);
+  processRegList(Ctx->getFlags().getExcludedRegisters(), ExcludeSet);
 
   if (!BadRegNames.empty()) {
     std::string Buffer;
@@ -185,9 +214,10 @@
   for (size_t TypeIndex = 0; TypeIndex < TypeToRegisterSetSize; ++TypeIndex) {
     llvm::SmallBitVector *TypeBitSet = &TypeToRegisterSet[TypeIndex];
     llvm::SmallBitVector *UseBitSet = &UseSet[TypeIndex];
+    llvm::SmallBitVector *ExcludeBitSet = &ExcludeSet[TypeIndex];
     if (UseBitSet->any())
       *TypeBitSet = *UseBitSet;
-    *TypeBitSet &= ExcludeBitSet;
+    (*TypeBitSet).reset(*ExcludeBitSet);
   }
 
   // Display filtered register sets, if requested.
@@ -198,13 +228,8 @@
     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";
+      Str << Indent << getRegClassName(static_cast<RegClass>(TypeIndex))
+          << ":\n";
       printRegisterSet(Str, TypeToRegisterSet[TypeIndex], getRegName,
                        IndentTwice);
     }
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index 202b85a..f8355b9 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -355,7 +355,8 @@
   filterTypeToRegisterSet(GlobalContext *Ctx, int32_t NumRegs,
                           llvm::SmallBitVector TypeToRegisterSet[],
                           size_t TypeToRegisterSetSize,
-                          std::function<IceString(int32_t)> getRegName);
+                          std::function<IceString(int32_t)> getRegName,
+                          std::function<IceString(RegClass)> getRegClassName);
   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 68e8c68..2d998ed 100644
--- a/src/IceTargetLoweringARM32.cpp
+++ b/src/IceTargetLoweringARM32.cpp
@@ -271,6 +271,18 @@
 #undef X
     ;
 std::array<uint32_t, NumVec128Args> Vec128ArgInitializer;
+
+IceString getRegClassName(RegClass C) {
+  auto ClassNum = static_cast<RegARM32::RegClassARM32>(C);
+  assert(ClassNum < RegARM32::RCARM32_NUM);
+  switch (ClassNum) {
+  default:
+    assert(C < RC_Target);
+    return regClassString(C);
+    // Add handling of new register classes below.
+  }
+}
+
 } // end of anonymous namespace
 
 TargetARM32::TargetARM32(Cfg *Func)
@@ -331,18 +343,19 @@
   TypeToRegisterSet[IceType_v4f32] = VectorRegisters;
 
   filterTypeToRegisterSet(
-      Ctx, RegARM32::Reg_NUM, TypeToRegisterSet, RegARM32::RCARM32_NUM,
-      [](int32_t RegNum) -> IceString {
+      Ctx, RegARM32::Reg_NUM, TypeToRegisterSet,
+      llvm::array_lengthof(TypeToRegisterSet), [](int32_t RegNum) -> IceString {
+        // This function simply removes ", " from the register name.
         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, ":");
+          Name.replace(Pos, RegSeparatorWidth, "");
         }
         return Name;
-      });
+      }, getRegClassName);
 }
 
 namespace {
@@ -6455,7 +6468,7 @@
   Str << ".eabi_attribute 14, 3   @ Tag_ABI_PCS_R9_use: Not used\n";
 }
 
-llvm::SmallBitVector TargetARM32::TypeToRegisterSet[IceType_NUM];
+llvm::SmallBitVector TargetARM32::TypeToRegisterSet[RegARM32::RCARM32_NUM];
 llvm::SmallBitVector TargetARM32::RegisterAliases[RegARM32::Reg_NUM];
 
 } // end of namespace ARM32
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
index 248c073..3cbf03e 100644
--- a/src/IceTargetLoweringMIPS32.cpp
+++ b/src/IceTargetLoweringMIPS32.cpp
@@ -60,6 +60,17 @@
 // The maximum number of arguments to pass in GPR registers.
 constexpr uint32_t MIPS32_MAX_GPR_ARG = 4;
 
+IceString getRegClassName(RegClass C) {
+  auto ClassNum = static_cast<RegClassMIPS32>(C);
+  assert(ClassNum < RCMIPS32_NUM);
+  switch (ClassNum) {
+  default:
+    assert(C < RC_Target);
+    return regClassString(C);
+    // Add handling of new register classes below.
+  }
+}
+
 } // end of anonymous namespace
 
 TargetMIPS32::TargetMIPS32(Cfg *Func) : TargetLowering(Func) {}
@@ -106,9 +117,8 @@
   TypeToRegisterSet[IceType_v4f32] = VectorRegisters;
 
   filterTypeToRegisterSet(Ctx, RegMIPS32::Reg_NUM, TypeToRegisterSet,
-                          RCMIPS32_NUM, [](int32_t RegNum) -> IceString {
-                            return RegMIPS32::getRegName(RegNum);
-                          });
+                          llvm::array_lengthof(TypeToRegisterSet),
+                          RegMIPS32::getRegName, getRegClassName);
 }
 
 void TargetMIPS32::translateO2() {
@@ -1115,7 +1125,7 @@
       << "nomips16\n";
 }
 
-llvm::SmallBitVector TargetMIPS32::TypeToRegisterSet[IceType_NUM];
+llvm::SmallBitVector TargetMIPS32::TypeToRegisterSet[RCMIPS32_NUM];
 llvm::SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM];
 
 } // end of namespace MIPS32
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index 0fee3d2..3e45c64 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -432,7 +432,7 @@
       _num
 };
 // Define a set of constants based on high-level table entries.
-#define X(tag, sizeLog2, align, elts, elty, str)                               \
+#define X(tag, sizeLog2, align, elts, elty, str, rcstr)                        \
   static const int _table1_##tag = IceType_##tag;
 ICETYPE_TABLE
 #undef X
@@ -446,7 +446,7 @@
 #undef X
 // Repeat the static asserts with respect to the high-level table entries in
 // case the high-level table has extra entries.
-#define X(tag, sizeLog2, align, elts, elty, str)                               \
+#define X(tag, sizeLog2, align, elts, elty, str, rcstr)                        \
   static_assert(_table1_##tag == _table2_##tag,                                \
                 "Inconsistency between ICETYPEX8632_TABLE and ICETYPE_TABLE");
 ICETYPE_TABLE
diff --git a/src/IceTargetLoweringX8632Traits.h b/src/IceTargetLoweringX8632Traits.h
index e54ffd2..5531959 100644
--- a/src/IceTargetLoweringX8632Traits.h
+++ b/src/IceTargetLoweringX8632Traits.h
@@ -516,7 +516,7 @@
     (*TypeToRegisterSet)[RC_i8] = IntegerRegistersI8;
     (*TypeToRegisterSet)[RC_i16] = IntegerRegistersI16;
     (*TypeToRegisterSet)[RC_i32] = IntegerRegistersI32;
-    (*TypeToRegisterSet)[RC_i64] = IntegerRegistersI32;
+    (*TypeToRegisterSet)[RC_i64] = InvalidRegisters;
     (*TypeToRegisterSet)[RC_f32] = FloatRegisters;
     (*TypeToRegisterSet)[RC_f64] = FloatRegisters;
     (*TypeToRegisterSet)[RC_v4i1] = VectorRegisters;
diff --git a/src/IceTargetLoweringX8664.cpp b/src/IceTargetLoweringX8664.cpp
index e46569b..5884321 100644
--- a/src/IceTargetLoweringX8664.cpp
+++ b/src/IceTargetLoweringX8664.cpp
@@ -699,7 +699,7 @@
       _num
 };
 // Define a set of constants based on high-level table entries.
-#define X(tag, sizeLog2, align, elts, elty, str)                               \
+#define X(tag, sizeLog2, align, elts, elty, str, rcstr)                        \
   static const int _table1_##tag = IceType_##tag;
 ICETYPE_TABLE
 #undef X
@@ -713,7 +713,7 @@
 #undef X
 // Repeat the static asserts with respect to the high-level table entries in
 // case the high-level table has extra entries.
-#define X(tag, sizeLog2, align, elts, elty, str)                               \
+#define X(tag, sizeLog2, align, elts, elty, str, rcstr)                        \
   static_assert(_table1_##tag == _table2_##tag,                                \
                 "Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE");
 ICETYPE_TABLE
diff --git a/src/IceTargetLoweringX86Base.h b/src/IceTargetLoweringX86Base.h
index 46bad77..631d06b 100644
--- a/src/IceTargetLoweringX86Base.h
+++ b/src/IceTargetLoweringX86Base.h
@@ -96,6 +96,25 @@
   }
   Variable *getPhysicalRegister(SizeT RegNum, Type Ty = IceType_void) override;
   IceString getRegName(SizeT RegNum, Type Ty) const override;
+  static IceString getRegClassName(RegClass C) {
+    auto ClassNum = static_cast<RegClassX86>(C);
+    assert(ClassNum < RCX86_NUM);
+    switch (ClassNum) {
+    default:
+      assert(C < RC_Target);
+      return regClassString(C);
+    case RCX86_Is64To8:
+      return "i64to8"; // 64-bit GPR truncable to i8
+    case RCX86_Is32To8:
+      return "i32to8"; // 32-bit GPR truncable to i8
+    case RCX86_Is16To8:
+      return "i16to8"; // 16-bit GPR truncable to i8
+    case RCX86_IsTrunc8Rcvr:
+      return "i8from"; // 8-bit GPR truncable from wider GPRs
+    case RCX86_IsAhRcvr:
+      return "i8fromah"; // 8-bit GPR that ah can be assigned to
+    }
+  }
   llvm::SmallBitVector getRegisterSet(RegSetMask Include,
                                       RegSetMask Exclude) const override;
   const llvm::SmallBitVector &
diff --git a/src/IceTargetLoweringX86BaseImpl.h b/src/IceTargetLoweringX86BaseImpl.h
index 5e87af9..01e2be0 100644
--- a/src/IceTargetLoweringX86BaseImpl.h
+++ b/src/IceTargetLoweringX86BaseImpl.h
@@ -381,7 +381,7 @@
                           &RegisterAliases);
   filterTypeToRegisterSet(Ctx, Traits::RegisterSet::Reg_NUM,
                           TypeToRegisterSet.data(), TypeToRegisterSet.size(),
-                          Traits::getRegName);
+                          Traits::getRegName, getRegClassName);
   PcRelFixup = Traits::FK_PcRel;
   AbsFixup =
       Ctx->getFlags().getUseNonsfi() ? Traits::FK_Gotoff : Traits::FK_Abs;
diff --git a/src/IceTypes.cpp b/src/IceTypes.cpp
index 2614d74..39eff2d 100644
--- a/src/IceTypes.cpp
+++ b/src/IceTypes.cpp
@@ -30,7 +30,7 @@
 
 // Define a temporary set of enum values based on ICETYPE_TABLE
 enum {
-#define X(tag, sizeLog2, align, elts, elty, str) _table_tag_##tag,
+#define X(tag, sizeLog2, align, elts, elty, str, rcstr) _table_tag_##tag,
   ICETYPE_TABLE
 #undef X
       _enum_table_tag_Names
@@ -45,7 +45,7 @@
       _enum_props_table_tag_Names
 };
 // Assert that tags in ICETYPE_TABLE are also in ICETYPE_PROPS_TABLE.
-#define X(tag, sizeLog2, align, elts, elty, str)                               \
+#define X(tag, sizeLog2, align, elts, elty, str, rcstr)                        \
   static_assert(                                                               \
       (unsigned)_table_tag_##tag == (unsigned)_props_table_tag_##tag,          \
       "Inconsistency between ICETYPE_PROPS_TABLE and ICETYPE_TABLE");
@@ -64,7 +64,8 @@
 
 // Define constants for each element size in ICETYPE_TABLE.
 enum {
-#define X(tag, sizeLog2, align, elts, elty, str) _table_elts_##tag = elts,
+#define X(tag, sizeLog2, align, elts, elty, str, rcstr)                        \
+  _table_elts_##tag = elts,
   ICETYPE_TABLE
 #undef X
       _enum_table_elts_Elements = 0
@@ -91,11 +92,12 @@
   size_t TypeNumElements;
   Type TypeElementType;
   const char *DisplayString;
+  const char *RegClassString;
 };
 
 const struct TypeAttributeFields TypeAttributes[] = {
-#define X(tag, sizeLog2, align, elts, elty, str)                               \
-  { sizeLog2, align, elts, IceType_##elty, str }                               \
+#define X(tag, sizeLog2, align, elts, elty, str, rcstr)                        \
+  { sizeLog2, align, elts, IceType_##elty, str, rcstr }                        \
   ,
     ICETYPE_TABLE
 #undef X
@@ -280,6 +282,13 @@
   return "???";
 }
 
+const char *regClassString(RegClass C) {
+  if (static_cast<size_t>(C) < IceType_NUM)
+    return TypeAttributes[C].RegClassString;
+  llvm_unreachable("Invalid type for regClassString");
+  return "???";
+}
+
 void FuncSigType::dump(Ostream &Stream) const {
   if (!BuildDefs::dump())
     return;
diff --git a/src/IceTypes.def b/src/IceTypes.def
index 0d4ec86..a1a2552 100644
--- a/src/IceTypes.def
+++ b/src/IceTypes.def
@@ -26,7 +26,7 @@
 #define TARGETARCH_TABLE                                                       \
   /* enum value, printable string, is_elf64,   e_machine, e_flags */           \
   X(Target_X8632, "x86-32", false, EM_386,     0)                              \
-  X(Target_X8664, "x86-64", true,  EM_X86_64,  0)                               \
+  X(Target_X8664, "x86-64", true,  EM_X86_64,  0)                              \
   X(Target_ARM32, "arm32",  false, EM_ARM,     EF_ARM_EABI_VER5)               \
   X(Target_ARM64, "arm64",  true,  EM_AARCH64, 0)                              \
   X(Target_MIPS32,"mips32", false, EM_MIPS,    0)                              \
@@ -34,23 +34,24 @@
 
 #define ICETYPE_TABLE                                                          \
   /* enum value, log_2(size), align, # elts, element type, */                  \
-  /*     printable string (size and alignment in bytes) */                     \
-  X(void,  -1,  0,  1, void, "void")                                           \
-  X(i1,     0,  1,  1, i1,   "i1")                                             \
-  X(i8,     0,  1,  1, i8,   "i8")                                             \
-  X(i16,    1,  1,  1, i16,  "i16")                                            \
-  X(i32,    2,  1,  1, i32,  "i32")                                            \
-  X(i64,    3,  1,  1, i64,  "i64")                                            \
-  X(f32,    2,  4,  1, f32,  "float")                                          \
-  X(f64,    3,  8,  1, f64,  "double")                                         \
-  X(v4i1,   4,  1,  4, i1,   "<4 x i1>")                                       \
-  X(v8i1,   4,  1,  8, i1,   "<8 x i1>")                                       \
-  X(v16i1,  4,  1, 16, i1,   "<16 x i1>")                                      \
-  X(v16i8,  4,  1, 16, i8,   "<16 x i8>")                                      \
-  X(v8i16,  4,  2,  8, i16,  "<8 x i16>")                                      \
-  X(v4i32,  4,  4,  4, i32,  "<4 x i32>")                                      \
-  X(v4f32,  4,  4,  4, f32,  "<4 x float>")                                    \
-//#define X(tag, sizeLog2, align, elts, elty, str)
+  /*     printable string (size and alignment in bytes), */                    \
+  /*     register class string */                                              \
+  X(void,  -1,  0,  1, void, "void",        "void")                            \
+  X(i1,     0,  1,  1, i1,   "i1",          "i1")                              \
+  X(i8,     0,  1,  1, i8,   "i8",          "i8")                              \
+  X(i16,    1,  1,  1, i16,  "i16",         "i16")                             \
+  X(i32,    2,  1,  1, i32,  "i32",         "i32")                             \
+  X(i64,    3,  1,  1, i64,  "i64",         "i64")                             \
+  X(f32,    2,  4,  1, f32,  "float",       "f32")                             \
+  X(f64,    3,  8,  1, f64,  "double",      "f64")                             \
+  X(v4i1,   4,  1,  4, i1,   "<4 x i1>",    "v4i1")                            \
+  X(v8i1,   4,  1,  8, i1,   "<8 x i1>",    "v8ii")                            \
+  X(v16i1,  4,  1, 16, i1,   "<16 x i1>",   "v16i1")                           \
+  X(v16i8,  4,  1, 16, i8,   "<16 x i8>",   "v16i8")                           \
+  X(v8i16,  4,  2,  8, i16,  "<8 x i16>",   "v8i16")                           \
+  X(v4i32,  4,  4,  4, i32,  "<4 x i32>",   "v4i32")                           \
+  X(v4f32,  4,  4,  4, f32,  "<4 x float>", "v4f32")                           \
+//#define X(tag, sizeLog2, align, elts, elty, str, rcstr)
 
 // Dictionary:
 //   V - Is vector type.
diff --git a/src/IceTypes.h b/src/IceTypes.h
index a87cf8b..1ef3df7 100644
--- a/src/IceTypes.h
+++ b/src/IceTypes.h
@@ -22,12 +22,30 @@
 namespace Ice {
 
 enum Type {
-#define X(tag, sizeLog2, align, elts, elty, str) IceType_##tag,
+#define X(tag, sizeLog2, align, elts, elty, str, rcstr) IceType_##tag,
   ICETYPE_TABLE
 #undef X
       IceType_NUM
 };
 
+/// RegClass indicates the physical register class that a Variable may be
+/// register-allocated from.  By default, a variable's register class is
+/// directly associated with its type.  However, the target lowering may define
+/// additional target-specific register classes by extending the set of enum
+/// values.
+enum RegClass : uint8_t {
+// Define RC_void, RC_i1, RC_i8, etc.
+#define X(tag, sizeLog2, align, elts, elty, str, rcstr)                        \
+  RC_##tag = IceType_##tag,
+  ICETYPE_TABLE
+#undef X
+      RC_Target,
+  // Leave plenty of space for target-specific values.
+  RC_Max = std::numeric_limits<uint8_t>::max()
+};
+static_assert(RC_Target == static_cast<RegClass>(IceType_NUM),
+              "Expected RC_Target and IceType_NUM to be the same");
+
 enum TargetArch {
 #define X(tag, str, is_elf64, e_machine, e_flags) tag,
   TARGETARCH_TABLE
@@ -64,6 +82,7 @@
 size_t typeNumElements(Type Ty);
 Type typeElementType(Type Ty);
 const char *typeString(Type Ty);
+const char *regClassString(RegClass C);
 
 inline Type getPointerType() { return IceType_i32; }