[llvm] bb18e49 - RegAlloc: Use DiagnosticInfo to report register allocation failures (#119492)

via llvm-commits llvm-commits at lists.llvm.org
Sun Dec 15 17:49:11 PST 2024


Author: Matt Arsenault
Date: 2024-12-16T10:49:08+09:00
New Revision: bb18e49edb2c4bbb7dd70ee0b5946598822a4e2a

URL: https://github.com/llvm/llvm-project/commit/bb18e49edb2c4bbb7dd70ee0b5946598822a4e2a
DIFF: https://github.com/llvm/llvm-project/commit/bb18e49edb2c4bbb7dd70ee0b5946598822a4e2a.diff

LOG: RegAlloc: Use DiagnosticInfo to report register allocation failures (#119492)

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.

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

Modified: 
    llvm/include/llvm/IR/DiagnosticInfo.h
    llvm/lib/CodeGen/RegAllocBase.cpp
    llvm/lib/CodeGen/RegAllocFast.cpp
    llvm/lib/IR/DiagnosticInfo.cpp
    llvm/test/CodeGen/AArch64/arm64-anyregcc-crash.ll
    llvm/test/CodeGen/AMDGPU/illegal-eviction-assert.mir
    llvm/test/CodeGen/AMDGPU/issue48473.mir
    llvm/test/CodeGen/AMDGPU/remaining-virtual-register-operands.ll
    llvm/test/CodeGen/PowerPC/ppc64-anyregcc-crash.ll
    llvm/test/CodeGen/X86/anyregcc-crash.ll

Removed: 
    


################################################################################
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..6300f6b8bf6d18 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,20 @@ 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");
+        if (MI && MI->isInlineAsm()) {
+          MI->emitInlineAsmError(
+              "inline assembly requires more registers than available");
+        } else {
+          const Function &Fn = VRM->getMachineFunction().getFunction();
+          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..3e3e2010400158
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/ran-out-of-registers-error-all-regs-reserved.ll
@@ -0,0 +1,21 @@
+; 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.
+
+; 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) {


        


More information about the llvm-commits mailing list