Commit 2544d4d2 by Jim Stichnoth

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 .
parent e078db8e
...@@ -424,23 +424,6 @@ private: ...@@ -424,23 +424,6 @@ private:
Ostream &operator<<(Ostream &Str, const LiveRange &L); 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 /// Variable represents an operand that is register-allocated or
/// stack-allocated. If it is register-allocated, it will ultimately have a /// stack-allocated. If it is register-allocated, it will ultimately have a
/// non-negative RegNum field. /// non-negative RegNum field.
......
...@@ -685,11 +685,14 @@ void LinearScan::handleNoFreeRegisters(IterationState &Iter) { ...@@ -685,11 +685,14 @@ void LinearScan::handleNoFreeRegisters(IterationState &Iter) {
// any register to it, and move it to the Handled state. // any register to it, and move it to the Handled state.
Handled.push_back(Iter.Cur); Handled.push_back(Iter.Cur);
if (Iter.Cur->mustHaveReg()) { if (Iter.Cur->mustHaveReg()) {
if (Kind == RAK_Phi) if (Kind == RAK_Phi) {
addSpillFill(Iter); addSpillFill(Iter);
else } else {
dumpLiveRangeTrace("Failing ", Iter.Cur);
Func->setError("Unable to find a physical register for an " Func->setError("Unable to find a physical register for an "
"infinite-weight live range"); "infinite-weight live range: " +
Iter.Cur->getName(Func));
}
} }
} else { } else {
// Evict all live ranges in Active that register number MinWeightIndex is // Evict all live ranges in Active that register number MinWeightIndex is
......
...@@ -138,39 +138,68 @@ void printRegisterSet(Ostream &Str, const llvm::SmallBitVector &Bitset, ...@@ -138,39 +138,68 @@ void printRegisterSet(Ostream &Str, const llvm::SmallBitVector &Bitset,
Str << "\n"; 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 } // end of anonymous namespace
void TargetLowering::filterTypeToRegisterSet( void TargetLowering::filterTypeToRegisterSet(
GlobalContext *Ctx, int32_t NumRegs, GlobalContext *Ctx, int32_t NumRegs,
llvm::SmallBitVector TypeToRegisterSet[], size_t TypeToRegisterSetSize, llvm::SmallBitVector TypeToRegisterSet[], size_t TypeToRegisterSetSize,
std::function<IceString(int32_t)> getRegName) { std::function<IceString(int32_t)> getRegName,
llvm::SmallBitVector ExcludeBitSet(NumRegs); std::function<IceString(RegClass)> getRegClassName) {
std::vector<llvm::SmallBitVector> UseSet(TypeToRegisterSetSize, std::vector<llvm::SmallBitVector> UseSet(TypeToRegisterSetSize,
ExcludeBitSet); llvm::SmallBitVector(NumRegs));
ExcludeBitSet.flip(); std::vector<llvm::SmallBitVector> ExcludeSet(TypeToRegisterSetSize,
llvm::SmallBitVector(NumRegs));
std::unordered_map<IceString, int32_t> RegNameToIndex; std::unordered_map<IceString, int32_t> RegNameToIndex;
for (int32_t RegIndex = 0; RegIndex < NumRegs; ++RegIndex) for (int32_t RegIndex = 0; RegIndex < NumRegs; ++RegIndex)
RegNameToIndex[getRegName(RegIndex)] = RegIndex; RegNameToIndex[getRegName(RegIndex)] = RegIndex;
ClFlags::StringVector BadRegNames; ClFlags::StringVector BadRegNames;
for (const IceString &RegName : Ctx->getFlags().getUseRestrictedRegisters()) {
if (!RegNameToIndex.count(RegName)) { // The processRegList function iterates across the RegNames vector. Each
BadRegNames.push_back(RegName); // 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; continue;
} }
const int32_t RegIndex = RegNameToIndex[RegName]; const int32_t RegIndex = RegNameToIndex.at(RName);
for (SizeT TypeIndex = 0; TypeIndex < TypeToRegisterSetSize; ++TypeIndex) for (SizeT TypeIndex = 0; TypeIndex < TypeToRegisterSetSize;
UseSet[TypeIndex][RegIndex] = TypeToRegisterSet[TypeIndex][RegIndex]; ++TypeIndex) {
if (RClass.empty() ||
RClass == getRegClassName(static_cast<RegClass>(TypeIndex))) {
RegSet[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;
} }
};
processRegList(Ctx->getFlags().getUseRestrictedRegisters(), UseSet);
processRegList(Ctx->getFlags().getExcludedRegisters(), ExcludeSet);
if (!BadRegNames.empty()) { if (!BadRegNames.empty()) {
std::string Buffer; std::string Buffer;
...@@ -185,9 +214,10 @@ void TargetLowering::filterTypeToRegisterSet( ...@@ -185,9 +214,10 @@ void TargetLowering::filterTypeToRegisterSet(
for (size_t TypeIndex = 0; TypeIndex < TypeToRegisterSetSize; ++TypeIndex) { for (size_t TypeIndex = 0; TypeIndex < TypeToRegisterSetSize; ++TypeIndex) {
llvm::SmallBitVector *TypeBitSet = &TypeToRegisterSet[TypeIndex]; llvm::SmallBitVector *TypeBitSet = &TypeToRegisterSet[TypeIndex];
llvm::SmallBitVector *UseBitSet = &UseSet[TypeIndex]; llvm::SmallBitVector *UseBitSet = &UseSet[TypeIndex];
llvm::SmallBitVector *ExcludeBitSet = &ExcludeSet[TypeIndex];
if (UseBitSet->any()) if (UseBitSet->any())
*TypeBitSet = *UseBitSet; *TypeBitSet = *UseBitSet;
*TypeBitSet &= ExcludeBitSet; (*TypeBitSet).reset(*ExcludeBitSet);
} }
// Display filtered register sets, if requested. // Display filtered register sets, if requested.
...@@ -198,13 +228,8 @@ void TargetLowering::filterTypeToRegisterSet( ...@@ -198,13 +228,8 @@ void TargetLowering::filterTypeToRegisterSet(
const IceString IndentTwice = Indent + Indent; const IceString IndentTwice = Indent + Indent;
Str << "Registers available for register allocation:\n"; Str << "Registers available for register allocation:\n";
for (size_t TypeIndex = 0; TypeIndex < TypeToRegisterSetSize; ++TypeIndex) { for (size_t TypeIndex = 0; TypeIndex < TypeToRegisterSetSize; ++TypeIndex) {
Str << Indent; Str << Indent << getRegClassName(static_cast<RegClass>(TypeIndex))
if (TypeIndex < IceType_NUM) { << ":\n";
Str << typeString(static_cast<Type>(TypeIndex));
} else {
Str << "other[" << TypeIndex << "]";
}
Str << ":\n";
printRegisterSet(Str, TypeToRegisterSet[TypeIndex], getRegName, printRegisterSet(Str, TypeToRegisterSet[TypeIndex], getRegName,
IndentTwice); IndentTwice);
} }
......
...@@ -355,7 +355,8 @@ protected: ...@@ -355,7 +355,8 @@ protected:
filterTypeToRegisterSet(GlobalContext *Ctx, int32_t NumRegs, filterTypeToRegisterSet(GlobalContext *Ctx, int32_t NumRegs,
llvm::SmallBitVector TypeToRegisterSet[], llvm::SmallBitVector TypeToRegisterSet[],
size_t TypeToRegisterSetSize, 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 lowerAlloca(const InstAlloca *Inst) = 0;
virtual void lowerArithmetic(const InstArithmetic *Inst) = 0; virtual void lowerArithmetic(const InstArithmetic *Inst) = 0;
virtual void lowerAssign(const InstAssign *Inst) = 0; virtual void lowerAssign(const InstAssign *Inst) = 0;
......
...@@ -271,6 +271,18 @@ constexpr SizeT NumVec128Args = ...@@ -271,6 +271,18 @@ constexpr SizeT NumVec128Args =
#undef X #undef X
; ;
std::array<uint32_t, NumVec128Args> Vec128ArgInitializer; 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 } // end of anonymous namespace
TargetARM32::TargetARM32(Cfg *Func) TargetARM32::TargetARM32(Cfg *Func)
...@@ -331,18 +343,19 @@ void TargetARM32::staticInit(GlobalContext *Ctx) { ...@@ -331,18 +343,19 @@ void TargetARM32::staticInit(GlobalContext *Ctx) {
TypeToRegisterSet[IceType_v4f32] = VectorRegisters; TypeToRegisterSet[IceType_v4f32] = VectorRegisters;
filterTypeToRegisterSet( filterTypeToRegisterSet(
Ctx, RegARM32::Reg_NUM, TypeToRegisterSet, RegARM32::RCARM32_NUM, Ctx, RegARM32::Reg_NUM, TypeToRegisterSet,
[](int32_t RegNum) -> IceString { llvm::array_lengthof(TypeToRegisterSet), [](int32_t RegNum) -> IceString {
// This function simply removes ", " from the register name.
IceString Name = RegARM32::getRegName(RegNum); IceString Name = RegARM32::getRegName(RegNum);
constexpr const char RegSeparator[] = ", "; constexpr const char RegSeparator[] = ", ";
constexpr size_t RegSeparatorWidth = constexpr size_t RegSeparatorWidth =
llvm::array_lengthof(RegSeparator) - 1; llvm::array_lengthof(RegSeparator) - 1;
for (size_t Pos = Name.find(RegSeparator); Pos != std::string::npos; for (size_t Pos = Name.find(RegSeparator); Pos != std::string::npos;
Pos = Name.find(RegSeparator)) { Pos = Name.find(RegSeparator)) {
Name.replace(Pos, RegSeparatorWidth, ":"); Name.replace(Pos, RegSeparatorWidth, "");
} }
return Name; return Name;
}); }, getRegClassName);
} }
namespace { namespace {
...@@ -6455,7 +6468,7 @@ void TargetHeaderARM32::lower() { ...@@ -6455,7 +6468,7 @@ void TargetHeaderARM32::lower() {
Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; 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]; llvm::SmallBitVector TargetARM32::RegisterAliases[RegARM32::Reg_NUM];
} // end of namespace ARM32 } // end of namespace ARM32
......
...@@ -60,6 +60,17 @@ namespace { ...@@ -60,6 +60,17 @@ namespace {
// The maximum number of arguments to pass in GPR registers. // The maximum number of arguments to pass in GPR registers.
constexpr uint32_t MIPS32_MAX_GPR_ARG = 4; 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 } // end of anonymous namespace
TargetMIPS32::TargetMIPS32(Cfg *Func) : TargetLowering(Func) {} TargetMIPS32::TargetMIPS32(Cfg *Func) : TargetLowering(Func) {}
...@@ -106,9 +117,8 @@ void TargetMIPS32::staticInit(GlobalContext *Ctx) { ...@@ -106,9 +117,8 @@ void TargetMIPS32::staticInit(GlobalContext *Ctx) {
TypeToRegisterSet[IceType_v4f32] = VectorRegisters; TypeToRegisterSet[IceType_v4f32] = VectorRegisters;
filterTypeToRegisterSet(Ctx, RegMIPS32::Reg_NUM, TypeToRegisterSet, filterTypeToRegisterSet(Ctx, RegMIPS32::Reg_NUM, TypeToRegisterSet,
RCMIPS32_NUM, [](int32_t RegNum) -> IceString { llvm::array_lengthof(TypeToRegisterSet),
return RegMIPS32::getRegName(RegNum); RegMIPS32::getRegName, getRegClassName);
});
} }
void TargetMIPS32::translateO2() { void TargetMIPS32::translateO2() {
...@@ -1115,7 +1125,7 @@ void TargetHeaderMIPS32::lower() { ...@@ -1115,7 +1125,7 @@ void TargetHeaderMIPS32::lower() {
<< "nomips16\n"; << "nomips16\n";
} }
llvm::SmallBitVector TargetMIPS32::TypeToRegisterSet[IceType_NUM]; llvm::SmallBitVector TargetMIPS32::TypeToRegisterSet[RCMIPS32_NUM];
llvm::SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM]; llvm::SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM];
} // end of namespace MIPS32 } // end of namespace MIPS32
......
...@@ -432,7 +432,7 @@ enum _tmp_enum { ...@@ -432,7 +432,7 @@ enum _tmp_enum {
_num _num
}; };
// Define a set of constants based on high-level table entries. // 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; static const int _table1_##tag = IceType_##tag;
ICETYPE_TABLE ICETYPE_TABLE
#undef X #undef X
...@@ -446,7 +446,7 @@ ICETYPEX8632_TABLE ...@@ -446,7 +446,7 @@ ICETYPEX8632_TABLE
#undef X #undef X
// Repeat the static asserts with respect to the high-level table entries in // Repeat the static asserts with respect to the high-level table entries in
// case the high-level table has extra entries. // 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, \ static_assert(_table1_##tag == _table2_##tag, \
"Inconsistency between ICETYPEX8632_TABLE and ICETYPE_TABLE"); "Inconsistency between ICETYPEX8632_TABLE and ICETYPE_TABLE");
ICETYPE_TABLE ICETYPE_TABLE
......
...@@ -516,7 +516,7 @@ public: ...@@ -516,7 +516,7 @@ public:
(*TypeToRegisterSet)[RC_i8] = IntegerRegistersI8; (*TypeToRegisterSet)[RC_i8] = IntegerRegistersI8;
(*TypeToRegisterSet)[RC_i16] = IntegerRegistersI16; (*TypeToRegisterSet)[RC_i16] = IntegerRegistersI16;
(*TypeToRegisterSet)[RC_i32] = IntegerRegistersI32; (*TypeToRegisterSet)[RC_i32] = IntegerRegistersI32;
(*TypeToRegisterSet)[RC_i64] = IntegerRegistersI32; (*TypeToRegisterSet)[RC_i64] = InvalidRegisters;
(*TypeToRegisterSet)[RC_f32] = FloatRegisters; (*TypeToRegisterSet)[RC_f32] = FloatRegisters;
(*TypeToRegisterSet)[RC_f64] = FloatRegisters; (*TypeToRegisterSet)[RC_f64] = FloatRegisters;
(*TypeToRegisterSet)[RC_v4i1] = VectorRegisters; (*TypeToRegisterSet)[RC_v4i1] = VectorRegisters;
......
...@@ -699,7 +699,7 @@ enum _tmp_enum { ...@@ -699,7 +699,7 @@ enum _tmp_enum {
_num _num
}; };
// Define a set of constants based on high-level table entries. // 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; static const int _table1_##tag = IceType_##tag;
ICETYPE_TABLE ICETYPE_TABLE
#undef X #undef X
...@@ -713,7 +713,7 @@ ICETYPEX8664_TABLE ...@@ -713,7 +713,7 @@ ICETYPEX8664_TABLE
#undef X #undef X
// Repeat the static asserts with respect to the high-level table entries in // Repeat the static asserts with respect to the high-level table entries in
// case the high-level table has extra entries. // 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, \ static_assert(_table1_##tag == _table2_##tag, \
"Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE"); "Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE");
ICETYPE_TABLE ICETYPE_TABLE
......
...@@ -96,6 +96,25 @@ public: ...@@ -96,6 +96,25 @@ public:
} }
Variable *getPhysicalRegister(SizeT RegNum, Type Ty = IceType_void) override; Variable *getPhysicalRegister(SizeT RegNum, Type Ty = IceType_void) override;
IceString getRegName(SizeT RegNum, Type Ty) const 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, llvm::SmallBitVector getRegisterSet(RegSetMask Include,
RegSetMask Exclude) const override; RegSetMask Exclude) const override;
const llvm::SmallBitVector & const llvm::SmallBitVector &
......
...@@ -381,7 +381,7 @@ void TargetX86Base<TraitsType>::staticInit(GlobalContext *Ctx) { ...@@ -381,7 +381,7 @@ void TargetX86Base<TraitsType>::staticInit(GlobalContext *Ctx) {
&RegisterAliases); &RegisterAliases);
filterTypeToRegisterSet(Ctx, Traits::RegisterSet::Reg_NUM, filterTypeToRegisterSet(Ctx, Traits::RegisterSet::Reg_NUM,
TypeToRegisterSet.data(), TypeToRegisterSet.size(), TypeToRegisterSet.data(), TypeToRegisterSet.size(),
Traits::getRegName); Traits::getRegName, getRegClassName);
PcRelFixup = Traits::FK_PcRel; PcRelFixup = Traits::FK_PcRel;
AbsFixup = AbsFixup =
Ctx->getFlags().getUseNonsfi() ? Traits::FK_Gotoff : Traits::FK_Abs; Ctx->getFlags().getUseNonsfi() ? Traits::FK_Gotoff : Traits::FK_Abs;
......
...@@ -30,7 +30,7 @@ const char *TargetArchName[] = { ...@@ -30,7 +30,7 @@ const char *TargetArchName[] = {
// Define a temporary set of enum values based on ICETYPE_TABLE // Define a temporary set of enum values based on ICETYPE_TABLE
enum { 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 ICETYPE_TABLE
#undef X #undef X
_enum_table_tag_Names _enum_table_tag_Names
...@@ -45,7 +45,7 @@ enum { ...@@ -45,7 +45,7 @@ enum {
_enum_props_table_tag_Names _enum_props_table_tag_Names
}; };
// Assert that tags in ICETYPE_TABLE are also in ICETYPE_PROPS_TABLE. // 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( \ static_assert( \
(unsigned)_table_tag_##tag == (unsigned)_props_table_tag_##tag, \ (unsigned)_table_tag_##tag == (unsigned)_props_table_tag_##tag, \
"Inconsistency between ICETYPE_PROPS_TABLE and ICETYPE_TABLE"); "Inconsistency between ICETYPE_PROPS_TABLE and ICETYPE_TABLE");
...@@ -64,7 +64,8 @@ ICETYPE_PROPS_TABLE ...@@ -64,7 +64,8 @@ ICETYPE_PROPS_TABLE
// Define constants for each element size in ICETYPE_TABLE. // Define constants for each element size in ICETYPE_TABLE.
enum { 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 ICETYPE_TABLE
#undef X #undef X
_enum_table_elts_Elements = 0 _enum_table_elts_Elements = 0
...@@ -91,11 +92,12 @@ struct TypeAttributeFields { ...@@ -91,11 +92,12 @@ struct TypeAttributeFields {
size_t TypeNumElements; size_t TypeNumElements;
Type TypeElementType; Type TypeElementType;
const char *DisplayString; const char *DisplayString;
const char *RegClassString;
}; };
const struct TypeAttributeFields TypeAttributes[] = { const struct TypeAttributeFields TypeAttributes[] = {
#define X(tag, sizeLog2, align, elts, elty, str) \ #define X(tag, sizeLog2, align, elts, elty, str, rcstr) \
{ sizeLog2, align, elts, IceType_##elty, str } \ { sizeLog2, align, elts, IceType_##elty, str, rcstr } \
, ,
ICETYPE_TABLE ICETYPE_TABLE
#undef X #undef X
...@@ -280,6 +282,13 @@ const char *typeString(Type Ty) { ...@@ -280,6 +282,13 @@ const char *typeString(Type Ty) {
return "???"; 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 { void FuncSigType::dump(Ostream &Stream) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
......
...@@ -34,23 +34,24 @@ ...@@ -34,23 +34,24 @@
#define ICETYPE_TABLE \ #define ICETYPE_TABLE \
/* enum value, log_2(size), align, # elts, element type, */ \ /* enum value, log_2(size), align, # elts, element type, */ \
/* printable string (size and alignment in bytes) */ \ /* printable string (size and alignment in bytes), */ \
X(void, -1, 0, 1, void, "void") \ /* register class string */ \
X(i1, 0, 1, 1, i1, "i1") \ X(void, -1, 0, 1, void, "void", "void") \
X(i8, 0, 1, 1, i8, "i8") \ X(i1, 0, 1, 1, i1, "i1", "i1") \
X(i16, 1, 1, 1, i16, "i16") \ X(i8, 0, 1, 1, i8, "i8", "i8") \
X(i32, 2, 1, 1, i32, "i32") \ X(i16, 1, 1, 1, i16, "i16", "i16") \
X(i64, 3, 1, 1, i64, "i64") \ X(i32, 2, 1, 1, i32, "i32", "i32") \
X(f32, 2, 4, 1, f32, "float") \ X(i64, 3, 1, 1, i64, "i64", "i64") \
X(f64, 3, 8, 1, f64, "double") \ X(f32, 2, 4, 1, f32, "float", "f32") \
X(v4i1, 4, 1, 4, i1, "<4 x i1>") \ X(f64, 3, 8, 1, f64, "double", "f64") \
X(v8i1, 4, 1, 8, i1, "<8 x i1>") \ X(v4i1, 4, 1, 4, i1, "<4 x i1>", "v4i1") \
X(v16i1, 4, 1, 16, i1, "<16 x i1>") \ X(v8i1, 4, 1, 8, i1, "<8 x i1>", "v8ii") \
X(v16i8, 4, 1, 16, i8, "<16 x i8>") \ X(v16i1, 4, 1, 16, i1, "<16 x i1>", "v16i1") \
X(v8i16, 4, 2, 8, i16, "<8 x i16>") \ X(v16i8, 4, 1, 16, i8, "<16 x i8>", "v16i8") \
X(v4i32, 4, 4, 4, i32, "<4 x i32>") \ X(v8i16, 4, 2, 8, i16, "<8 x i16>", "v8i16") \
X(v4f32, 4, 4, 4, f32, "<4 x float>") \ X(v4i32, 4, 4, 4, i32, "<4 x i32>", "v4i32") \
//#define X(tag, sizeLog2, align, elts, elty, str) X(v4f32, 4, 4, 4, f32, "<4 x float>", "v4f32") \
//#define X(tag, sizeLog2, align, elts, elty, str, rcstr)
// Dictionary: // Dictionary:
// V - Is vector type. // V - Is vector type.
......
...@@ -22,12 +22,30 @@ ...@@ -22,12 +22,30 @@
namespace Ice { namespace Ice {
enum Type { 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 ICETYPE_TABLE
#undef X #undef X
IceType_NUM 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 { enum TargetArch {
#define X(tag, str, is_elf64, e_machine, e_flags) tag, #define X(tag, str, is_elf64, e_machine, e_flags) tag,
TARGETARCH_TABLE TARGETARCH_TABLE
...@@ -64,6 +82,7 @@ size_t typeAlignInBytes(Type Ty); ...@@ -64,6 +82,7 @@ size_t typeAlignInBytes(Type Ty);
size_t typeNumElements(Type Ty); size_t typeNumElements(Type Ty);
Type typeElementType(Type Ty); Type typeElementType(Type Ty);
const char *typeString(Type Ty); const char *typeString(Type Ty);
const char *regClassString(RegClass C);
inline Type getPointerType() { return IceType_i32; } inline Type getPointerType() { return IceType_i32; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment