[llvm] 1a65d95 - [CodeGen][RAGreedy] Inform LiveDebugVariables about snippets spilled by InlineSpiller. (#109962)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 2 01:30:00 PDT 2024
Author: Bevin Hansson
Date: 2024-10-02T10:29:56+02:00
New Revision: 1a65d95d0056ce98f94944ff1fd5309242fd5f28
URL: https://github.com/llvm/llvm-project/commit/1a65d95d0056ce98f94944ff1fd5309242fd5f28
DIFF: https://github.com/llvm/llvm-project/commit/1a65d95d0056ce98f94944ff1fd5309242fd5f28.diff
LOG: [CodeGen][RAGreedy] Inform LiveDebugVariables about snippets spilled by InlineSpiller. (#109962)
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.
Added:
llvm/test/CodeGen/X86/debug-spilled-snippet.ll
llvm/test/CodeGen/X86/debug-spilled-snippet.mir
Modified:
llvm/include/llvm/CodeGen/Spiller.h
llvm/lib/CodeGen/InlineSpiller.cpp
llvm/lib/CodeGen/RegAllocGreedy.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/CodeGen/Spiller.h b/llvm/include/llvm/CodeGen/Spiller.h
index b2f5485eba02e7..4568cdfab86288 100644
--- a/llvm/include/llvm/CodeGen/Spiller.h
+++ b/llvm/include/llvm/CodeGen/Spiller.h
@@ -30,6 +30,13 @@ class Spiller {
/// spill - Spill the LRE.getParent() live interval.
virtual void spill(LiveRangeEdit &LRE) = 0;
+ /// Return the registers that were spilled.
+ virtual ArrayRef<Register> getSpilledRegs() = 0;
+
+ /// Return registers that were not spilled, but otherwise replaced
+ /// (e.g. rematerialized).
+ virtual ArrayRef<Register> getReplacedRegs() = 0;
+
virtual void postOptimization() {}
};
diff --git a/llvm/lib/CodeGen/InlineSpiller.cpp b/llvm/lib/CodeGen/InlineSpiller.cpp
index 409879a8b49bcc..d1f67d1a3d4aa1 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 through some other method,
+ // e.g. rematerialization.
+ 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,8 @@ class InlineSpiller : public Spiller {
HSpiller(Pass, MF, VRM), VRAI(VRAI) {}
void spill(LiveRangeEdit &) override;
+ ArrayRef<Register> getSpilledRegs() override { return RegsToSpill; }
+ ArrayRef<Register> getReplacedRegs() override { return RegsReplaced; }
void postOptimization() override;
private:
@@ -385,6 +391,7 @@ void InlineSpiller::collectRegsToSpill() {
// Main register always spills.
RegsToSpill.assign(1, Reg);
SnippetCopies.clear();
+ RegsReplaced.clear();
// Snippets all have the same original, so there can't be any for an original
// register.
@@ -796,6 +803,7 @@ void InlineSpiller::reMaterializeAll() {
for (Register Reg : RegsToSpill) {
if (MRI.reg_nodbg_empty(Reg)) {
Edit->eraseVirtReg(Reg);
+ RegsReplaced.push_back(Reg);
continue;
}
@@ -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..8cfd2192de460e 100644
--- a/llvm/lib/CodeGen/RegAllocGreedy.cpp
+++ b/llvm/lib/CodeGen/RegAllocGreedy.cpp
@@ -2504,7 +2504,10 @@ 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().getSpilledRegs())
+ DebugVars->splitRegister(r, 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..96d5d9812325f9
--- /dev/null
+++ b/llvm/test/CodeGen/X86/debug-spilled-snippet.ll
@@ -0,0 +1,55 @@
+; RUN: llc -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)
diff --git a/llvm/test/CodeGen/X86/debug-spilled-snippet.mir b/llvm/test/CodeGen/X86/debug-spilled-snippet.mir
new file mode 100644
index 00000000000000..015701f71fefc0
--- /dev/null
+++ b/llvm/test/CodeGen/X86/debug-spilled-snippet.mir
@@ -0,0 +1,100 @@
+# RUN: llc -mtriple i386 -start-before=greedy -stop-after=livedebugvars %s -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() #0 !dbg !4 {
+ entry:
+ #dbg_value(i32 undef, !6, !DIExpression(), !10)
+ 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)
+
+...
+---
+name: main
+alignment: 16
+tracksRegLiveness: true
+hasWinCFI: false
+noPhis: true
+fixedStack:
+ - { id: 0, type: default, offset: 0, size: 4, alignment: 4, stack-id: default,
+ isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+ - { id: 1, type: default, offset: 4, size: 4, alignment: 4, stack-id: default,
+ isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+ - { id: 2, type: default, offset: 8, size: 1, alignment: 4, stack-id: default,
+ isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+ - { id: 3, type: default, offset: 12, size: 4, alignment: 4, stack-id: default,
+ isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body: |
+ bb.0:
+ successors: %bb.2(0x80000000)
+
+ %0:gr32 = MOV32rm %fixed-stack.3, 1, $noreg, 0, $noreg :: (load (s32) from %fixed-stack.3)
+ %1:gr8 = MOV8rm %fixed-stack.2, 1, $noreg, 0, $noreg :: (load (s8) from %fixed-stack.2, align 4)
+ %2:gr32 = MOV32rm %fixed-stack.0, 1, $noreg, 0, $noreg :: (load (s32) from %fixed-stack.0)
+ %3:gr32_abcd = MOV32r0 implicit-def dead $eflags
+ TEST32rr %2, %2, implicit-def $eflags
+ %3.sub_8bit:gr32_abcd = SETCCr 5, implicit $eflags
+ %4:gr32 = COPY %2
+ %4:gr32 = SAR32ri %4, 1, implicit-def dead $eflags
+ %5:gr32 = MOV32rm %fixed-stack.1, 1, $noreg, 0, $noreg :: (load (s32) from %fixed-stack.1)
+ %6:gr32 = MOV32r0 implicit-def dead $eflags
+ JMP_1 %bb.2
+
+ bb.1:
+ successors: %bb.4(0x30000000), %bb.3(0x50000000)
+
+ DBG_VALUE %3, $noreg, !6, !DIExpression(), debug-location !10
+ TEST32rr %3, %3, implicit-def $eflags
+ JCC_1 %bb.4, 4, implicit $eflags
+ JMP_1 %bb.3
+
+ bb.2:
+ successors: %bb.1(0x04000000), %bb.2(0x7c000000)
+
+ %6:gr32 = XOR32rr %6, %0, implicit-def dead $eflags
+ %6:gr32 = SAR32ri %6, 2, implicit-def dead $eflags
+ %6:gr32 = XOR32rr %6, %4, implicit-def dead $eflags
+ %6:gr32 = XOR32rr %6, %5, implicit-def dead $eflags
+ %6:gr32 = XOR32rr %6, %2, implicit-def dead $eflags
+ TEST8ri %1, 1, implicit-def $eflags
+ JCC_1 %bb.1, 5, implicit $eflags
+ JMP_1 %bb.2
+
+ bb.3:
+ successors: %bb.4(0x80000000)
+
+ MOV32mi $noreg, 1, $noreg, 4, $noreg, 0 :: (store (s32) into `ptr null` + 4)
+ MOV32mi $noreg, 1, $noreg, 0, $noreg, 0 :: (store (s32) into `ptr null`)
+
+ bb.4:
+ RET 0
+
+...
More information about the llvm-commits
mailing list