[llvm] [CodeGen][RAGreedy] Inform LiveDebugVariables about snippets spilled by InlineSpiller. (PR #109962)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 25 04:10:11 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-regalloc

Author: Bevin Hansson (bevin-hansson)

<details>
<summary>Changes</summary>

RAGreedy invokes InlineSpiller to spill a particular virtreg inline. When the
spiller does this, it also identifies small, adjacent liveranges called
snippets. These are also spilled or rematerialized in the process.

However, the spiller does not inform RA that it has spilled these regs.
This means that debug variable locations referencing these regs/ranges are
lost.

Mark any spilled regs which do not have a stack slot assigned to them as
allocated to the slot being spilled to to tell LDV that those regs are
located in that slot, even though the regs might no longer exist in the
program after regalloc is finished. Also, inform RA about all of the regs
which were replaced (spilled or rematted), not just the one that was
requested so that it can properly manage the ranges of the debug vars.


---
Full diff: https://github.com/llvm/llvm-project/pull/109962.diff


4 Files Affected:

- (modified) llvm/include/llvm/CodeGen/Spiller.h (+2) 
- (modified) llvm/lib/CodeGen/InlineSpiller.cpp (+14-1) 
- (modified) llvm/lib/CodeGen/RegAllocGreedy.cpp (+2-1) 
- (added) llvm/test/CodeGen/X86/debug-spilled-snippet.ll (+55) 


``````````diff
diff --git a/llvm/include/llvm/CodeGen/Spiller.h b/llvm/include/llvm/CodeGen/Spiller.h
index b2f5485eba02e7..0731db533ad839 100644
--- a/llvm/include/llvm/CodeGen/Spiller.h
+++ b/llvm/include/llvm/CodeGen/Spiller.h
@@ -30,6 +30,8 @@ class Spiller {
   /// spill - Spill the LRE.getParent() live interval.
   virtual void spill(LiveRangeEdit &LRE) = 0;
 
+  virtual ArrayRef<Register> getReplacedRegs() = 0;
+
   virtual void postOptimization() {}
 };
 
diff --git a/llvm/lib/CodeGen/InlineSpiller.cpp b/llvm/lib/CodeGen/InlineSpiller.cpp
index 409879a8b49bcc..93027678c0652b 100644
--- a/llvm/lib/CodeGen/InlineSpiller.cpp
+++ b/llvm/lib/CodeGen/InlineSpiller.cpp
@@ -167,6 +167,10 @@ class InlineSpiller : public Spiller {
   // All registers to spill to StackSlot, including the main register.
   SmallVector<Register, 8> RegsToSpill;
 
+  // All registers that were replaced by the spiller. This includes registers
+  // that were rematerialized; rematted regs are removed from RegsToSpill.
+  SmallVector<Register, 8> RegsReplaced;
+
   // All COPY instructions to/from snippets.
   // They are ignored since both operands refer to the same stack slot.
   // For bundled copies, this will only include the first header copy.
@@ -199,6 +203,7 @@ class InlineSpiller : public Spiller {
         HSpiller(Pass, MF, VRM), VRAI(VRAI) {}
 
   void spill(LiveRangeEdit &) override;
+  ArrayRef<Register> getReplacedRegs() override { return RegsReplaced; }
   void postOptimization() override;
 
 private:
@@ -385,6 +390,7 @@ void InlineSpiller::collectRegsToSpill() {
   // Main register always spills.
   RegsToSpill.assign(1, Reg);
   SnippetCopies.clear();
+  RegsReplaced.assign(RegsToSpill);
 
   // Snippets all have the same original, so there can't be any for an original
   // register.
@@ -405,6 +411,8 @@ void InlineSpiller::collectRegsToSpill() {
     LLVM_DEBUG(dbgs() << "\talso spill snippet " << SnipLI << '\n');
     ++NumSnippets;
   }
+
+  RegsReplaced.assign(RegsToSpill);
 }
 
 bool InlineSpiller::isSibling(Register Reg) {
@@ -1255,8 +1263,13 @@ void InlineSpiller::spillAll() {
   LLVM_DEBUG(dbgs() << "Merged spilled regs: " << *StackInt << '\n');
 
   // Spill around uses of all RegsToSpill.
-  for (Register Reg : RegsToSpill)
+  for (Register Reg : RegsToSpill) {
     spillAroundUses(Reg);
+    // Assign all of the spilled registers to the slot so that
+    // LiveDebugVariables knows about these locations later on.
+    if (VRM.getStackSlot(Reg) == VirtRegMap::NO_STACK_SLOT)
+      VRM.assignVirt2StackSlot(Reg, StackSlot);
+  }
 
   // Hoisted spills may cause dead code.
   if (!DeadDefs.empty()) {
diff --git a/llvm/lib/CodeGen/RegAllocGreedy.cpp b/llvm/lib/CodeGen/RegAllocGreedy.cpp
index 1ad70c86d68e3d..60d1c7e53316c9 100644
--- a/llvm/lib/CodeGen/RegAllocGreedy.cpp
+++ b/llvm/lib/CodeGen/RegAllocGreedy.cpp
@@ -2504,7 +2504,8 @@ MCRegister RAGreedy::selectOrSplitImpl(const LiveInterval &VirtReg,
     // Tell LiveDebugVariables about the new ranges. Ranges not being covered by
     // the new regs are kept in LDV (still mapping to the old register), until
     // we rewrite spilled locations in LDV at a later stage.
-    DebugVars->splitRegister(VirtReg.reg(), LRE.regs(), *LIS);
+    for (Register r : spiller().getReplacedRegs())
+      DebugVars->splitRegister(r, LRE.regs(), *LIS);
 
     if (VerifyEnabled)
       MF->verify(this, "After spilling", &errs());
diff --git a/llvm/test/CodeGen/X86/debug-spilled-snippet.ll b/llvm/test/CodeGen/X86/debug-spilled-snippet.ll
new file mode 100644
index 00000000000000..c05e93f5b15d65
--- /dev/null
+++ b/llvm/test/CodeGen/X86/debug-spilled-snippet.ll
@@ -0,0 +1,55 @@
+; RUN: llc -O3 -mtriple i386 %s -stop-after=livedebugvalues -o - | FileCheck %s
+
+; There should be multiple debug values for this variable after regalloc. The
+; value has been spilled, but we shouldn't lose track of the location because
+; of this.
+
+; CHECK-COUNT-4: DBG_VALUE $ebp, 0, !6, !DIExpression(DW_OP_constu, 16, DW_OP_minus), debug-location !10
+
+define void @main(i32 %call, i32 %xor.i, i1 %tobool4.not, i32 %.pre) #0 !dbg !4 {
+entry:
+  %tobool1.not = icmp ne i32 %call, 0
+  %spec.select = zext i1 %tobool1.not to i32
+  br label %for.body5
+
+for.cond.loopexit.loopexit:                       ; preds = %for.body5
+    #dbg_value(i32 %spec.select, !6, !DIExpression(), !10)
+  %tobool.not.i53 = icmp eq i32 %spec.select, 0
+  br i1 %tobool.not.i53, label %transparent_crc.exit57, label %if.then.i54
+
+for.body5:                                        ; preds = %for.body5, %entry
+  %0 = phi i32 [ 0, %entry ], [ %xor1.i40.i, %for.body5 ]
+  %xor6.i = xor i32 %.pre, %0
+  %shr7.i = ashr i32 %xor6.i, 1
+  %xor17.i = xor i32 %shr7.i, %call
+  %shr18.i = ashr i32 %xor17.i, 1
+  %xor.i.i = xor i32 %shr18.i, %xor.i
+  %arrayidx.i.i = getelementptr [0 x i32], ptr null, i32 0, i32 %xor.i.i
+  %xor1.i40.i = xor i32 %xor.i.i, %call
+  br i1 %tobool4.not, label %for.cond.loopexit.loopexit, label %for.body5
+
+if.then.i54:                                      ; preds = %for.cond.loopexit.loopexit
+  store i64 0, ptr null, align 4
+  br label %transparent_crc.exit57
+
+transparent_crc.exit57:                           ; preds = %if.then.i54, %for.cond.loopexit.loopexit
+  ret void
+}
+
+attributes #0 = { "frame-pointer"="all" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 20.0.0git.prerel", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !2, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "xx.c", directory: "/path", checksumkind: CSK_MD5, checksum: "c4b2fc62bca9171ad484c91fb78b8842")
+!2 = !{}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 20, type: !5, scopeLine: 20, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
+!5 = !DISubroutineType(types: !2)
+!6 = !DILocalVariable(name: "flag", arg: 2, scope: !7, file: !1, line: 8, type: !9)
+!7 = distinct !DISubprogram(name: "transparent_crc", scope: !1, file: !1, line: 8, type: !8, scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
+!8 = distinct !DISubroutineType(types: !2)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DILocation(line: 0, scope: !7, inlinedAt: !11)
+!11 = distinct !DILocation(line: 28, column: 3, scope: !4)

``````````

</details>


https://github.com/llvm/llvm-project/pull/109962


More information about the llvm-commits mailing list