Skip to content

Commit 3c6cd73

Browse files
authored
CodeGen: Do not store RegisterClass copy costs as a signed value (#161786)
Tolerate setting negative values in tablegen, and store them as a saturated uint8_t value. This will allow naive uses of the copy cost to directly add it as a cost without considering the degenerate negative case. The degenerate negative cases are only used in InstrEmitter / DAG scheduling, so leave the special case processing there. There are also fixmes about this system already there. This is the expedient fix for an out of tree target regression after #160084. Currently targets can set a negative copy cost to mark copies as "impossible". However essentially all the in-tree uses only uses this for non-allocatable condition registers. We probably should replace the InstrEmitter/DAG scheduler uses with a more direct check for a copyable register but that has test changes.
1 parent fee840d commit 3c6cd73

File tree

9 files changed

+56
-13
lines changed

9 files changed

+56
-13
lines changed

llvm/include/llvm/CodeGen/TargetRegisterInfo.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,15 @@ class TargetRegisterClass {
109109
return MC->contains(Reg1.asMCReg(), Reg2.asMCReg());
110110
}
111111

112-
/// Return the cost of copying a value between two registers in this class.
113-
/// A negative number means the register class is very expensive
114-
/// to copy e.g. status flag register classes.
115-
int getCopyCost() const { return MC->getCopyCost(); }
112+
/// Return the cost of copying a value between two registers in this class. If
113+
/// this is the maximum value, the register may be impossible to copy.
114+
uint8_t getCopyCost() const { return MC->getCopyCost(); }
115+
116+
/// \return true if register class is very expensive to copy e.g. status flag
117+
/// register classes.
118+
bool expensiveOrImpossibleToCopy() const {
119+
return MC->getCopyCost() == std::numeric_limits<uint8_t>::max();
120+
}
116121

117122
/// Return true if this register class may be used to create virtual
118123
/// registers.

llvm/include/llvm/MC/MCRegisterInfo.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class MCRegisterClass {
4545
const uint16_t RegSetSize;
4646
const uint16_t ID;
4747
const uint16_t RegSizeInBits;
48-
const int8_t CopyCost;
48+
const uint8_t CopyCost;
4949
const bool Allocatable;
5050
const bool BaseClass;
5151

@@ -94,7 +94,7 @@ class MCRegisterClass {
9494
/// getCopyCost - Return the cost of copying a value between two registers in
9595
/// this class. A negative number means the register class is very expensive
9696
/// to copy e.g. status flag register classes.
97-
int getCopyCost() const { return CopyCost; }
97+
uint8_t getCopyCost() const { return CopyCost; }
9898

9999
/// isAllocatable - Return true if this register class may be used to create
100100
/// virtual registers.

llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ void InstrEmitter::EmitCopyFromReg(SDValue Op, bool IsClone, Register SrcReg,
160160

161161
// If all uses are reading from the src physical register and copying the
162162
// register is either impossible or very expensive, then don't create a copy.
163-
if (MatchReg && SrcRC->getCopyCost() < 0) {
163+
if (MatchReg && SrcRC->expensiveOrImpossibleToCopy()) {
164164
VRBase = SrcReg;
165165
} else {
166166
// Create the reg, emit the copy.

llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ static void CheckForPhysRegDependency(SDNode *Def, SDNode *User, unsigned Op,
136136
if (PhysReg) {
137137
const TargetRegisterClass *RC =
138138
TRI->getMinimalPhysRegClass(Reg, Def->getSimpleValueType(ResNo));
139-
Cost = RC->getCopyCost();
139+
Cost = RC->expensiveOrImpossibleToCopy() ? -1 : RC->getCopyCost();
140140
}
141141
}
142142

llvm/lib/Target/AMDGPU/SIISelLowering.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18879,7 +18879,7 @@ bool SITargetLowering::checkForPhysRegDependency(
1887918879
PhysReg = AMDGPU::SCC;
1888018880
const TargetRegisterClass *RC =
1888118881
TRI->getMinimalPhysRegClass(PhysReg, Def->getSimpleValueType(ResNo));
18882-
Cost = RC->getCopyCost();
18882+
Cost = RC->expensiveOrImpossibleToCopy() ? -1 : RC->getCopyCost();
1888318883
return true;
1888418884
}
1888518885
return false;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: llvm-tblgen --gen-register-info -I %p/../../include %s 2>&1 | FileCheck %s
2+
// RUN: not llvm-tblgen --gen-register-info -I %p/../../include -DERROR %s 2>&1 | FileCheck -check-prefix=ERROR %s
3+
4+
// Check that there is no assertion when specifying unsupported
5+
// CopyCost values on register classes. Check that negative CopyCost
6+
// values are saturated to 255.
7+
8+
include "llvm/Target/Target.td"
9+
10+
// CHECK: extern const MCRegisterClass MyTargetMCRegisterClasses[] = {
11+
// CHECK-NEXT: { GPR32, GPR32Bits, 0, 2, sizeof(GPR32Bits), MyTarget::GPR32RegClassID, 32, 1, true, false },
12+
// CHECK-NEXT: { SPECIAL_CLASS, SPECIAL_CLASSBits, 6, 1, sizeof(SPECIAL_CLASSBits), MyTarget::SPECIAL_CLASSRegClassID, 32, 255, true, false },
13+
// CHECK-NEXT: };
14+
15+
def MyTargetISA : InstrInfo;
16+
def MyTarget : Target { let InstructionSet = MyTargetISA; }
17+
18+
def R0 : Register<"r0"> { let Namespace = "MyTarget"; }
19+
def R1 : Register<"r1"> { let Namespace = "MyTarget"; }
20+
def SPECIAL : Register<"special"> { let Namespace = "MyTarget"; }
21+
22+
// ERROR: :[[@LINE+1]]:5: error: 'CopyCost' must be an 8-bit value
23+
def GPR32 : RegisterClass<"MyTarget", [i32], 32, (add R0, R1)> {
24+
#ifdef ERROR
25+
let CopyCost = 256;
26+
#endif
27+
}
28+
29+
def SPECIAL_CLASS : RegisterClass<"MyTarget", [i32], 32, (add SPECIAL)> {
30+
let CopyCost = -1;
31+
}

llvm/utils/TableGen/Common/CodeGenRegisters.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,7 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank,
744744
RSI.insertRegSizeForMode(DefaultMode, RI);
745745
}
746746

747-
CopyCost = R->getValueAsInt("CopyCost");
747+
int CopyCostParsed = R->getValueAsInt("CopyCost");
748748
Allocatable = R->getValueAsBit("isAllocatable");
749749
AltOrderSelect = R->getValueAsString("AltOrderSelect");
750750
int AllocationPriority = R->getValueAsInt("AllocationPriority");
@@ -757,6 +757,14 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank,
757757
const BitsInit *TSF = R->getValueAsBitsInit("TSFlags");
758758
for (auto [Idx, Bit] : enumerate(TSF->getBits()))
759759
TSFlags |= uint8_t(cast<BitInit>(Bit)->getValue()) << Idx;
760+
761+
// Saturate negative costs to the maximum
762+
if (CopyCostParsed < 0)
763+
CopyCost = std::numeric_limits<uint8_t>::max();
764+
else if (!isUInt<8>(CopyCostParsed))
765+
PrintFatalError(R->getLoc(), "'CopyCost' must be an 8-bit value");
766+
767+
CopyCost = CopyCostParsed;
760768
}
761769

762770
// Create an inferred register class that was missing from the .td files.

llvm/utils/TableGen/Common/CodeGenRegisters.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ class CodeGenRegisterClass {
359359
StringRef Namespace;
360360
SmallVector<ValueTypeByHwMode, 4> VTs;
361361
RegSizeInfoByHwMode RSI;
362-
int CopyCost;
362+
uint8_t CopyCost;
363363
bool Allocatable;
364364
StringRef AltOrderSelect;
365365
uint8_t AllocationPriority;

llvm/utils/TableGen/RegisterInfoEmitter.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,14 +1083,13 @@ void RegisterInfoEmitter::runMCDesc(raw_ostream &OS) {
10831083
std::string RCName = Order.empty() ? "nullptr" : RC.getName();
10841084
std::string RCBitsName = Order.empty() ? "nullptr" : RC.getName() + "Bits";
10851085
std::string RCBitsSize = Order.empty() ? "0" : "sizeof(" + RCBitsName + ")";
1086-
assert(isInt<8>(RC.CopyCost) && "Copy cost too large.");
10871086
uint32_t RegSize = 0;
10881087
if (RC.RSI.isSimple())
10891088
RegSize = RC.RSI.getSimple().RegSize;
10901089
OS << " { " << RCName << ", " << RCBitsName << ", "
10911090
<< RegClassStrings.get(RC.getName()) << ", " << RC.getOrder().size()
10921091
<< ", " << RCBitsSize << ", " << RC.getQualifiedIdName() << ", "
1093-
<< RegSize << ", " << RC.CopyCost << ", "
1092+
<< RegSize << ", " << static_cast<unsigned>(RC.CopyCost) << ", "
10941093
<< (RC.Allocatable ? "true" : "false") << ", "
10951094
<< (RC.getBaseClassOrder() ? "true" : "false") << " },\n";
10961095
}

0 commit comments

Comments
 (0)