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; }