Index: include/llvm/CodeGen/MachineInstr.h =================================================================== --- include/llvm/CodeGen/MachineInstr.h +++ include/llvm/CodeGen/MachineInstr.h @@ -1544,6 +1544,9 @@ /// Scan instructions following MI and collect any matching DBG_VALUEs. void collectDebugValues(SmallVectorImpl &DbgValues); + /// Update any matching DBG_VALUEs with the given register. + void updateDebugValues(unsigned Reg); + private: /// If this instruction is embedded into a MachineFunction, return the /// MachineRegisterInfo object for the current function, otherwise Index: lib/CodeGen/MachineCSE.cpp =================================================================== --- lib/CodeGen/MachineCSE.cpp +++ lib/CodeGen/MachineCSE.cpp @@ -181,12 +181,8 @@ LLVM_DEBUG(dbgs() << "Coalescing: " << *DefMI); LLVM_DEBUG(dbgs() << "*** to: " << *MI); - // Collect matching debug values. - SmallVector DbgValues; - DefMI->collectDebugValues(DbgValues); - // Propagate SrcReg to debug value instructions. - for (auto *DBI : DbgValues) - DBI->getOperand(0).setReg(SrcReg); + // Update matching debug values. + DefMI->updateDebugValues(SrcReg); // Propagate SrcReg of copies to MI. MO.setReg(SrcReg); Index: lib/CodeGen/MachineCopyPropagation.cpp =================================================================== --- lib/CodeGen/MachineCopyPropagation.cpp +++ lib/CodeGen/MachineCopyPropagation.cpp @@ -602,6 +602,11 @@ LLVM_DEBUG(dbgs() << "MCP: Removing copy due to no live-out succ: "; MaybeDead->dump()); assert(!MRI->isReserved(MaybeDead->getOperand(0).getReg())); + + // Update matching debug values. + assert(MaybeDead->isCopy()); + MaybeDead->updateDebugValues(MaybeDead->getOperand(1).getReg()); + MaybeDead->eraseFromParent(); Changed = true; ++NumDeletes; Index: lib/CodeGen/MachineInstr.cpp =================================================================== --- lib/CodeGen/MachineInstr.cpp +++ lib/CodeGen/MachineInstr.cpp @@ -2092,3 +2092,13 @@ DbgValues.push_back(&*DI); } } + +void MachineInstr::updateDebugValues(unsigned Reg) { + // Collect matching debug values. + SmallVector DbgValues; + collectDebugValues(DbgValues); + + // Propagate Reg to debug value instructions. + for (auto *DBI : DbgValues) + DBI->getOperand(0).setReg(Reg); +} Index: test/CodeGen/MIR/X86/pr38773.mir =================================================================== --- test/CodeGen/MIR/X86/pr38773.mir +++ test/CodeGen/MIR/X86/pr38773.mir @@ -0,0 +1,159 @@ +# RUN: llc -o - %s -mtriple=x86_64-- -run-pass=machine-cp | FileCheck %s + +# When MachineCopyPropagation eliminates a dead 'copy', its associated debug +# information becomes invalid (as the recorded register has been removed). +# It causes the debugger to display wrong variable value. +# +# When in the debugger, on the line "return read1;", the value of "read1" +# is reported as '4', where it should be '1'. +# +# MIR generated with: +# clang -S -g -O2 -emit-llvm pr38773.cpp -o pr38773.ll -mllvm +# llc pr38773.ll -stop-after=tailduplication -simplify-mir +# +# // pr38773.cpp +# int main() { +# volatile int foo = 4; +# int read1 = foo; +# int read2 = foo; +# +# switch ((read1 == 4) ? 3 : 1) { +# case 1: +# read1 *= read2; +# break; +# case 3: +# read1 /= read2; +# break; +# } +# +# return read1; +# } +# +# Update the register for the '@llvm.dbg.value' associated with 'read1', when +# the 'copy' is removed, to be the 'source' register. + +--- | + ; ModuleID = 'pr38773.ll' + source_filename = "pr38773.cpp" + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-pc-linux-gnu" + + ; Function Attrs: norecurse nounwind uwtable + define dso_local i32 @main() local_unnamed_addr #0 !dbg !7 { + entry: + %foo = alloca i32, align 4 + %foo.0.foo.0..sroa_cast = bitcast i32* %foo to i8*, !dbg !16 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %foo.0.foo.0..sroa_cast), !dbg !16 + call void @llvm.dbg.declare(metadata i32* %foo, metadata !12, metadata !DIExpression()), !dbg !17 + store volatile i32 4, i32* %foo, align 4, !dbg !17, !tbaa !18 + %foo.0.foo.0. = load volatile i32, i32* %foo, align 4, !dbg !22, !tbaa !18 + call void @llvm.dbg.value(metadata i32 %foo.0.foo.0., metadata !14, metadata !DIExpression()), !dbg !23 + %foo.0.foo.0.6 = load volatile i32, i32* %foo, align 4, !dbg !24, !tbaa !18 + call void @llvm.dbg.value(metadata i32 %foo.0.foo.0.6, metadata !15, metadata !DIExpression()), !dbg !25 + %cmp = icmp eq i32 %foo.0.foo.0., 4, !dbg !26 + br i1 %cmp, label %sw.bb1, label %sw.bb, !dbg !27 + + sw.bb: ; preds = %entry + %mul = mul nsw i32 %foo.0.foo.0.6, %foo.0.foo.0., !dbg !28 + call void @llvm.dbg.value(metadata i32 %mul, metadata !14, metadata !DIExpression()), !dbg !23 + br label %sw.epilog, !dbg !30 + + sw.bb1: ; preds = %entry + %div = sdiv i32 4, %foo.0.foo.0.6, !dbg !31 + call void @llvm.dbg.value(metadata i32 %div, metadata !14, metadata !DIExpression()), !dbg !23 + br label %sw.epilog, !dbg !32 + + sw.epilog: ; preds = %sw.bb1, %sw.bb + %read1.0 = phi i32 [ %div, %sw.bb1 ], [ %mul, %sw.bb ], !dbg !33 + call void @llvm.dbg.value(metadata i32 %read1.0, metadata !14, metadata !DIExpression()), !dbg !23 + %0 = bitcast i32* %foo to i8*, !dbg !16 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %0), !dbg !34 + ret i32 %read1.0, !dbg !35 + } + + declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1 + declare void @llvm.dbg.declare(metadata, metadata, metadata) #2 + declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1 + declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + declare void @llvm.stackprotector(i8*, i8**) #3 + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3, !4, !5} + !llvm.ident = !{!6} + + !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 8.0.0 (trunk 343183)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) + !1 = !DIFile(filename: "pr38773.cpp", directory: ".") + !2 = !{} + !3 = !{i32 2, !"Dwarf Version", i32 4} + !4 = !{i32 2, !"Debug Info Version", i32 3} + !5 = !{i32 1, !"wchar_size", i32 4} + !6 = !{!"clang version 8.0.0 (trunk 343183)"} + !7 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !11) + !8 = !DISubroutineType(types: !9) + !9 = !{!10} + !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !11 = !{!12, !14, !15} + !12 = !DILocalVariable(name: "foo", scope: !7, file: !1, line: 2, type: !13) + !13 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !10) + !14 = !DILocalVariable(name: "read1", scope: !7, file: !1, line: 3, type: !10) + !15 = !DILocalVariable(name: "read2", scope: !7, file: !1, line: 4, type: !10) + !16 = !DILocation(line: 2, column: 3, scope: !7) + !17 = !DILocation(line: 2, column: 16, scope: !7) + !18 = !{!19, !19, i64 0} + !19 = !{!"int", !20, i64 0} + !20 = !{!"omnipotent char", !21, i64 0} + !21 = !{!"Simple C++ TBAA"} + !22 = !DILocation(line: 3, column: 15, scope: !7) + !23 = !DILocation(line: 3, column: 7, scope: !7) + !24 = !DILocation(line: 4, column: 15, scope: !7) + !25 = !DILocation(line: 4, column: 7, scope: !7) + !26 = !DILocation(line: 6, column: 18, scope: !7) + !27 = !DILocation(line: 6, column: 3, scope: !7) + !28 = !DILocation(line: 8, column: 11, scope: !29) + !29 = distinct !DILexicalBlock(scope: !7, file: !1, line: 6, column: 33) + !30 = !DILocation(line: 9, column: 5, scope: !29) + !31 = !DILocation(line: 11, column: 11, scope: !29) + !32 = !DILocation(line: 12, column: 5, scope: !29) + !33 = !DILocation(line: 0, scope: !29) + !34 = !DILocation(line: 16, column: 1, scope: !7) + !35 = !DILocation(line: 15, column: 3, scope: !7) + +... +--- +name: main + +body: | + bb.0.entry: + MOV32mi $rsp, 1, $noreg, -4, $noreg, 4, debug-location !17 :: (volatile store 4 into %ir.foo, !tbaa !18) + renamable $eax = MOV32rm $rsp, 1, $noreg, -4, $noreg, debug-location !22 :: (volatile dereferenceable load 4 from %ir.foo, !tbaa !18) + DBG_VALUE debug-use $eax, debug-use $noreg, !14, !DIExpression(), debug-location !23 + renamable $ecx = MOV32rm $rsp, 1, $noreg, -4, $noreg, debug-location !24 :: (volatile dereferenceable load 4 from %ir.foo, !tbaa !18) + DBG_VALUE debug-use $ecx, debug-use $noreg, !15, !DIExpression(), debug-location !25 + CMP32ri8 renamable $eax, 4, implicit-def $eflags, debug-location !26 + JE_1 %bb.2, implicit killed $eflags, debug-location !27 + + bb.1.sw.bb: + liveins: $eax, $ecx + + renamable $ecx = nsw IMUL32rr killed renamable $ecx, killed renamable $eax, implicit-def dead $eflags, debug-location !28 + DBG_VALUE debug-use $ecx, debug-use $noreg, !14, !DIExpression(), debug-location !23 + DBG_VALUE debug-use $ecx, debug-use $noreg, !14, !DIExpression(), debug-location !23 + $eax = COPY killed renamable $ecx, debug-location !35 + RET 0, $eax, debug-location !35 + + bb.2.sw.bb1: + liveins: $ecx + + $eax = MOV32ri 4, debug-location !31 + $edx = MOV32r0 implicit-def dead $eflags, debug-location !31 + IDIV32r killed renamable $ecx, implicit-def $eax, implicit-def dead $edx, implicit-def dead $eflags, implicit $eax, implicit killed $edx, debug-location !31 + renamable $ecx = COPY $eax, debug-location !31 + ; CHECK: IDIV32r killed renamable $ecx + ; CHECK-NEXT: DBG_VALUE debug-use $eax, debug-use $noreg, !14, !DIExpression(), debug-location !23 + ; CHECK-NEXT: DBG_VALUE debug-use $eax, debug-use $noreg, !14, !DIExpression(), debug-location !23 + DBG_VALUE debug-use $ecx, debug-use $noreg, !14, !DIExpression(), debug-location !23 + DBG_VALUE debug-use $ecx, debug-use $noreg, !14, !DIExpression(), debug-location !23 + $eax = COPY killed renamable $ecx, debug-location !35 + RET 0, $eax, debug-location !35 + +...