Skip to content

Commit 61f99a1

Browse files
authored
RegAlloc: Do not fatal error if there are no registers in the alloc order (#119640)
Try to use DiagnosticInfo if every register in the class is reserved by forcing assignment to a reserved register. Also reduces the number of redundant errors emitted, particularly with fast. This is still broken in the case of undef uses. There are additional complications in greedy and fast, so leave it for a separate fix.
1 parent bb18e49 commit 61f99a1

10 files changed

+139
-68
lines changed

llvm/include/llvm/CodeGen/MachineFunction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ class MachineFunctionProperties {
186186
Selected,
187187
TiedOpsRewritten,
188188
FailsVerification,
189+
FailedRegAlloc,
189190
TracksDebugUserValues,
190191
LastProperty = TracksDebugUserValues,
191192
};

llvm/lib/CodeGen/MachineFunction.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ static const char *getPropertyName(MachineFunctionProperties::Property Prop) {
102102
case P::TracksLiveness: return "TracksLiveness";
103103
case P::TiedOpsRewritten: return "TiedOpsRewritten";
104104
case P::FailsVerification: return "FailsVerification";
105+
case P::FailedRegAlloc: return "FailedRegAlloc";
105106
case P::TracksDebugUserValues: return "TracksDebugUserValues";
106107
}
107108
// clang-format on

llvm/lib/CodeGen/RegAllocBase.cpp

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -124,25 +124,10 @@ void RegAllocBase::allocatePhysRegs() {
124124
}
125125

126126
const TargetRegisterClass *RC = MRI->getRegClass(VirtReg->reg());
127-
ArrayRef<MCPhysReg> AllocOrder = RegClassInfo.getOrder(RC);
128-
if (AllocOrder.empty()) {
129-
report_fatal_error("no registers from class available to allocate");
130-
} else {
131-
if (MI && MI->isInlineAsm()) {
132-
MI->emitInlineAsmError(
133-
"inline assembly requires more registers than available");
134-
} else {
135-
const Function &Fn = VRM->getMachineFunction().getFunction();
136-
LLVMContext &Context = Fn.getContext();
137-
DiagnosticInfoRegAllocFailure DI(
138-
"ran out of registers during register allocation", Fn,
139-
MI ? MI->getDebugLoc() : DiagnosticLocation());
140-
Context.diagnose(DI);
141-
}
142-
}
127+
AvailablePhysReg = getErrorAssignment(*RC, MI);
143128

144129
// Keep going after reporting the error.
145-
VRM->assignVirt2Phys(VirtReg->reg(), AllocOrder.front());
130+
VRM->assignVirt2Phys(VirtReg->reg(), AvailablePhysReg);
146131
} else if (AvailablePhysReg)
147132
Matrix->assign(*VirtReg, AvailablePhysReg);
148133

@@ -192,3 +177,50 @@ void RegAllocBase::enqueue(const LiveInterval *LI) {
192177
<< " in skipped register class\n");
193178
}
194179
}
180+
181+
MCPhysReg RegAllocBase::getErrorAssignment(const TargetRegisterClass &RC,
182+
const MachineInstr *CtxMI) {
183+
MachineFunction &MF = VRM->getMachineFunction();
184+
185+
// Avoid printing the error for every single instance of the register. It
186+
// would be better if this were per register class.
187+
bool EmitError = !MF.getProperties().hasProperty(
188+
MachineFunctionProperties::Property::FailedRegAlloc);
189+
if (EmitError)
190+
MF.getProperties().set(MachineFunctionProperties::Property::FailedRegAlloc);
191+
192+
const Function &Fn = MF.getFunction();
193+
LLVMContext &Context = Fn.getContext();
194+
195+
ArrayRef<MCPhysReg> AllocOrder = RegClassInfo.getOrder(&RC);
196+
if (AllocOrder.empty()) {
197+
// If the allocation order is empty, it likely means all registers in the
198+
// class are reserved. We still to need to pick something, so look at the
199+
// underlying class.
200+
ArrayRef<MCPhysReg> RawRegs = RC.getRegisters();
201+
202+
if (EmitError) {
203+
DiagnosticInfoRegAllocFailure DI(
204+
"no registers from class available to allocate", Fn,
205+
CtxMI ? CtxMI->getDebugLoc() : DiagnosticLocation());
206+
Context.diagnose(DI);
207+
}
208+
209+
assert(!RawRegs.empty() && "register classes cannot have no registers");
210+
return RawRegs.front();
211+
}
212+
213+
if (EmitError) {
214+
if (CtxMI && CtxMI->isInlineAsm()) {
215+
CtxMI->emitInlineAsmError(
216+
"inline assembly requires more registers than available");
217+
} else {
218+
DiagnosticInfoRegAllocFailure DI(
219+
"ran out of registers during register allocation", Fn,
220+
CtxMI ? CtxMI->getDebugLoc() : DiagnosticLocation());
221+
Context.diagnose(DI);
222+
}
223+
}
224+
225+
return AllocOrder.front();
226+
}

