-
Notifications
You must be signed in to change notification settings - Fork 14.3k
RegAlloc: Use DiagnosticInfo to report register allocation failures #119492
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RegAlloc: Use DiagnosticInfo to report register allocation failures #119492
Conversation
@llvm/pr-subscribers-backend-amdgpu @llvm/pr-subscribers-llvm-regalloc Author: Matt Arsenault (arsenm) ChangesImprove the non-fatal cases to use DiagnosticInfo, which will now Full diff: https://github.com/llvm/llvm-project/pull/119492.diff 12 Files Affected:
diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h
index 4c34c39683e56a..0d582cc17967e5 100644
--- a/llvm/include/llvm/IR/DiagnosticInfo.h
+++ b/llvm/include/llvm/IR/DiagnosticInfo.h
@@ -61,6 +61,7 @@ enum DiagnosticKind {
DK_Generic,
DK_GenericWithLoc,
DK_InlineAsm,
+ DK_RegAllocFailure,
DK_ResourceLimit,
DK_StackSize,
DK_Linker,
@@ -399,6 +400,32 @@ class DiagnosticInfoGenericWithLoc : public DiagnosticInfoWithLocationBase {
}
};
+class DiagnosticInfoRegAllocFailure : public DiagnosticInfoWithLocationBase {
+private:
+ /// Message to be reported.
+ const Twine &MsgStr;
+
+public:
+ /// \p MsgStr is the message to be reported to the frontend.
+ /// This class does not copy \p MsgStr, therefore the reference must be valid
+ /// for the whole life time of the Diagnostic.
+ DiagnosticInfoRegAllocFailure(const Twine &MsgStr, const Function &Fn,
+ const DiagnosticLocation &DL,
+ DiagnosticSeverity Severity = DS_Error);
+
+ DiagnosticInfoRegAllocFailure(const Twine &MsgStr, const Function &Fn,
+ DiagnosticSeverity Severity = DS_Error);
+
+ const Twine &getMsgStr() const { return MsgStr; }
+
+ /// \see DiagnosticInfo::print.
+ void print(DiagnosticPrinter &DP) const override;
+
+ static bool classof(const DiagnosticInfo *DI) {
+ return DI->getKind() == DK_RegAllocFailure;
+ }
+};
+
/// Diagnostic information for stack size etc. reporting.
/// This is basically a function and a size.
class DiagnosticInfoResourceLimit : public DiagnosticInfoWithLocationBase {
diff --git a/llvm/lib/CodeGen/RegAllocBase.cpp b/llvm/lib/CodeGen/RegAllocBase.cpp
index e9fcff5c8ccbd8..2246e1230e4278 100644
--- a/llvm/lib/CodeGen/RegAllocBase.cpp
+++ b/llvm/lib/CodeGen/RegAllocBase.cpp
@@ -23,6 +23,7 @@
#include "llvm/CodeGen/Spiller.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/VirtRegMap.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
@@ -124,17 +125,21 @@ void RegAllocBase::allocatePhysRegs() {
const TargetRegisterClass *RC = MRI->getRegClass(VirtReg->reg());
ArrayRef<MCPhysReg> AllocOrder = RegClassInfo.getOrder(RC);
- if (AllocOrder.empty())
+ if (AllocOrder.empty()) {
report_fatal_error("no registers from class available to allocate");
- else if (MI && MI->isInlineAsm()) {
- MI->emitInlineAsmError(
- "inline assembly requires more registers than available");
- } else if (MI) {
- LLVMContext &Context =
- MI->getParent()->getParent()->getFunction().getContext();
- Context.emitError("ran out of registers during register allocation");
} else {
- report_fatal_error("ran out of registers during register allocation");
+ const Function &Fn = VRM->getMachineFunction().getFunction();
+
+ if (MI && MI->isInlineAsm()) {
+ MI->emitInlineAsmError(
+ "inline assembly requires more registers than available");
+ } else {
+ LLVMContext &Context = Fn.getContext();
+ DiagnosticInfoRegAllocFailure DI(
+ "ran out of registers during register allocation", Fn,
+ MI ? MI->getDebugLoc() : DiagnosticLocation());
+ Context.diagnose(DI);
+ }
}
// Keep going after reporting the error.
diff --git a/llvm/lib/CodeGen/RegAllocFast.cpp b/llvm/lib/CodeGen/RegAllocFast.cpp
index cd1e6263d7a43f..65a27d564d1e30 100644
--- a/llvm/lib/CodeGen/RegAllocFast.cpp
+++ b/llvm/lib/CodeGen/RegAllocFast.cpp
@@ -682,7 +682,7 @@ void RegAllocFastImpl::reloadAtBegin(MachineBasicBlock &MBB) {
getMBBBeginInsertionPoint(MBB, PrologLiveIns);
for (const LiveReg &LR : LiveVirtRegs) {
MCPhysReg PhysReg = LR.PhysReg;
- if (PhysReg == 0)
+ if (PhysReg == 0 || LR.Error)
continue;
MCRegister FirstUnit = *TRI->regunits(PhysReg).begin();
@@ -963,14 +963,22 @@ void RegAllocFastImpl::allocVirtReg(MachineInstr &MI, LiveReg &LR,
if (!BestReg) {
// Nothing we can do: Report an error and keep going with an invalid
// allocation.
- if (MI.isInlineAsm())
+ if (MI.isInlineAsm()) {
MI.emitInlineAsmError(
"inline assembly requires more registers than available");
- else
- MI.emitInlineAsmError("ran out of registers during register allocation");
+ } else {
+ const Function &Fn = MBB->getParent()->getFunction();
+ DiagnosticInfoRegAllocFailure DI(
+ "ran out of registers during register allocation", Fn,
+ MI.getDebugLoc());
+ Fn.getContext().diagnose(DI);
+ }
LR.Error = true;
- LR.PhysReg = 0;
+ if (!AllocationOrder.empty())
+ LR.PhysReg = AllocationOrder.front();
+ else
+ LR.PhysReg = 0;
return;
}
@@ -1076,7 +1084,7 @@ bool RegAllocFastImpl::defineVirtReg(MachineInstr &MI, unsigned OpNum,
return setPhysReg(MI, MO, *AllocationOrder.begin());
}
} else {
- assert(!isRegUsedInInstr(LRI->PhysReg, LookAtPhysRegUses) &&
+ assert((!isRegUsedInInstr(LRI->PhysReg, LookAtPhysRegUses) || LRI->Error) &&
"TODO: preassign mismatch");
LLVM_DEBUG(dbgs() << "In def of " << printReg(VirtReg, TRI)
<< " use existing assignment to "
diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp
index eb91f49a524acc..0e526ada4b405b 100644
--- a/llvm/lib/IR/DiagnosticInfo.cpp
+++ b/llvm/lib/IR/DiagnosticInfo.cpp
@@ -80,6 +80,24 @@ void DiagnosticInfoInlineAsm::print(DiagnosticPrinter &DP) const {
DP << " at line " << getLocCookie();
}
+DiagnosticInfoRegAllocFailure::DiagnosticInfoRegAllocFailure(
+ const Twine &MsgStr, const Function &Fn, const DiagnosticLocation &DL,
+ DiagnosticSeverity Severity)
+ : DiagnosticInfoWithLocationBase(DK_RegAllocFailure, Severity, Fn,
+ DL.isValid() ? DL : Fn.getSubprogram()),
+ MsgStr(MsgStr) {}
+
+DiagnosticInfoRegAllocFailure::DiagnosticInfoRegAllocFailure(
+ const Twine &MsgStr, const Function &Fn, DiagnosticSeverity Severity)
+ : DiagnosticInfoWithLocationBase(DK_RegAllocFailure, Severity, Fn,
+ Fn.getSubprogram()),
+ MsgStr(MsgStr) {}
+
+void DiagnosticInfoRegAllocFailure::print(DiagnosticPrinter &DP) const {
+ DP << getLocationStr() << ": " << MsgStr << " in function '" << getFunction()
+ << '\'';
+}
+
DiagnosticInfoResourceLimit::DiagnosticInfoResourceLimit(
const Function &Fn, const char *ResourceName, uint64_t ResourceSize,
uint64_t ResourceLimit, DiagnosticSeverity Severity, DiagnosticKind Kind)
diff --git a/llvm/test/CodeGen/AArch64/arm64-anyregcc-crash.ll b/llvm/test/CodeGen/AArch64/arm64-anyregcc-crash.ll
index b4fb9b613233d2..ad8b027f8b760d 100644
--- a/llvm/test/CodeGen/AArch64/arm64-anyregcc-crash.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-anyregcc-crash.ll
@@ -2,7 +2,7 @@
;
; Check that misuse of anyregcc results in a compile time error.
-; CHECK: error: ran out of registers during register allocation
+; CHECK: error: <unknown>:0:0: ran out of registers during register allocation
define i64 @anyreglimit(i64 %v1, i64 %v2, i64 %v3, i64 %v4, i64 %v5, i64 %v6, i64 %v7, i64 %v8,
i64 %v9, i64 %v10, i64 %v11, i64 %v12, i64 %v13, i64 %v14, i64 %v15, i64 %v16,
i64 %v17, i64 %v18, i64 %v19, i64 %v20, i64 %v21, i64 %v22, i64 %v23, i64 %v24,
diff --git a/llvm/test/CodeGen/AMDGPU/illegal-eviction-assert.mir b/llvm/test/CodeGen/AMDGPU/illegal-eviction-assert.mir
index 40089ed82b5db0..99c27fa0bc95c4 100644
--- a/llvm/test/CodeGen/AMDGPU/illegal-eviction-assert.mir
+++ b/llvm/test/CodeGen/AMDGPU/illegal-eviction-assert.mir
@@ -6,7 +6,7 @@
# check was inconsistent with a later assertion when the eviction was
# performed.
-# ERR: error: ran out of registers during register allocation
+# ERR: error: <unknown>:0:0: ran out of registers during register allocation
--- |
define void @foo() #0 {
diff --git a/llvm/test/CodeGen/AMDGPU/issue48473.mir b/llvm/test/CodeGen/AMDGPU/issue48473.mir
index 5c202d9928ab78..e272bd34803831 100644
--- a/llvm/test/CodeGen/AMDGPU/issue48473.mir
+++ b/llvm/test/CodeGen/AMDGPU/issue48473.mir
@@ -2,7 +2,7 @@
# RUN: FileCheck -check-prefix=ERR %s < %t.err
# ERR: error: register allocation failed: maximum depth for recoloring reached. Use -fexhaustive-register-search to skip cutoffs
-# ERR-NEXT: error: ran out of registers during register allocation
+# ERR-NEXT: error: <unknown>:0:0: ran out of registers during register allocation
# This testcase used to fail with an "overlapping insert" assertion
# when trying to roll back an unsucessful recoloring of %25. One of
diff --git a/llvm/test/CodeGen/AMDGPU/ran-out-of-registers-error-all-regs-reserved.ll b/llvm/test/CodeGen/AMDGPU/ran-out-of-registers-error-all-regs-reserved.ll
new file mode 100644
index 00000000000000..300eeeeddcf26f
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/ran-out-of-registers-error-all-regs-reserved.ll
@@ -0,0 +1,24 @@
+; RUN: not --crash llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx908 -vgpr-regalloc=greedy -filetype=null %s 2>&1 | FileCheck %s
+; RUN: not --crash llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx908 -vgpr-regalloc=basic -filetype=null %s 2>&1 | FileCheck %s
+
+; TODO: Check regalloc fast when it doesn't assert after failing.
+
+; TODO: Make error use DiagnosticInfo and merge with
+; ran-out-of-registers-errors.ll
+
+; CHECK: LLVM ERROR: no registers from class available to allocate
+
+declare <32 x i32> @llvm.amdgcn.mfma.i32.32x32x4i8(i32, i32, <32 x i32>, i32 immarg, i32 immarg, i32 immarg)
+
+define <32 x i32> @no_registers_from_class_available_to_allocate(<32 x i32> %arg) #0 {
+ %ret = call <32 x i32> @llvm.amdgcn.mfma.i32.32x32x4i8(i32 1, i32 2, <32 x i32> %arg, i32 1, i32 2, i32 3)
+ ret <32 x i32> %ret
+}
+
+; FIXME: Special case in fast RA, asserts. Also asserts in greedy
+; define void @no_registers_from_class_available_to_allocate_undef_asm() #0 {
+; call void asm sideeffect "; use $0", "v"(<32 x i32> poison)
+; ret void
+; }
+
+attributes #0 = { "amdgpu-waves-per-eu"="10,10" }
diff --git a/llvm/test/CodeGen/AMDGPU/ran-out-of-registers-errors.ll b/llvm/test/CodeGen/AMDGPU/ran-out-of-registers-errors.ll
new file mode 100644
index 00000000000000..3d150fe90d5ce9
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/ran-out-of-registers-errors.ll
@@ -0,0 +1,70 @@
+; 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
+; 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
+; 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
+; RUN: opt -passes=debugify -o %t.bc %s
+; 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
+; 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
+
+; FIXME: Asserts when using -O2 + -vgpr-regalloc=fast
+; 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
+
+; TODO: Should we fix emitting multiple errors sometimes in basic and fast?
+
+
+; CHECK: error: <unknown>:0:0: ran out of registers during register allocation in function 'ran_out_of_registers_general'
+; BASIC: error: <unknown>:0:0: ran out of registers during register allocation in function 'ran_out_of_registers_general'
+; FAST: error: <unknown>:0:0: ran out of registers during register allocation in function 'ran_out_of_registers_general'
+
+; DBGINFO-GREEDY: error: {{.*}}:3:1: ran out of registers during register allocation in function 'ran_out_of_registers_general'
+
+; DBGINFO-BASIC: error: {{.*}}:1:1: ran out of registers during register allocation in function 'ran_out_of_registers_general'
+; DBGINFO-BASIC: error: {{.*}}:3:1: ran out of registers during register allocation in function 'ran_out_of_registers_general'
+
+; DBGINFO-FAST: error: {{.*}}:3:1: ran out of registers during register allocation in function 'ran_out_of_registers_general'
+; DBGINFO-FAST: error: {{.*}}:1:0: ran out of registers during register allocation in function 'ran_out_of_registers_general'
+define i32 @ran_out_of_registers_general(ptr addrspace(1) %ptr) #0 {
+ %ld0 = load volatile i32, ptr addrspace(1) %ptr
+ %ld1 = load volatile i32, ptr addrspace(1) %ptr
+ %add = add i32 %ld0, %ld1
+ ret i32 %add
+}
+
+; CHECK: error: inline assembly requires more registers than available at line 23
+; DBGINFO-CHECK: error: inline assembly requires more registers than available at line 23
+define void @ran_out_of_registers_asm_def() #0 {
+ %asm = call { i32, i32 } asm sideeffect "; def $0 $1", "=v,=v"(), !srcloc !0
+ ret void
+}
+
+; CHECK: error: inline assembly requires more registers than available at line 23
+; DBGINFO-CHECK: error: inline assembly requires more registers than available at line 23
+define void @ran_out_of_registers_asm_use() #0 {
+ call void asm sideeffect "; def $0 $1", "v,v"(i32 0, i32 1), !srcloc !0
+ ret void
+}
+
+; Test error in anonymous function.
+
+; GREEDY: error: inline assembly requires more registers than available at line 23
+; BASIC: error: inline assembly requires more registers than available at line 23
+
+; FAST: error: <unknown>:0:0: ran out of registers during register allocation in function '@0'
+; FAST: error: <unknown>:0:0: ran out of registers during register allocation in function '@0'
+
+
+; DBGINFO-GREEDY: error: inline assembly requires more registers than available at line 23
+; DBGINFO-BASIC: error: inline assembly requires more registers than available at line 23
+
+; DBGINFO-FAST: error: {{.*}}:12:1: ran out of registers during register allocation in function '@0'
+; DBGINFO-FAST: error: {{.*}}:9:0: ran out of registers during register allocation in function '@0'
+define i32 @0(ptr addrspace(1) %ptr) #0 {
+ %asm = call { i32, i32 } asm sideeffect "; def $0 $1 use $2", "=v,=v,v"(ptr addrspace(1) %ptr), !srcloc !0
+ %elt0 = extractvalue { i32, i32 } %asm, 0
+ %elt1 = extractvalue { i32, i32 } %asm, 1
+ %add = add i32 %elt0, %elt1
+ ret i32 %add
+}
+
+attributes #0 = { "target-cpu"="gfx908" }
+
+!0 = !{i32 23}
diff --git a/llvm/test/CodeGen/AMDGPU/remaining-virtual-register-operands.ll b/llvm/test/CodeGen/AMDGPU/remaining-virtual-register-operands.ll
index 04e995b6f343ef..8e3054cceb85b7 100644
--- a/llvm/test/CodeGen/AMDGPU/remaining-virtual-register-operands.ll
+++ b/llvm/test/CodeGen/AMDGPU/remaining-virtual-register-operands.ll
@@ -10,7 +10,7 @@
; This happens due to when register allocator is out of registers
; it takes the first avialable register.
-; CHECK: error: ran out of registers during register allocation
+; CHECK: error: <unknown>:0:0: ran out of registers during register allocation
; CHECK: Bad machine code: Using an undefined physical register
define amdgpu_kernel void @alloc_failure_with_split_vregs(float %v0, float %v1) #0 {
%agpr0 = call float asm sideeffect "; def $0", "=${a0}"()
diff --git a/llvm/test/CodeGen/PowerPC/ppc64-anyregcc-crash.ll b/llvm/test/CodeGen/PowerPC/ppc64-anyregcc-crash.ll
index a7d372c5e61a29..e4d96678b28771 100644
--- a/llvm/test/CodeGen/PowerPC/ppc64-anyregcc-crash.ll
+++ b/llvm/test/CodeGen/PowerPC/ppc64-anyregcc-crash.ll
@@ -2,7 +2,7 @@
;
; Check that misuse of anyregcc results in a compile time error.
-; CHECK: error: ran out of registers during register allocation
+; CHECK: error: <unknown>:0:0: ran out of registers during register allocation
define i64 @anyreglimit(i64 %v1, i64 %v2, i64 %v3, i64 %v4, i64 %v5, i64 %v6, i64 %v7, i64 %v8,
i64 %v9, i64 %v10, i64 %v11, i64 %v12, i64 %v13, i64 %v14, i64 %v15, i64 %v16,
i64 %v17, i64 %v18, i64 %v19, i64 %v20, i64 %v21, i64 %v22, i64 %v23, i64 %v24,
diff --git a/llvm/test/CodeGen/X86/anyregcc-crash.ll b/llvm/test/CodeGen/X86/anyregcc-crash.ll
index d5d6ebe751c0d9..3b65babea23ebf 100644
--- a/llvm/test/CodeGen/X86/anyregcc-crash.ll
+++ b/llvm/test/CodeGen/X86/anyregcc-crash.ll
@@ -2,7 +2,7 @@
;
; Check that misuse of anyregcc results in a compile time error.
-; CHECK: error: ran out of registers during register allocation
+; CHECK: error: <unknown>:0:0: ran out of registers during register allocation
define i64 @anyreglimit(i64 %v1, i64 %v2, i64 %v3, i64 %v4, i64 %v5, i64 %v6,
i64 %v7, i64 %v8, i64 %v9, i64 %v10, i64 %v11, i64 %v12,
i64 %v13, i64 %v14, i64 %v15, i64 %v16) {
|
8bfb4bd
to
84bc22e
Compare
204d8aa
to
ce786fd
Compare
|
||
LR.Error = true; | ||
LR.PhysReg = 0; | ||
if (!AllocationOrder.empty()) | ||
LR.PhysReg = AllocationOrder.front(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LR.PhysReg = 0 makes more sense to me (the original code).
Why are you still trying to assign something at this point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LR.PhysReg is used as a lack of assignment marker in non-error situations. We need a definitive registers assignment. This will get cleaned up more in a pending PR
ce786fd
to
400fba2
Compare
400fba2
to
7b20a3b
Compare
Merge activity
|
7b20a3b
to
f6b6cbe
Compare
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.
f6b6cbe
to
33f8439
Compare
These two the tests are failing on the buildbot in stage2/asan with a stack use-after-scope: https://lab.llvm.org/buildbot/#/builders/52/builds/4533 (first failure here; contains llvm#119492 and llvm#119640) ... https://lab.llvm.org/buildbot/#/builders/52/builds/4550 This patch disables the tests for now, to allow the bots to return to green.
Two tests are failing on the buildbot in stage2/asan with a stack use-after-scope: https://lab.llvm.org/buildbot/#/builders/52/builds/4533 (first failure here; contains #119492 and #119640) ... https://lab.llvm.org/buildbot/#/builders/52/builds/4550 This patch disables the tests for now, to allow the bots to return to green (instead of reverting the patch series).
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.