Index: llvm/lib/Transforms/Scalar/ADCE.cpp =================================================================== --- llvm/lib/Transforms/Scalar/ADCE.cpp +++ llvm/lib/Transforms/Scalar/ADCE.cpp @@ -29,6 +29,7 @@ #include "llvm/Analysis/PostDominators.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/Dominators.h" @@ -544,6 +545,11 @@ continue; if (auto *DII = dyn_cast(&I)) { + // Avoid removing a dbg.assign that is linked to instructions because it + // holds information about an existing store. + if (auto *DAI = dyn_cast(DII)) + if (!at::getAssignmentInsts(DAI).empty()) + continue; // Check if the scope of this variable location is alive. if (AliveScopes.count(DII->getDebugLoc()->getScope())) continue; Index: llvm/test/DebugInfo/Generic/assignment-tracking/adce/no-delete.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/Generic/assignment-tracking/adce/no-delete.ll @@ -0,0 +1,51 @@ +; RUN: opt %s -passes=adce -experimental-assignment-tracking -S -o - \ +; RUN: | FileCheck %s + +;; $ cat test.c +;; void fun(int local) {} +;; +;; $ clang test.c -g -O1 -Xclang -disable-llvm-passes | opt -S -passes=declare-to-assign + +;; Check that the dbg.assign intrinsics that are considered "out of scope" but still linked +;; to an instruction are not deleted by ADCE. + +; CHECK: llvm.dbg.assign +; CHECK: llvm.dbg.assign + +define dso_local void @fun(i32 noundef %local) #0 !dbg !7 { +entry: + %local.addr = alloca i32, align 4, !DIAssignID !13 + call void @llvm.dbg.assign(metadata i1 undef, metadata !12, metadata !DIExpression(), metadata !13, metadata i32* %local.addr, metadata !DIExpression()), !dbg !14 + store i32 %local, i32* %local.addr, align 4, !tbaa !15, !DIAssignID !19 + call void @llvm.dbg.assign(metadata i32 %local, metadata !12, metadata !DIExpression(), metadata !19, metadata i32* %local.addr, metadata !DIExpression()), !dbg !14 + ret void, !dbg !20 +} + +declare void @llvm.dbg.declare(metadata, metadata, metadata) +declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"uwtable", i32 1} +!6 = !{!"clang version 14.0.0"} +!7 = distinct !DISubprogram(name: "fun", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{null, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "local", arg: 1, scope: !7, file: !1, line: 1, type: !10) +!13 = distinct !DIAssignID() +!14 = !DILocation(line: 0, scope: !7) +!15 = !{!16, !16, i64 0} +!16 = !{!"int", !17, i64 0} +!17 = !{!"omnipotent char", !18, i64 0} +!18 = !{!"Simple C/C++ TBAA"} +!19 = distinct !DIAssignID() +!20 = !DILocation(line: 1, column: 22, scope: !7)