llvm/lib/CodeGen/RegAllocBase.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ class RegAllocBase {
123123
virtual MCRegister selectOrSplit(const LiveInterval &VirtReg,
124124
SmallVectorImpl<Register> &splitLVRs) = 0;
125125

126+
/// Query a physical register to use as a filler in contexts where the
127+
/// allocation has failed. This will raise an error, but not abort the
128+
/// compilation.
129+
MCPhysReg getErrorAssignment(const TargetRegisterClass &RC,
130+
const MachineInstr *CtxMI = nullptr);
131+
126132
// Use this group name for NamedRegionTimer.
127133
static const char TimerGroupName[];
128134
static const char TimerGroupDescription[];

llvm/lib/CodeGen/RegAllocFast.cpp

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,9 @@ class RegAllocFastImpl {
368368
bool LookAtPhysRegUses = false);
369369
bool useVirtReg(MachineInstr &MI, MachineOperand &MO, Register VirtReg);
370370

371+
MCPhysReg getErrorAssignment(const LiveReg &LR, MachineInstr &MI,
372+
const TargetRegisterClass &RC);
373+
371374
MachineBasicBlock::iterator
372375
getMBBBeginInsertionPoint(MachineBasicBlock &MBB,
373376
SmallSet<Register, 2> &PrologLiveIns) const;
@@ -963,22 +966,8 @@ void RegAllocFastImpl::allocVirtReg(MachineInstr &MI, LiveReg &LR,
963966
if (!BestReg) {
964967
// Nothing we can do: Report an error and keep going with an invalid
965968
// allocation.
966-
if (MI.isInlineAsm()) {
967-
MI.emitInlineAsmError(
968-
"inline assembly requires more registers than available");
969-
} else {
970-
const Function &Fn = MBB->getParent()->getFunction();
971-
DiagnosticInfoRegAllocFailure DI(
972-
"ran out of registers during register allocation", Fn,
973-
MI.getDebugLoc());
974-
Fn.getContext().diagnose(DI);
975-
}
976-
969+
LR.PhysReg = getErrorAssignment(LR, MI, RC);
977970
LR.Error = true;
978-
if (!AllocationOrder.empty())
979-
LR.PhysReg = AllocationOrder.front();
980-
else
981-
LR.PhysReg = 0;
982971
return;
983972
}
984973

@@ -1000,6 +989,7 @@ void RegAllocFastImpl::allocVirtRegUndef(MachineOperand &MO) {
1000989
} else {
1001990
const TargetRegisterClass &RC = *MRI->getRegClass(VirtReg);
1002991
ArrayRef<MCPhysReg> AllocationOrder = RegClassInfo.getOrder(&RC);
992+
// FIXME: This can happen, and should fall back to a reserved entry in RC.
1003993
assert(!AllocationOrder.empty() && "Allocation order must not be empty");
1004994
PhysReg = AllocationOrder[0];
1005995
}
@@ -1074,15 +1064,6 @@ bool RegAllocFastImpl::defineVirtReg(MachineInstr &MI, unsigned OpNum,
10741064
}
10751065
if (LRI->PhysReg == 0) {
10761066
allocVirtReg(MI, *LRI, 0, LookAtPhysRegUses);
1077-
// If no physical register is available for LRI, we assign one at random
1078-
// and bail out of this function immediately.
1079-
if (LRI->Error) {
1080-
const TargetRegisterClass &RC = *MRI->getRegClass(VirtReg);
1081-
ArrayRef<MCPhysReg> AllocationOrder = RegClassInfo.getOrder(&RC);
1082-
if (AllocationOrder.empty())
1083-
return setPhysReg(MI, MO, MCRegister::NoRegister);
1084-
return setPhysReg(MI, MO, *AllocationOrder.begin());
1085-
}
10861067
} else {
10871068
assert((!isRegUsedInInstr(LRI->PhysReg, LookAtPhysRegUses) || LRI->Error) &&
10881069
"TODO: preassign mismatch");
@@ -1167,13 +1148,6 @@ bool RegAllocFastImpl::useVirtReg(MachineInstr &MI, MachineOperand &MO,
11671148
}
11681149
}
11691150
allocVirtReg(MI, *LRI, Hint, false);
1170-
if (LRI->Error) {
1171-
const TargetRegisterClass &RC = *MRI->getRegClass(VirtReg);
1172-
ArrayRef<MCPhysReg> AllocationOrder = RegClassInfo.getOrder(&RC);
1173-
if (AllocationOrder.empty())
1174-
return setPhysReg(MI, MO, MCRegister::NoRegister);
1175-
return setPhysReg(MI, MO, *AllocationOrder.begin());
1176-
}
11771151
}
11781152

11791153
LRI->LastUse = &MI;
@@ -1185,6 +1159,56 @@ bool RegAllocFastImpl::useVirtReg(MachineInstr &MI, MachineOperand &MO,
11851159
return setPhysReg(MI, MO, LRI->PhysReg);
11861160
}
11871161

1162+
/// Query a physical register to use as a filler in contexts where the
1163+
/// allocation has failed. This will raise an error, but not abort the
1164+
/// compilation.
1165+
MCPhysReg RegAllocFastImpl::getErrorAssignment(const LiveReg &LR,
1166+
MachineInstr &MI,
1167+
const TargetRegisterClass &RC) {
1168+
MachineFunction &MF = *MI.getMF();
1169+
1170+
// Avoid repeating the error every time a register is used.
1171+
bool EmitError = !MF.getProperties().hasProperty(
1172+
MachineFunctionProperties::Property::FailedRegAlloc);
1173+
if (EmitError)
1174+
MF.getProperties().set(MachineFunctionProperties::Property::FailedRegAlloc);
1175+
1176+
// If the allocation order was empty, all registers in the class were
1177+
// probably reserved. Fall back to taking the first register in the class,
1178+
// even if it's reserved.
1179+
ArrayRef<MCPhysReg> AllocationOrder = RegClassInfo.getOrder(&RC);
1180+
if (AllocationOrder.empty()) {
1181+
const Function &Fn = MF.getFunction();
1182+
if (EmitError) {
1183+
DiagnosticInfoRegAllocFailure DI(
1184+
"no registers from class available to allocate", Fn,
1185+
MI.getDebugLoc());
1186+
Fn.getContext().diagnose(DI);
1187+
}
1188+
1189+
ArrayRef<MCPhysReg> RawRegs = RC.getRegisters();
1190+
assert(!RawRegs.empty() && "register classes cannot have no registers");
1191+
return RawRegs.front();
1192+
}
1193+
1194+
if (!LR.Error && EmitError) {
1195+
// Nothing we can do: Report an error and keep going with an invalid
1196+
// allocation.
1197+
if (MI.isInlineAsm()) {
1198+
MI.emitInlineAsmError(
1199+
"inline assembly requires more registers than available");
1200+
} else {
1201+
const Function &Fn = MBB->getParent()->getFunction();
1202+
DiagnosticInfoRegAllocFailure DI(
1203+
"ran out of registers during register allocation", Fn,
1204+
MI.getDebugLoc());
1205+
Fn.getContext().diagnose(DI);
1206+
}
1207+
}
1208+
1209+
return AllocationOrder.front();
1210+
}
1211+
11881212
/// Changes operand OpNum in MI the refer the PhysReg, considering subregs.
11891213
/// \return true if MI's MachineOperands were re-arranged/invalidated.
11901214
bool RegAllocFastImpl::setPhysReg(MachineInstr &MI, MachineOperand &MO,

llvm/lib/CodeGen/VirtRegMap.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ void VirtRegMap::assignVirt2Phys(Register virtReg, MCPhysReg physReg) {
8888
assert(!Virt2PhysMap[virtReg] &&
8989
"attempt to assign physical register to already mapped "
9090
"virtual register");
91-
assert(!getRegInfo().isReserved(physReg) &&
91+
assert((!getRegInfo().isReserved(physReg) ||
92+
MF->getProperties().hasProperty(
93+
MachineFunctionProperties::Property::FailedRegAlloc)) &&
9294
"Attempt to map virtReg to a reserved physReg");
9395
Virt2PhysMap[virtReg] = physReg;
9496
}
@@ -615,7 +617,10 @@ void VirtRegRewriter::rewrite() {
615617
assert(Register(PhysReg).isPhysical());
616618

617619
RewriteRegs.insert(PhysReg);
618-
assert(!MRI->isReserved(PhysReg) && "Reserved register assignment");
620+
assert((!MRI->isReserved(PhysReg) ||
621+
MF->getProperties().hasProperty(
622+
MachineFunctionProperties::Property::FailedRegAlloc)) &&
623+
"Reserved register assignment");
619624

620625
// Preserve semantics of sub-register operands.
621626
unsigned SubReg = MO.getSubReg();

llvm/test/CodeGen/AMDGPU/alloc-all-regs-reserved-in-class.mir

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
# RUN: not --crash llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -run-pass=greedy -verify-machineinstrs -o /dev/null %s 2>&1 | FileCheck %s
1+
# RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -run-pass=greedy -verify-machineinstrs -filetype=null %s 2>&1 | FileCheck --implicit-check-not=error %s
22

33
# Check that there isn't an assert if we try to allocate a virtual register from
44
# a class where all registers are reserved. All AGPRs are reserved on subtargets
55
# that do not have them.
66

7-
# CHECK-NOT: ran out of registers during register allocation
8-
# CHECK: LLVM ERROR: no registers from class available to allocate
9-
# CHECK-NOT: ran out of registers during register allocation
7+
# CHECK: error: <unknown>:0:0: no registers from class available to allocate in function 'use_agpr'
108

119
---
1210
name: use_agpr

llvm/test/CodeGen/AMDGPU/ran-out-of-registers-error-all-regs-reserved.ll

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,29 @@
1-
; RUN: not --crash llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx908 -vgpr-regalloc=greedy -filetype=null %s 2>&1 | FileCheck %s
2-
; RUN: not --crash llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx908 -vgpr-regalloc=basic -filetype=null %s 2>&1 | FileCheck %s
1+
; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx908 -vgpr-regalloc=greedy -verify-machineinstrs=0 -filetype=null %s 2>&1 | FileCheck -implicit-check-not=error %s
2+
; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx908 -vgpr-regalloc=basic -verify-machineinstrs=0 -filetype=null %s 2>&1 | FileCheck -implicit-check-not=error %s
3+
; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx908 -vgpr-regalloc=fast -verify-machineinstrs=0 -filetype=null %s 2>&1 | FileCheck -implicit-check-not=error %s
34

4-
; TODO: Check regalloc fast when it doesn't assert after failing.
5-
6-
; CHECK: LLVM ERROR: no registers from class available to allocate
5+
; FIXME: Should pass verifier after failure.
76

87
declare <32 x i32> @llvm.amdgcn.mfma.i32.32x32x4i8(i32, i32, <32 x i32>, i32 immarg, i32 immarg, i32 immarg)
98

9+
; CHECK: error: <unknown>:0:0: no registers from class available to allocate in function 'no_registers_from_class_available_to_allocate'
1010
define <32 x i32> @no_registers_from_class_available_to_allocate(<32 x i32> %arg) #0 {
1111
%ret = call <32 x i32> @llvm.amdgcn.mfma.i32.32x32x4i8(i32 1, i32 2, <32 x i32> %arg, i32 1, i32 2, i32 3)
1212
ret <32 x i32> %ret
1313
}
1414

15+
; CHECK: error: <unknown>:0:0: no registers from class available to allocate in function 'no_registers_from_class_available_to_allocate_asm_use'
16+
define void @no_registers_from_class_available_to_allocate_asm_use(<32 x i32> %arg) #0 {
17+
call void asm sideeffect "; use $0", "v"(<32 x i32> %arg)
18+
ret void
19+
}
20+
21+
; CHECK: error: <unknown>:0:0: no registers from class available to allocate in function 'no_registers_from_class_available_to_allocate_asm_def'
22+
define <32 x i32> @no_registers_from_class_available_to_allocate_asm_def() #0 {
23+
%ret = call <32 x i32> asm sideeffect "; def $0", "=v"()
24+
ret <32 x i32> %ret
25+
}
26+
1527
; FIXME: Special case in fast RA, asserts. Also asserts in greedy
1628
; define void @no_registers_from_class_available_to_allocate_undef_asm() #0 {
1729
; call void asm sideeffect "; use $0", "v"(<32 x i32> poison)

llvm/test/CodeGen/AMDGPU/ran-out-of-registers-errors.ll

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,12 @@
1212

1313

1414
; CHECK: error: <unknown>:0:0: ran out of registers during register allocation in function 'ran_out_of_registers_general'
15-
; BASIC: error: <unknown>:0:0: ran out of registers during register allocation in function 'ran_out_of_registers_general'
16-
; FAST: error: <unknown>:0:0: ran out of registers during register allocation in function 'ran_out_of_registers_general'
1715

1816
; DBGINFO-GREEDY: error: {{.*}}:3:1: ran out of registers during register allocation in function 'ran_out_of_registers_general'
1917

2018
; DBGINFO-BASIC: error: {{.*}}:1:1: ran out of registers during register allocation in function 'ran_out_of_registers_general'
21-
; DBGINFO-BASIC: error: {{.*}}:3:1: ran out of registers during register allocation in function 'ran_out_of_registers_general'
2219

2320
; DBGINFO-FAST: error: {{.*}}:3:1: ran out of registers during register allocation in function 'ran_out_of_registers_general'
24-
; DBGINFO-FAST: error: {{.*}}:1:0: ran out of registers during register allocation in function 'ran_out_of_registers_general'
2521
define i32 @ran_out_of_registers_general(ptr addrspace(1) %ptr) #0 {
2622
%ld0 = load volatile i32, ptr addrspace(1) %ptr
2723
%ld1 = load volatile i32, ptr addrspace(1) %ptr
@@ -49,14 +45,11 @@ define void @ran_out_of_registers_asm_use() #0 {
4945
; BASIC: error: inline assembly requires more registers than available at line 23
5046

5147
; FAST: error: <unknown>:0:0: ran out of registers during register allocation in function '@0'
52-
; FAST: error: <unknown>:0:0: ran out of registers during register allocation in function '@0'
53-
5448

5549
; DBGINFO-GREEDY: error: inline assembly requires more registers than available at line 23
5650
; DBGINFO-BASIC: error: inline assembly requires more registers than available at line 23
5751

5852
; DBGINFO-FAST: error: {{.*}}:12:1: ran out of registers during register allocation in function '@0'
59-
; DBGINFO-FAST: error: {{.*}}:9:0: ran out of registers during register allocation in function '@0'
6053
define i32 @0(ptr addrspace(1) %ptr) #0 {
6154
%asm = call { i32, i32 } asm sideeffect "; def $0 $1 use $2", "=v,=v,v"(ptr addrspace(1) %ptr), !srcloc !0
6255
%elt0 = extractvalue { i32, i32 } %asm, 0

llvm/test/CodeGen/AMDGPU/regalloc-illegal-eviction-assert.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
; RUN: not llc -mtriple=amdgcn -mcpu=gfx908 -verify-machineinstrs -o - %s 2>%t.err | FileCheck %s
1+
; RUN: not llc -mtriple=amdgcn -mcpu=gfx908 -verify-machineinstrs -o - %s 2>%t.err | FileCheck -implicit-check-not=error %s
22
; RUN: FileCheck -check-prefix=ERR %s < %t.err
33

44
; This testcase would fail on an "illegal eviction". If the assert was
55
; relaxed to allow equivalent cascade numbers, it would infinite loop.
66

7-
; ERR: error: inline assembly requires more registers than available
87
; ERR: error: inline assembly requires more registers than available
98

109
%asm.output = type { <16 x i32>, <8 x i32>, <5 x i32>, <4 x i32>, <16 x i32> }

0 commit comments

Comments
 (0)