Skip to content

Commit 204d8aa

Browse files
committed
RegAlloc: Use DiagnosticInfo to report register allocation failures
Improve the non-fatal cases to use DiagnosticInfo, which will now provide a location. The allocators attempt to report different errors if it happens to see inline assembly is involved (this detection is quite unreliable) using srcloc instead of dbgloc. For now, leave this behavior unchanged. I think reporting the full location and context function would be more useful.
1 parent 8bfb4bd commit 204d8aa

12 files changed

+173
-21
lines changed

llvm/include/llvm/IR/DiagnosticInfo.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ enum DiagnosticKind {
6161
DK_Generic,
6262
DK_GenericWithLoc,
6363
DK_InlineAsm,
64+
DK_RegAllocFailure,
6465
DK_ResourceLimit,
6566
DK_StackSize,
6667
DK_Linker,
@@ -399,6 +400,32 @@ class DiagnosticInfoGenericWithLoc : public DiagnosticInfoWithLocationBase {
399400
}
400401
};
401402

403+
class DiagnosticInfoRegAllocFailure : public DiagnosticInfoWithLocationBase {
404+
private:
405+
/// Message to be reported.
406+
const Twine &MsgStr;
407+
408+
public:
409+
/// \p MsgStr is the message to be reported to the frontend.
410+
/// This class does not copy \p MsgStr, therefore the reference must be valid
411+
/// for the whole life time of the Diagnostic.
412+
DiagnosticInfoRegAllocFailure(const Twine &MsgStr, const Function &Fn,
413+
const DiagnosticLocation &DL,
414+
DiagnosticSeverity Severity = DS_Error);
415+
416+
DiagnosticInfoRegAllocFailure(const Twine &MsgStr, const Function &Fn,
417+
DiagnosticSeverity Severity = DS_Error);
418+
419+
const Twine &getMsgStr() const { return MsgStr; }
420+
421+
/// \see DiagnosticInfo::print.
422+
void print(DiagnosticPrinter &DP) const override;
423+
424+
static bool classof(const DiagnosticInfo *DI) {
425+
return DI->getKind() == DK_RegAllocFailure;
426+
}
427+
};
428+
402429
/// Diagnostic information for stack size etc. reporting.
403430
/// This is basically a function and a size.
404431
class DiagnosticInfoResourceLimit : public DiagnosticInfoWithLocationBase {

llvm/lib/CodeGen/RegAllocBase.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/CodeGen/Spiller.h"
2424
#include "llvm/CodeGen/TargetRegisterInfo.h"
2525
#include "llvm/CodeGen/VirtRegMap.h"
26+
#include "llvm/IR/DiagnosticInfo.h"
2627
#include "llvm/IR/Module.h"
2728
#include "llvm/Pass.h"
2829
#include "llvm/Support/CommandLine.h"
@@ -124,17 +125,21 @@ void RegAllocBase::allocatePhysRegs() {
124125

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

140145
// Keep going after reporting the error.

llvm/lib/CodeGen/RegAllocFast.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,7 @@ void RegAllocFastImpl::reloadAtBegin(MachineBasicBlock &MBB) {
682682
getMBBBeginInsertionPoint(MBB, PrologLiveIns);
683683
for (const LiveReg &LR : LiveVirtRegs) {
684684
MCPhysReg PhysReg = LR.PhysReg;
685-
if (PhysReg == 0)
685+
if (PhysReg == 0 || LR.Error)
686686
continue;
687687

688688
MCRegister FirstUnit = *TRI->regunits(PhysReg).begin();
@@ -963,14 +963,22 @@ void RegAllocFastImpl::allocVirtReg(MachineInstr &MI, LiveReg &LR,
963963
if (!BestReg) {
964964
// Nothing we can do: Report an error and keep going with an invalid
965965
// allocation.
966-
if (MI.isInlineAsm())
966+
if (MI.isInlineAsm()) {
967967
MI.emitInlineAsmError(
968968
"inline assembly requires more registers than available");
969-
else
970-
MI.emitInlineAsmError("ran out of registers during register allocation");
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+
}
971976

972977
LR.Error = true;
973-
LR.PhysReg = 0;
978+
if (!AllocationOrder.empty())
979+
LR.PhysReg = AllocationOrder.front();
980+
else
981+
LR.PhysReg = 0;
974982
return;
975983
}
976984

@@ -1076,7 +1084,7 @@ bool RegAllocFastImpl::defineVirtReg(MachineInstr &MI, unsigned OpNum,
10761084
return setPhysReg(MI, MO, *AllocationOrder.begin());
10771085
}
10781086
} else {
1079-
assert(!isRegUsedInInstr(LRI->PhysReg, LookAtPhysRegUses) &&
1087+
assert((!isRegUsedInInstr(LRI->PhysReg, LookAtPhysRegUses) || LRI->Error) &&
10801088
"TODO: preassign mismatch");
10811089
LLVM_DEBUG(dbgs() << "In def of " << printReg(VirtReg, TRI)
10821090
<< " use existing assignment to "

llvm/lib/IR/DiagnosticInfo.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,24 @@ void DiagnosticInfoInlineAsm::print(DiagnosticPrinter &DP) const {
8080
DP << " at line " << getLocCookie();
8181
}
8282

83+
DiagnosticInfoRegAllocFailure::DiagnosticInfoRegAllocFailure(
84+
const Twine &MsgStr, const Function &Fn, const DiagnosticLocation &DL,
85+
DiagnosticSeverity Severity)
86+
: DiagnosticInfoWithLocationBase(DK_RegAllocFailure, Severity, Fn,
87+
DL.isValid() ? DL : Fn.getSubprogram()),
88+
MsgStr(MsgStr) {}
89+
90+
DiagnosticInfoRegAllocFailure::DiagnosticInfoRegAllocFailure(
91+
const Twine &MsgStr, const Function &Fn, DiagnosticSeverity Severity)
92+
: DiagnosticInfoWithLocationBase(DK_RegAllocFailure, Severity, Fn,
93+
Fn.getSubprogram()),
94+
MsgStr(MsgStr) {}
95+
96+
void DiagnosticInfoRegAllocFailure::print(DiagnosticPrinter &DP) const {
97+
DP << getLocationStr() << ": " << MsgStr << " in function '" << getFunction()
98+
<< '\'';
99+
}
100+
83101
DiagnosticInfoResourceLimit::DiagnosticInfoResourceLimit(
84102
const Function &Fn, const char *ResourceName, uint64_t ResourceSize,
85103
uint64_t ResourceLimit, DiagnosticSeverity Severity, DiagnosticKind Kind)

llvm/test/CodeGen/AArch64/arm64-anyregcc-crash.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
;
33
; Check that misuse of anyregcc results in a compile time error.
44

5-
; CHECK: error: ran out of registers during register allocation
5+
; CHECK: error: <unknown>:0:0: ran out of registers during register allocation
66
define i64 @anyreglimit(i64 %v1, i64 %v2, i64 %v3, i64 %v4, i64 %v5, i64 %v6, i64 %v7, i64 %v8,
77
i64 %v9, i64 %v10, i64 %v11, i64 %v12, i64 %v13, i64 %v14, i64 %v15, i64 %v16,
88
i64 %v17, i64 %v18, i64 %v19, i64 %v20, i64 %v21, i64 %v22, i64 %v23, i64 %v24,

llvm/test/CodeGen/AMDGPU/illegal-eviction-assert.mir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# check was inconsistent with a later assertion when the eviction was
77
# performed.
88

9-
# ERR: error: ran out of registers during register allocation
9+
# ERR: error: <unknown>:0:0: ran out of registers during register allocation
1010

1111
--- |
1212
define void @foo() #0 {

llvm/test/CodeGen/AMDGPU/issue48473.mir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# RUN: FileCheck -check-prefix=ERR %s < %t.err
33

44
# ERR: error: register allocation failed: maximum depth for recoloring reached. Use -fexhaustive-register-search to skip cutoffs
5-
# ERR-NEXT: error: ran out of registers during register allocation
5+
# ERR-NEXT: error: <unknown>:0:0: ran out of registers during register allocation
66

77
# This testcase used to fail with an "overlapping insert" assertion
88
# when trying to roll back an unsucessful recoloring of %25. One of
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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
3+
4+
; TODO: Check regalloc fast when it doesn't assert after failing.
5+
6+
; TODO: Make error use DiagnosticInfo and merge with
7+
; ran-out-of-registers-errors.ll
8+
9+
; CHECK: LLVM ERROR: no registers from class available to allocate
10+
11+
declare <32 x i32> @llvm.amdgcn.mfma.i32.32x32x4i8(i32, i32, <32 x i32>, i32 immarg, i32 immarg, i32 immarg)
12+
13+
define <32 x i32> @no_registers_from_class_available_to_allocate(<32 x i32> %arg) #0 {
14+
%ret = call <32 x i32> @llvm.amdgcn.mfma.i32.32x32x4i8(i32 1, i32 2, <32 x i32> %arg, i32 1, i32 2, i32 3)
15+
ret <32 x i32> %ret
16+
}
17+
18+
; FIXME: Special case in fast RA, asserts. Also asserts in greedy
19+
; define void @no_registers_from_class_available_to_allocate_undef_asm() #0 {
20+
; call void asm sideeffect "; use $0", "v"(<32 x i32> poison)
21+
; ret void
22+
; }
23+
24+
attributes #0 = { "amdgpu-waves-per-eu"="10,10" }
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
; RUN: not llc -mtriple=amdgcn-amd-amdhsa -stress-regalloc=1 -vgpr-regalloc=greedy -filetype=null %s 2>&1 | FileCheck -check-prefixes=CHECK,GREEDY -implicit-check-not=error %s
2+
; RUN: not llc -mtriple=amdgcn-amd-amdhsa -stress-regalloc=1 -vgpr-regalloc=basic -filetype=null %s 2>&1 | FileCheck -implicit-check-not=error -check-prefixes=CHECK,BASIC %s
3+
; RUN: not llc -mtriple=amdgcn-amd-amdhsa -stress-regalloc=1 -vgpr-regalloc=fast -filetype=null %s 2>&1 | FileCheck -implicit-check-not=error -check-prefixes=CHECK,FAST %s
4+
; RUN: opt -passes=debugify -o %t.bc %s
5+
; RUN: not llc -mtriple=amdgcn-amd-amdhsa -stress-regalloc=1 -vgpr-regalloc=greedy -filetype=null %t.bc 2>&1 | FileCheck -implicit-check-not=error -check-prefixes=DBGINFO-CHECK,DBGINFO-GREEDY %s
6+
; RUN: not llc -mtriple=amdgcn-amd-amdhsa -stress-regalloc=1 -vgpr-regalloc=basic -filetype=null %t.bc 2>&1 | FileCheck -implicit-check-not=error -check-prefixes=DBGINFO-CHECK,DBGINFO-BASIC %s
7+
8+
; FIXME: Asserts when using -O2 + -vgpr-regalloc=fast
9+
; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx908 -stress-regalloc=1 -O0 -filetype=null %t.bc 2>&1 | FileCheck -implicit-check-not=error -check-prefixes=DBGINFO-CHECK,DBGINFO-FAST %s
10+
11+
; TODO: Should we fix emitting multiple errors sometimes in basic and fast?
12+
13+
14+
; 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'
17+
18+
; DBGINFO-GREEDY: error: {{.*}}:3:1: ran out of registers during register allocation in function 'ran_out_of_registers_general'
19+
20+
; 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'
22+
23+
; 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'
25+
define i32 @ran_out_of_registers_general(ptr addrspace(1) %ptr) #0 {
26+
%ld0 = load volatile i32, ptr addrspace(1) %ptr
27+
%ld1 = load volatile i32, ptr addrspace(1) %ptr
28+
%add = add i32 %ld0, %ld1
29+
ret i32 %add
30+
}
31+
32+
; CHECK: error: inline assembly requires more registers than available at line 23
33+
; DBGINFO-CHECK: error: inline assembly requires more registers than available at line 23
34+
define void @ran_out_of_registers_asm_def() #0 {
35+
%asm = call { i32, i32 } asm sideeffect "; def $0 $1", "=v,=v"(), !srcloc !0
36+
ret void
37+
}
38+
39+
; CHECK: error: inline assembly requires more registers than available at line 23
40+
; DBGINFO-CHECK: error: inline assembly requires more registers than available at line 23
41+
define void @ran_out_of_registers_asm_use() #0 {
42+
call void asm sideeffect "; def $0 $1", "v,v"(i32 0, i32 1), !srcloc !0
43+
ret void
44+
}
45+
46+
; Test error in anonymous function.
47+
48+
; GREEDY: error: inline assembly requires more registers than available at line 23
49+
; BASIC: error: inline assembly requires more registers than available at line 23
50+
51+
; 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+
54+
55+
; DBGINFO-GREEDY: error: inline assembly requires more registers than available at line 23
56+
; DBGINFO-BASIC: error: inline assembly requires more registers than available at line 23
57+
58+
; 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'
60+
define i32 @0(ptr addrspace(1) %ptr) #0 {
61+
%asm = call { i32, i32 } asm sideeffect "; def $0 $1 use $2", "=v,=v,v"(ptr addrspace(1) %ptr), !srcloc !0
62+
%elt0 = extractvalue { i32, i32 } %asm, 0
63+
%elt1 = extractvalue { i32, i32 } %asm, 1
64+
%add = add i32 %elt0, %elt1
65+
ret i32 %add
66+
}
67+
68+
attributes #0 = { "target-cpu"="gfx908" }
69+
70+
!0 = !{i32 23}

llvm/test/CodeGen/AMDGPU/remaining-virtual-register-operands.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
; This happens due to when register allocator is out of registers
1111
; it takes the first avialable register.
1212

13-
; CHECK: error: ran out of registers during register allocation
13+
; CHECK: error: <unknown>:0:0: ran out of registers during register allocation
1414
; CHECK: Bad machine code: Using an undefined physical register
1515
define amdgpu_kernel void @alloc_failure_with_split_vregs(float %v0, float %v1) #0 {
1616
%agpr0 = call float asm sideeffect "; def $0", "=${a0}"()

llvm/test/CodeGen/PowerPC/ppc64-anyregcc-crash.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
;
33
; Check that misuse of anyregcc results in a compile time error.
44

5-
; CHECK: error: ran out of registers during register allocation
5+
; CHECK: error: <unknown>:0:0: ran out of registers during register allocation
66
define i64 @anyreglimit(i64 %v1, i64 %v2, i64 %v3, i64 %v4, i64 %v5, i64 %v6, i64 %v7, i64 %v8,
77
i64 %v9, i64 %v10, i64 %v11, i64 %v12, i64 %v13, i64 %v14, i64 %v15, i64 %v16,
88
i64 %v17, i64 %v18, i64 %v19, i64 %v20, i64 %v21, i64 %v22, i64 %v23, i64 %v24,

llvm/test/CodeGen/X86/anyregcc-crash.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
;
33
; Check that misuse of anyregcc results in a compile time error.
44

5-
; CHECK: error: ran out of registers during register allocation
5+
; CHECK: error: <unknown>:0:0: ran out of registers during register allocation
66
define i64 @anyreglimit(i64 %v1, i64 %v2, i64 %v3, i64 %v4, i64 %v5, i64 %v6,
77
i64 %v7, i64 %v8, i64 %v9, i64 %v10, i64 %v11, i64 %v12,
88
i64 %v13, i64 %v14, i64 %v15, i64 %v16) {

0 commit comments

Comments
 (0)