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:
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.
......
......@@ -685,11 +685,14 @@ void LinearScan::handleNoFreeRegisters(IterationState &Iter) {
// 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
......
......@@ -138,39 +138,68 @@ void printRegisterSet(Ostream &Str, const llvm::SmallBitVector &Bitset,
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 @@ void TargetLowering::filterTypeToRegisterSet(
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 @@ void TargetLowering::filterTypeToRegisterSet(
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);
}
......
......@@ -355,7 +355,8 @@ protected:
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;
......
......@@ -271,6 +271,18 @@ constexpr SizeT NumVec128Args =
#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 @@ void TargetARM32::staticInit(GlobalContext *Ctx) {
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 @@ void TargetHeaderARM32::lower() {
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
......
......@@ -60,6 +60,17 @@ namespace {
// 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 @@ void TargetMIPS32::staticInit(GlobalContext *Ctx) {
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 @@ void TargetHeaderMIPS32::lower() {
<< "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
......
......@@ -432,7 +432,7 @@ enum _tmp_enum {
_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 @@ ICETYPEX8632_TABLE
#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
......
......@@ -516,7 +516,7 @@ public:
(*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;
......
......@@ -699,7 +699,7 @@ enum _tmp_enum {
_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 @@ ICETYPEX8664_TABLE
#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
......
......@@ -96,6 +96,25 @@ public:
}
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 &
......
......@@ -381,7 +381,7 @@ void TargetX86Base<TraitsType>::staticInit(GlobalContext *Ctx) {
&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;
......
......@@ -30,7 +30,7 @@ const char *TargetArchName[] = {
// 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 {
_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 @@ ICETYPE_PROPS_TABLE
// 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 @@ struct TypeAttributeFields {
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 @@ const char *typeString(Type Ty) {
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;
......
......@@ -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.
......
......@@ -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 typeAlignInBytes(Type Ty);
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; }
......
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