[llvm] [SelectionDAG] Salvage debuginfo when combining load and z|s ext instrs. (PR #188544)
Shubham Sandeep Rastogi via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 31 03:04:27 PDT 2026
https://github.com/rastogishubham updated https://github.com/llvm/llvm-project/pull/188544
>From 9eaa9be7174a0ace68dcc9942333c9c1c7cb6098 Mon Sep 17 00:00:00 2001
From: Shubham Sandeep Rastogi <Shubham.Rastogi at sony.com>
Date: Tue, 17 Mar 2026 11:27:31 -0700
Subject: [PATCH 1/2] Reland 2b958b9ee24b8ea36dcc777b2d1bcfb66c4972b6
Salvage debuginfo when combining load and z|s ext instrs.
SelectionDAG uses the DAGCombiner to fold a load followed by a sext to a
load and sext instruction. For example, in x86 we will see that
```
%1 = load i32, ptr @GlobArr
#dbg_value(i32 %1, !43, !DIExpression(), !52)
%2 = sext i32 %1 to i64, !dbg !53
```
is converted to:
```
%0:gr64_nosp = MOVSX64rm32 $rip, 1, $noreg, @GlobArr, $noreg, debug-instr-number 1, debug-location !51
DBG_VALUE $noreg, $noreg, !"Idx", !DIExpression(), debug-location !52
```
The `DBG_VALUE` needs to be transferred correctly to the new combined
instruction, and it needs to be appended with a `DIExpression` which
contains a `DW_OP_LLVM_fragment`, describing that the lower bits of the
virtual register contain the value.
This patch fixes the above described problem.
The patch also accounts for multiple DW_OP_LLVM_arg's in a DIExpression
which had caused it to break tests on the sanitizer-x86_64-linux bot but
has now been fixed, with an added testcase called
selectionDAG-load-zext-multiple-args.ll which was reduced from the
broken test itself.
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 72 ++++++++++++++++++-
.../X86/selectionDAG-load-sext-trunc.ll | 70 ++++++++++++++++++
.../DebugInfo/X86/selectionDAG-load-sext.ll | 61 ++++++++++++++++
.../selectionDAG-load-zext-multiple-args.ll | 48 +++++++++++++
4 files changed, 248 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/DebugInfo/X86/selectionDAG-load-sext-trunc.ll
create mode 100644 llvm/test/DebugInfo/X86/selectionDAG-load-sext.ll
create mode 100644 llvm/test/DebugInfo/X86/selectionDAG-load-zext-multiple-args.ll
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 82f8fd572bf19..3d350bb107402 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -52,6 +52,7 @@
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Metadata.h"
@@ -79,6 +80,7 @@
#include <variant>
#include "MatchContext.h"
+#include "SDNodeDbgValue.h"
using namespace llvm;
using namespace llvm::SDPatternMatch;
@@ -14799,6 +14801,9 @@ static SDValue tryToFoldExtOfLoad(SelectionDAG &DAG, DAGCombiner &Combiner,
ISD::LoadExtType ExtLoadType,
ISD::NodeType ExtOpc,
bool NonNegZExt = false) {
+ unsigned Opcode_N = N->getOpcode();
+ bool IsSigned = Opcode_N == ISD::SIGN_EXTEND;
+
bool Frozen = N0.getOpcode() == ISD::FREEZE;
SDValue Freeze = Frozen ? N0 : SDValue();
auto *Load = dyn_cast<LoadSDNode>(Frozen ? N0.getOperand(0) : N0);
@@ -14842,8 +14847,60 @@ static SDValue tryToFoldExtOfLoad(SelectionDAG &DAG, DAGCombiner &Combiner,
return {};
SDLoc DL(Load);
- // If the load value is used only by N, replace it via CombineTo N.
- bool NoReplaceTrunc = N0.hasOneUse();
+
+ auto SalvageDbgValue = [&](SDDbgValue *Dbg, SDValue From, SDValue To,
+ const DIExpression *NewExpr) {
+ SmallVector<SDDbgOperand> Locs = Dbg->copyLocationOps();
+ bool Changed = false;
+
+ for (SDDbgOperand &Op : Locs) {
+ if (Op.getKind() != SDDbgOperand::SDNODE)
+ continue;
+
+ if (Op.getSDNode() == From.getNode() &&
+ Op.getResNo() == From.getResNo()) {
+ Op = SDDbgOperand::fromNode(To.getNode(), To.getResNo());
+ Changed = true;
+ }
+ }
+
+ if (!Changed)
+ return;
+
+ SDDbgValue *NewDV = DAG.getDbgValueList(
+ Dbg->getVariable(), const_cast<DIExpression *>(NewExpr), Locs,
+ Dbg->getAdditionalDependencies(), Dbg->isIndirect(), Dbg->getDebugLoc(),
+ Dbg->getOrder(), Dbg->isVariadic());
+
+ Dbg->setIsInvalidated();
+ Dbg->setIsEmitted();
+ DAG.AddDbgValue(NewDV, /*isParameter=*/false);
+ };
+
+ // Because we are replacing a load and a s|z ext with a load-s|z ext
+ // instruction, the dbg_value attached to the load will be of a smaller bit
+ // width, and we have to add a DW_OP_LLVM_convert expression to get the
+ // correct size.
+ auto SalvageToOldLoadSize = [&](SDValue From, SDValue To, bool IsSigned) {
+ SmallVector<SDDbgValue *, 4> DbgVals(
+ DAG.GetDbgValues(From.getNode()).begin(),
+ DAG.GetDbgValues(From.getNode()).end());
+
+ unsigned VarBitsFrom = From.getValueSizeInBits();
+ unsigned VarBitsTo = To.getValueSizeInBits();
+
+ for (SDDbgValue *Dbg : DbgVals) {
+ if (Dbg->isInvalidated())
+ continue;
+
+ const DIExpression *OldE = Dbg->getExpression();
+ const DIExpression *NewE =
+ DIExpression::appendExt(OldE, VarBitsFrom, VarBitsTo, IsSigned);
+
+ SalvageDbgValue(Dbg, From, To, NewE);
+ }
+ };
+
SDValue ExtLoad =
DAG.getExtLoad(ExtLoadType, DL, VT, Load->getChain(), Load->getBasePtr(),
Load->getValueType(0), Load->getMemOperand());
@@ -14856,8 +14913,16 @@ static SDValue tryToFoldExtOfLoad(SelectionDAG &DAG, DAGCombiner &Combiner,
DAG.getValueType(Load->getValueType(0).getScalarType()));
}
Combiner.ExtendSetCCUses(SetCCs, N0, Res, ExtOpc);
- Combiner.CombineTo(N, Res);
+ // If the load value is used only by N, replace it via CombineTo N.
+ SDValue OldLoadVal(Load, 0);
+ SDValue OldExtValue(N, 0);
+ bool NoReplaceTrunc = N0.hasOneUse();
if (NoReplaceTrunc) {
+ if (Load->getHasDebugValue())
+ SalvageToOldLoadSize(OldLoadVal, ExtLoad, IsSigned);
+
+ if (N->getHasDebugValue())
+ DAG.transferDbgValues(OldExtValue, ExtLoad);
DAG.ReplaceAllUsesOfValueWith(SDValue(Load, 1), ExtLoad.getValue(1));
Combiner.recursivelyDeleteUnusedNodes(N0.getNode());
} else {
@@ -14869,6 +14934,7 @@ static SDValue tryToFoldExtOfLoad(SelectionDAG &DAG, DAGCombiner &Combiner,
Combiner.CombineTo(Load, Trunc, ExtLoad.getValue(1));
}
}
+ Combiner.CombineTo(N, Res);
return SDValue(N, 0); // Return N so it doesn't get rechecked!
}
diff --git a/llvm/test/DebugInfo/X86/selectionDAG-load-sext-trunc.ll b/llvm/test/DebugInfo/X86/selectionDAG-load-sext-trunc.ll
new file mode 100644
index 0000000000000..46afb9c598a74
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/selectionDAG-load-sext-trunc.ll
@@ -0,0 +1,70 @@
+; This test checks that after SelectionDAG runs, it preserves the debug info that is lost due to the DAGCombiner combining a load and a sext instruction, where the #dbg_value is pointing to the result of the load.
+; However, in this case, the load has multiple uses.
+
+; RUN: llc %s -mtriple=x86_64-unkown-linux -start-before=x86-isel -stop-after=x86-isel -o - | FileCheck %s --check-prefix=MIR
+; RUN: llc -O2 %s -start-before=x86-isel -mtriple=x86_64-unkown-linux --filetype=obj -o %t.o
+; RUN: llvm-dwarfdump %t.o --name Idx | FileCheck %s --check-prefix=DUMP
+; RUN: llvm-dwarfdump %t.o --name Idx2 | FileCheck %s --check-prefix=DUMP2
+
+; MIR: ![[IDX:[0-9]+]] = !DILocalVariable(name: "Idx"
+; MIR: ![[IDX2:[0-9]+]] = !DILocalVariable(name: "Idx2"
+; MIR: name: _Z8useValuei
+; MIR: name: main
+; MIR: debugValueSubstitutions
+; MIR-NEXT: - { srcinst: [[INSTR_NUM2:[0-9]+]], srcop: 0, dstinst: [[INSTR_NUM:[0-9]+]], dstop: 0, subreg: 6 }
+; MIR-LABEL: bb.0 (%ir-block.0)
+; MIR: %{{[0-9a-f]+}}{{.*}} = MOVSX64rm32 ${{.*}}, 1, $noreg, @GlobArr, $noreg, debug-instr-number [[INSTR_NUM]]
+; MIR-NEXT: {{.*}} = COPY %0.sub_32bit
+; MIR-NEXT DBG_INSTR_REF ![[IDX]], !DIExpression(DW_OP_LLVM_arg, 0), dbg-instr-ref([[INSTR_NUM2]], 0)
+; MIR-NEXT DBG_INSTR_REF ![[IDX2]], !DIExpression(DW_OP_LLVM_arg, 0), dbg-instr-ref([[INSTR_NUM]], 0)
+
+; DUMP: DW_AT_location (indexed ({{[0-9a-f]+}}x{{[0-9a-f]+}}) loclist = 0x{{[0-9a-f]+}}:
+; DUMP-NEXT: [0x{{[0-9a-f]+}}, 0x{{[0-9a-f]+}}): DW_OP_reg3 RBX)
+
+; DUMP2: DW_AT_location (indexed ({{[0-9a-f]+}}x{{[0-9a-f]+}}) loclist = 0x{{[0-9a-f]+}}:
+; DUMP2-NEXT: [0x{{[0-9a-f]+}}, 0x{{[0-9a-f]+}}): DW_OP_reg3 RBX)
+
+
+
+ @GlobArr = dso_local local_unnamed_addr global [5 x i32] [i32 1, i32 1, i32 2, i32 3, i32 5], align 16, !dbg !0
+ @__const.main.Data = private unnamed_addr constant [7 x i32] [i32 10, i32 20, i32 30, i32 40, i32 50, i32 60, i32 70], align 16
+ define dso_local void @_Z8useValuei(i32 noundef %0) local_unnamed_addr #0 !dbg !22 {
+ ret void, !dbg !28
+ }
+ define dso_local noundef i32 @main() local_unnamed_addr #1 !dbg !29 {
+ %1 = load i32, ptr @GlobArr
+ #dbg_value(i32 %1, !43, !DIExpression(), !52)
+ %2 = sext i32 %1 to i64
+ #dbg_value(i64 %2, !57, !DIExpression(), !52)
+ tail call void @_Z8useValuei(i32 noundef %1), !dbg !56
+ %3 = getelementptr inbounds i32, ptr @__const.main.Data, i64 %2
+ %4 = load i32, ptr %3
+ tail call void @_Z8useValuei(i32 noundef %4), !dbg !56
+ ret i32 0
+ }
+ !llvm.dbg.cu = !{!2}
+ !llvm.module.flags = !{!10, !11, !16}
+ !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+ !1 = distinct !DIGlobalVariable(type: !6, isDefinition: true)
+ !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, emissionKind: FullDebug, nameTableKind: None)
+ !3 = !DIFile(filename: "/tmp/test.cpp", directory: "/Users/srastogi/Development/llvm-project/build_ninja", checksumkind: CSK_MD5, checksum: "0fe735937e606b4db3e3b2e9253eff90")
+ !6 = !DICompositeType(tag: DW_TAG_array_type, elements: !8)
+ !7 = !DIBasicType()
+ !8 = !{}
+ !10 = !{i32 7, !"Dwarf Version", i32 5}
+ !11 = !{i32 2, !"Debug Info Version", i32 3}
+ !16 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
+ !22 = distinct !DISubprogram(type: !23, unit: !2, keyInstructions: true)
+ !23 = !DISubroutineType(types: !24)
+ !24 = !{}
+ !28 = !DILocation(scope: !22, atomRank: 1)
+ !29 = distinct !DISubprogram(type: !30, unit: !2, keyInstructions: true)
+ !30 = !DISubroutineType(types: !31)
+ !31 = !{}
+ !38 = distinct !DILexicalBlock(scope: !29, line: 5, column: 3)
+ !43 = !DILocalVariable(name: "Idx", scope: !44, type: !7)
+ !44 = distinct !DILexicalBlock(scope: !38, line: 5, column: 3)
+ !46 = distinct !DILexicalBlock(scope: !44, line: 5, column: 27)
+ !52 = !DILocation(scope: !44)
+ !56 = !DILocation(scope: !46)
+ !57 = !DILocalVariable(name: "Idx2", scope: !44, type: !7)
diff --git a/llvm/test/DebugInfo/X86/selectionDAG-load-sext.ll b/llvm/test/DebugInfo/X86/selectionDAG-load-sext.ll
new file mode 100644
index 0000000000000..7e61780a6ab13
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/selectionDAG-load-sext.ll
@@ -0,0 +1,61 @@
+; This test checks that after SelectionDAG runs, it preserves the debug info that is lost due to the DAGCombiner combining a load and a sext instruction, where the #dbg_value is pointing to the result of the load.
+; RUN: llc %s -mtriple=x86_64-unkown-linux -start-before=x86-isel -stop-after=x86-isel -o - | FileCheck %s --check-prefix=MIR
+; RUN: llc -O2 %s -start-before=x86-isel -mtriple=x86_64-unkown-linux --filetype=obj -o %t.o
+; RUN: llvm-dwarfdump %t.o --name Idx | FileCheck %s --check-prefix=DUMP
+; RUN: llvm-dwarfdump %t.o --name Idx2 | FileCheck %s --check-prefix=DUMP2
+
+; MIR: ![[IDX:[0-9]+]] = !DILocalVariable(name: "Idx"
+; MIR: ![[IDX2:[0-9]+]] = !DILocalVariable(name: "Idx2"
+; MIR-LABEL: bb.0
+; MIR: %{{[0-9a-f]+}}{{.*}} = MOVSX64rm32 ${{.*}}, 1, $noreg, @GlobArr, $noreg, debug-instr-number [[INSTR_NUM:[0-9]+]]
+; MIR-NEXT: DBG_INSTR_REF ![[IDX]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_LLVM_convert, 64, DW_ATE_signed, DW_OP_stack_value), dbg-instr-ref([[INSTR_NUM]], 0)
+; MIR-NEXT: DBG_INSTR_REF ![[IDX2]], !DIExpression(DW_OP_LLVM_arg, 0), dbg-instr-ref([[INSTR_NUM]], 0)
+
+; DUMP: DW_AT_location (indexed ({{[0-9a-f]+}}x{{[0-9a-f]+}}) loclist = 0x{{[0-9a-f]+}}:
+; DUMP-NEXT: [0x{{[0-9a-f]+}}, 0x{{[0-9a-f]+}}): DW_OP_breg0 RAX+0, DW_OP_convert (0x{{[0-9a-f]+}}) "DW_ATE_signed_32", DW_OP_convert (0x{{[0-9a-f]+}}) "DW_ATE_signed_64", DW_OP_stack_value)
+
+; DUMP2: DW_AT_location (indexed ({{[0-9a-f]+}}x{{[0-9a-f]+}}) loclist = 0x{{[0-9a-f]+}}:
+; DUMP2-NEXT: [0x{{[0-9a-f]+}}, 0x{{[0-9a-f]+}}): DW_OP_reg0 RAX)
+
+
+ @GlobArr = dso_local local_unnamed_addr global [5 x i32] [i32 1, i32 1, i32 2, i32 3, i32 5], align 16, !dbg !0
+ @__const.main.Data = private unnamed_addr constant [7 x i32] [i32 10, i32 20, i32 30, i32 40, i32 50, i32 60, i32 70], align 16
+ define dso_local void @_Z8useValuei(i32 noundef %0) local_unnamed_addr #0 !dbg !22 {
+ ret void, !dbg !28
+ }
+ define dso_local noundef i32 @main() local_unnamed_addr #1 !dbg !29 {
+ %1 = load i32, ptr @GlobArr
+ #dbg_value(i32 %1, !43, !DIExpression(), !52)
+ %2 = sext i32 %1 to i64
+ #dbg_value(i64 %2, !57, !DIExpression(), !52)
+ %3 = getelementptr inbounds i32, ptr @__const.main.Data, i64 %2
+ %4 = load i32, ptr %3
+ tail call void @_Z8useValuei(i32 noundef %4), !dbg !56
+ ret i32 0
+ }
+ !llvm.dbg.cu = !{!2}
+ !llvm.module.flags = !{!10, !11, !16}
+ !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+ !1 = distinct !DIGlobalVariable(type: !6, isDefinition: true)
+ !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, emissionKind: FullDebug, nameTableKind: None)
+ !3 = !DIFile(filename: "/tmp/test.cpp", directory: "/Users/srastogi/Development/llvm-project/build_ninja", checksumkind: CSK_MD5, checksum: "0fe735937e606b4db3e3b2e9253eff90")
+ !6 = !DICompositeType(tag: DW_TAG_array_type, elements: !8)
+ !7 = !DIBasicType()
+ !8 = !{}
+ !10 = !{i32 7, !"Dwarf Version", i32 5}
+ !11 = !{i32 2, !"Debug Info Version", i32 3}
+ !16 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
+ !22 = distinct !DISubprogram(type: !23, unit: !2, keyInstructions: true)
+ !23 = !DISubroutineType(types: !24)
+ !24 = !{}
+ !28 = !DILocation(scope: !22, atomRank: 1)
+ !29 = distinct !DISubprogram(type: !30, unit: !2, keyInstructions: true)
+ !30 = !DISubroutineType(types: !31)
+ !31 = !{}
+ !38 = distinct !DILexicalBlock(scope: !29, line: 5, column: 3)
+ !43 = !DILocalVariable(name: "Idx", scope: !44, type: !7)
+ !44 = distinct !DILexicalBlock(scope: !38, line: 5, column: 3)
+ !46 = distinct !DILexicalBlock(scope: !44, line: 5, column: 27)
+ !52 = !DILocation(scope: !44)
+ !56 = !DILocation(scope: !46)
+ !57 = !DILocalVariable(name: "Idx2", scope: !44, type: !7)
diff --git a/llvm/test/DebugInfo/X86/selectionDAG-load-zext-multiple-args.ll b/llvm/test/DebugInfo/X86/selectionDAG-load-zext-multiple-args.ll
new file mode 100644
index 0000000000000..235fc34d36dcb
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/selectionDAG-load-zext-multiple-args.ll
@@ -0,0 +1,48 @@
+; This test checks that after SelectionDAG runs, it preserves the debug info that is lost due to the DAGCombiner combining a load and a zext instruction, where the #dbg_value is pointing to the result of the load. However, this test also ensures that the DIExpression, which has multiple DW_OP_LLVM_arg's is handled correctly when the debug info is preserved in selectioDAG.
+; RUN: llc %s -mtriple=x86_64-unkown-linux-gnu -start-before=x86-isel -stop-after=x86-isel -o - | FileCheck %s --check-prefix=MIR
+; RUN: llc -O2 %s -start-before=x86-isel -mtriple=x86_64-unkown-linux --filetype=obj -o %t.o
+
+; MIR: ![[V:[0-9]+]] = !DILocalVariable(name: "v"
+; MIR-LABEL: bb.0
+; MIR: %{{[0-9a-f]+}}{{.*}} = MOVZX32rm8 {{.*}}, 1, $noreg, 0, $noreg, debug-instr-number [[INSTR_NUM:[0-9]+]]
+; MIR-NEXT: DBG_INSTR_REF ![[V]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_constu, 45, DW_OP_eq, DW_OP_LLVM_arg, 1, DW_OP_constu, 114, DW_OP_eq, DW_OP_or, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_stack_value), dbg-instr-ref([[INSTR_NUM]], 0), dbg-instr-ref([[INSTR_NUM]], 0)
+
+ @.str = private unnamed_addr constant [105 x i8] c"/Users/srastogi/Development/llvm-project-2/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cpp\00"
+ @.str.1 = private unnamed_addr constant [45 x i8] c"((IsOneOf(*data_.current, '-', 'r'))) != (0)\00"
+ define hidden noundef zeroext i1 @_ZN11__sanitizer19MemoryMappingLayout4NextEPNS_19MemoryMappedSegmentE(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(32) %this, ptr noundef readonly captures(none) %segment) unnamed_addr #0 align 2 !dbg !64 {
+ %current = getelementptr inbounds nuw i8, ptr %this, i64 24
+ %3 = load ptr, ptr %current, !dbg !95
+ %4 = load i8, ptr %3
+ #dbg_value(!DIArgList(i8 %4, i8 %4), !71, !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_constu, 45, DW_OP_eq, DW_OP_LLVM_arg, 1, DW_OP_constu, 114, DW_OP_eq, DW_OP_or, DW_OP_stack_value), !98)
+ %5 = zext i8 %4 to i32
+ switch i32 %5, label %if.then [
+ i32 114, label %if.end
+ i32 45, label %if.end
+ ]
+ if.then: ; preds = %entry
+ tail call void @_ZN11__sanitizer11CheckFailedEPKciS1_yy(ptr noundef nonnull @.str, i32 noundef 45, ptr noundef nonnull @.str.1, i64 noundef 0, i64 noundef 0) #5
+ unreachable
+ if.end: ; preds = %entry, %entry
+ ret i1 true
+ }
+ declare void @_ZN11__sanitizer11CheckFailedEPKciS1_yy(ptr noundef, i32 noundef, ptr noundef, i64 noundef, i64 noundef) local_unnamed_addr #2
+ !llvm.dbg.cu = !{!15}
+ !llvm.module.flags = !{!55, !58}
+ !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+ !1 = distinct !DIGlobalVariable()
+ !2 = !DIFile(filename: "san.pp.cpp", directory: "/Users/srastogi/Development/Delta", checksumkind: CSK_MD5, checksum: "386698ddde6c66899ec76581efaeabe2")
+ !15 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !16, emissionKind: FullDebug, nameTableKind: None)
+ !16 = !DIFile(filename: "/Users/srastogi/Development/Delta/san.pp.cpp", directory: "/Users/srastogi/Development/Delta", checksumkind: CSK_MD5, checksum: "386698ddde6c66899ec76581efaeabe2")
+ !19 = !DIDerivedType(tag: DW_TAG_typedef,baseType: !21)
+ !21 = !DIBasicType()
+ !22 = !DIDerivedType(tag: DW_TAG_typedef, baseType: !23)
+ !23 = !DIBasicType()
+ !46 = !DISubroutineType(types: !47)
+ !47 = !{}
+ !55 = !{i32 2, !"Debug Info Version", i32 3}
+ !58 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
+ !64 = distinct !DISubprogram( type: !46, unit: !15, keyInstructions: true)
+ !71 = !DILocalVariable(name: "v", scope: !72, type: !19)
+ !72 = distinct !DILexicalBlock(scope: !64, line: 187, column: 6)
+ !95 = !DILocation( scope: !72)
+ !98 = !DILocation(scope: !72)
>From 70fdd9963a52cec80e0976805a8357bd28dfaa17 Mon Sep 17 00:00:00 2001
From: Shubham Sandeep Rastogi <Shubham.Rastogi at sony.com>
Date: Mon, 30 Mar 2026 18:15:38 -0700
Subject: [PATCH 2/2] Address review feedback
1. Sunk
```
unsigned Opcode_N = N->getOpcode();
bool IsSigned = Opcode_N == ISD::SIGN_EXTEND;
```
closer to where it is used
2. Ensured that every DW_OP_LLVM_arg that has it's argument been changed
gets a convert expression.
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 39 ++++++++++++++-----
.../CodeGen/ARM/2011-01-19-MergedGlobalDbg.o | 0
.../selectionDAG-load-zext-multiple-args.ll | 2 +-
3 files changed, 31 insertions(+), 10 deletions(-)
create mode 100644 llvm/test/CodeGen/ARM/2011-01-19-MergedGlobalDbg.o
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 3d350bb107402..59ee1c9db3467 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -14801,8 +14801,6 @@ static SDValue tryToFoldExtOfLoad(SelectionDAG &DAG, DAGCombiner &Combiner,
ISD::LoadExtType ExtLoadType,
ISD::NodeType ExtOpc,
bool NonNegZExt = false) {
- unsigned Opcode_N = N->getOpcode();
- bool IsSigned = Opcode_N == ISD::SIGN_EXTEND;
bool Frozen = N0.getOpcode() == ISD::FREEZE;
SDValue Freeze = Frozen ? N0 : SDValue();
@@ -14849,11 +14847,16 @@ static SDValue tryToFoldExtOfLoad(SelectionDAG &DAG, DAGCombiner &Combiner,
SDLoc DL(Load);
auto SalvageDbgValue = [&](SDDbgValue *Dbg, SDValue From, SDValue To,
- const DIExpression *NewExpr) {
+ unsigned FromBits, unsigned ToBits,
+ bool IsSigned) {
SmallVector<SDDbgOperand> Locs = Dbg->copyLocationOps();
bool Changed = false;
- for (SDDbgOperand &Op : Locs) {
+ bool IsVariadic = Dbg->isVariadic();
+ SmallVector<unsigned, 2> AffectedArgs;
+
+ for (unsigned I = 0, E = Locs.size(); I != E; ++I) {
+ SDDbgOperand &Op = Locs[I];
if (Op.getKind() != SDDbgOperand::SDNODE)
continue;
@@ -14861,12 +14864,32 @@ static SDValue tryToFoldExtOfLoad(SelectionDAG &DAG, DAGCombiner &Combiner,
Op.getResNo() == From.getResNo()) {
Op = SDDbgOperand::fromNode(To.getNode(), To.getResNo());
Changed = true;
+
+ if (IsVariadic)
+ AffectedArgs.push_back(I);
}
}
if (!Changed)
return;
+ const DIExpression *OldExpr = Dbg->getExpression();
+ const DIExpression *NewExpr = nullptr;
+
+ if (!IsVariadic) {
+ // Do not introduce DW_OP_LLVM_arg into ordinary single-location
+ // DBG_VALUEs.
+ NewExpr = DIExpression::appendExt(OldExpr, FromBits, ToBits, IsSigned);
+ } else {
+ auto ExtOps = DIExpression::getExtOps(FromBits, ToBits, IsSigned);
+
+ NewExpr = DIExpression::convertToVariadicExpression(OldExpr);
+
+ for (unsigned ArgNo : AffectedArgs)
+ NewExpr = DIExpression::appendOpsToArg(NewExpr, ExtOps, ArgNo,
+ /*StackValue=*/false);
+ }
+
SDDbgValue *NewDV = DAG.getDbgValueList(
Dbg->getVariable(), const_cast<DIExpression *>(NewExpr), Locs,
Dbg->getAdditionalDependencies(), Dbg->isIndirect(), Dbg->getDebugLoc(),
@@ -14893,11 +14916,7 @@ static SDValue tryToFoldExtOfLoad(SelectionDAG &DAG, DAGCombiner &Combiner,
if (Dbg->isInvalidated())
continue;
- const DIExpression *OldE = Dbg->getExpression();
- const DIExpression *NewE =
- DIExpression::appendExt(OldE, VarBitsFrom, VarBitsTo, IsSigned);
-
- SalvageDbgValue(Dbg, From, To, NewE);
+ SalvageDbgValue(Dbg, From, To, VarBitsFrom, VarBitsTo, IsSigned);
}
};
@@ -14914,6 +14933,8 @@ static SDValue tryToFoldExtOfLoad(SelectionDAG &DAG, DAGCombiner &Combiner,
}
Combiner.ExtendSetCCUses(SetCCs, N0, Res, ExtOpc);
// If the load value is used only by N, replace it via CombineTo N.
+ unsigned Opcode_N = N->getOpcode();
+ bool IsSigned = Opcode_N == ISD::SIGN_EXTEND;
SDValue OldLoadVal(Load, 0);
SDValue OldExtValue(N, 0);
bool NoReplaceTrunc = N0.hasOneUse();
diff --git a/llvm/test/CodeGen/ARM/2011-01-19-MergedGlobalDbg.o b/llvm/test/CodeGen/ARM/2011-01-19-MergedGlobalDbg.o
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/llvm/test/DebugInfo/X86/selectionDAG-load-zext-multiple-args.ll b/llvm/test/DebugInfo/X86/selectionDAG-load-zext-multiple-args.ll
index 235fc34d36dcb..334dfbfe8495b 100644
--- a/llvm/test/DebugInfo/X86/selectionDAG-load-zext-multiple-args.ll
+++ b/llvm/test/DebugInfo/X86/selectionDAG-load-zext-multiple-args.ll
@@ -5,7 +5,7 @@
; MIR: ![[V:[0-9]+]] = !DILocalVariable(name: "v"
; MIR-LABEL: bb.0
; MIR: %{{[0-9a-f]+}}{{.*}} = MOVZX32rm8 {{.*}}, 1, $noreg, 0, $noreg, debug-instr-number [[INSTR_NUM:[0-9]+]]
-; MIR-NEXT: DBG_INSTR_REF ![[V]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_constu, 45, DW_OP_eq, DW_OP_LLVM_arg, 1, DW_OP_constu, 114, DW_OP_eq, DW_OP_or, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_stack_value), dbg-instr-ref([[INSTR_NUM]], 0), dbg-instr-ref([[INSTR_NUM]], 0)
+; MIR-NEXT: DBG_INSTR_REF ![[V]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_constu, 45, DW_OP_eq, DW_OP_LLVM_arg, 1, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_constu, 114, DW_OP_eq, DW_OP_or, DW_OP_stack_value), dbg-instr-ref([[INSTR_NUM]], 0), dbg-instr-ref([[INSTR_NUM]], 0)
@.str = private unnamed_addr constant [105 x i8] c"/Users/srastogi/Development/llvm-project-2/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cpp\00"
@.str.1 = private unnamed_addr constant [45 x i8] c"((IsOneOf(*data_.current, '-', 'r'))) != (0)\00"
More information about the llvm-commits
mailing list