Index: llvm/lib/CodeGen/MachineSink.cpp =================================================================== --- llvm/lib/CodeGen/MachineSink.cpp +++ llvm/lib/CodeGen/MachineSink.cpp @@ -146,6 +146,11 @@ /// blocks. DenseMap SunkDebugDefs; + /// A set of DBG_VALUEs that are going to have a sunk copy created later. + /// These DBG_VALUEs might need to be copy-propagated further, but + /// they should not be sunk out of the same block twice. + SmallPtrSet DbgInstsAlreadySinking; + public: static char ID; // Pass identification @@ -265,6 +270,18 @@ MRI->replaceRegWith(DstReg, SrcReg); MI.eraseFromParent(); + // Debug users pointing at the destination of the copy, should now be + // recorded against its source. + if (SeenDbgUsers.count(DstReg)) { + auto &DbgSrcSeen = SeenDbgUsers[SrcReg]; + auto &DbgDstSeen = SeenDbgUsers[DstReg]; + DbgSrcSeen.insert(DbgSrcSeen.end(), DbgDstSeen.begin(), DbgDstSeen.end()); + } + + // We should never sink something, and _then_ coalesce it. Assert that there + // are no sinking DBG_VALUEs hanging off this copy. + assert(SunkDebugDefs.count(DstReg) == 0); + // Conservatively, clear any kill flags, since it's possible that they are no // longer correct. MRI->clearKillFlags(SrcReg); @@ -472,6 +489,7 @@ SeenDbgUsers.clear(); SeenDbgVars.clear(); + DbgInstsAlreadySinking.clear(); return MadeChange; } @@ -1054,12 +1072,26 @@ auto &Users = SeenDbgUsers[MO.getReg()]; for (auto &User : Users) { MachineInstr *DbgMI = User.getPointer(); - DebugVariable Var(DbgMI->getDebugVariable(), DbgMI->getDebugExpression(), - DbgMI->getDebugLoc()->getInlinedAt()); - // If we can't copy-propagate the original DBG_VALUE, mark it undef, as + + bool AlreadySinking = DbgInstsAlreadySinking.count(DbgMI) != 0; + + // If we can't copy-propagate this DBG_VALUE, mark it undef, as // its operand will not be available. - if (!attemptDebugCopyProp(MI, *DbgMI)) + if (!attemptDebugCopyProp(MI, *DbgMI)) { DbgMI->getOperand(0).setReg(0); + } else { + ProcessDbgInst(*DbgMI); + DbgInstsAlreadySinking.insert(DbgMI); + } + + // If we've already created a "sinking" record for this DBG_VALUE, and + // we get here, then it's being repeatedly copy propagated. Don't create + // any more sinking records. + if (AlreadySinking) + continue; + + DebugVariable Var(DbgMI->getDebugVariable(), DbgMI->getDebugExpression(), + DbgMI->getDebugLoc()->getInlinedAt()); // Debug users that don't pass any other DBG_VALUEs for this variable // can be sunk. Index: llvm/test/DebugInfo/MIR/X86/machinesink.mir =================================================================== --- llvm/test/DebugInfo/MIR/X86/machinesink.mir +++ llvm/test/DebugInfo/MIR/X86/machinesink.mir @@ -12,6 +12,9 @@ # # Test four: if we sink a DBG_VALUE via an intermediate block, no spurious # DBG_VALUE $noreg's should appear along the way. +# +# Test five and six: we should continue to copy-propagate remaining DBG_VALUEs +# once we know they need a sunk DBG_VALUE creating. --- | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" @@ -65,7 +68,26 @@ ret void } - ; Function Attrs: nounwind readnone + define void @test5(i32* nocapture readonly %p) local_unnamed_addr !dbg !401 { + ; Stripped + entry: + br label %nou + nou: + br label %exit + exit: + ret void + } + + define void @test6(i32* nocapture readonly %p) local_unnamed_addr !dbg !501 { + ; Stripped + entry: + br label %nou + nou: + br label %exit + exit: + ret void + } + declare void @llvm.dbg.value(metadata, i64, metadata, metadata) !llvm.dbg.cu = !{!1} @@ -104,11 +126,21 @@ !302 = !{!303} !303 = !DILocalVariable(name: "s", arg: 1, scope: !301, file: !2, line: 2, type: !12) !304 = !DILocation(line: 1, column: 1, scope: !301) + !401 = distinct !DISubprogram(name: "test5", scope: !2, file: !2, line: 2, type: !10, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !1, retainedNodes: !402) + !402 = !{!403} + !403 = !DILocalVariable(name: "t", arg: 1, scope: !401, file: !2, line: 2, type: !12) + !404 = !DILocation(line: 1, column: 1, scope: !401) + !501 = distinct !DISubprogram(name: "test5", scope: !2, file: !2, line: 2, type: !10, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !1, retainedNodes: !502) + !502 = !{!503} + !503 = !DILocalVariable(name: "u", arg: 1, scope: !501, file: !2, line: 2, type: !12) + !504 = !DILocation(line: 1, column: 1, scope: !501) ; CHECK: [[VARNUM:![0-9]+]] = !DILocalVariable(name: "p", ; CHECK: [[VAR2NUM:![0-9]+]] = !DILocalVariable(name: "q", ; CHECK: [[VAR3NUM:![0-9]+]] = !DILocalVariable(name: "r", ; CHECK: [[VAR4NUM:![0-9]+]] = !DILocalVariable(name: "s", + ; CHECK: [[VAR5NUM:![0-9]+]] = !DILocalVariable(name: "t", + ; CHECK: [[VAR6NUM:![0-9]+]] = !DILocalVariable(name: "u", ... --- @@ -341,3 +373,97 @@ $rax = MOV64rr %2 RET 0 ... +--- +name: test5 +tracksRegLiveness: true +liveins: + - { reg: '$rdi', virtual-reg: '%2' } + - { reg: '$rsi', virtual-reg: '%2' } +body: | + bb.0.entry: + successors: %bb.1.nou, %bb.2.exit + liveins: $rdi, $esi + + ; This block has a chain of COPYs that should be sunk out, except the first, + ; which has a use in this block. We know that the DBG_VALUE will sink, + ; but should continue to copy propagate it. + ; CHECK-LABEL: bb.0.entry: + ; CHECK: [[T5ARG0:%[0-9]+]]:gr64 = COPY $rdi + ; CHECK-NEXT: [[T5COPY1:%[0-9]+]]:gr64 = COPY [[T5ARG0]] + ; CHECK-NEXT: CMP64ri8 [[T5COPY1]], 0 + ; CHECK-NEXT: DBG_VALUE [[T5COPY1]], $noreg, [[VAR5NUM]] + ; CHECK-NEXT: JCC_1 %bb.1, 4 + ; CHECK-NEXT: JMP_1 + + %2:gr64 = COPY $rdi + %5:gr64 = COPY %2 + %7:gr64 = COPY %5 + %8:gr64 = COPY %7 + CMP64ri8 %5, 0, implicit-def $eflags + DBG_VALUE %8, $noreg, !403, !17, debug-location !404 + JCC_1 %bb.1.nou, 4, implicit $eflags + JMP_1 %bb.2.exit + + bb.1.nou: + successors: %bb.2.exit + + ; This block should receive the sunk copies and DBG_VALUE + ; CHECK-LABEL: bb.1.nou: + ; CHECK: [[T5COPY2:%[0-9]+]]:gr64 = COPY [[T5COPY1]] + ; CHECK-NEXT: [[T5COPY3:%[0-9]+]]:gr64 = COPY [[T5COPY2]] + ; CHECK-NEXT: DBG_VALUE [[T5COPY3]], $noreg, [[VAR5NUM]] + ; CHECK-NEXT: ADD64ri8 + ; CHECK-NEXT: JMP_1 + %1:gr64 = ADD64ri8 %8, 4, implicit-def dead $eflags + JMP_1 %bb.2.exit + + bb.2.exit: + $rax = MOV64rr %2 + RET 0 +... +--- +name: test6 +tracksRegLiveness: true +liveins: + - { reg: '$rdi', virtual-reg: '%2' } + - { reg: '$rsi', virtual-reg: '%2' } +body: | + bb.0.entry: + successors: %bb.1.nou, %bb.2.exit + liveins: $rdi, $esi + + ; This block has a chain of insts that should be completely sunk out; + ; the DBG_VALUE should copy-propagate through each and end up $noreg. + ; CHECK-LABEL: bb.0.entry: + ; CHECK: CMP32ri $esi, 0 + ; CHECK-NEXT: DBG_VALUE $noreg, $noreg, [[VAR6NUM]] + ; CHECK-NEXT: JCC_1 %bb.1, 4 + ; CHECK-NEXT: JMP_1 + + %2:gr64 = MOV64ri 0 + %5:gr64 = COPY %2 + %7:gr64 = COPY %5 + %8:gr64 = COPY %7 + CMP32ri $esi, 0, implicit-def $eflags + DBG_VALUE %8, $noreg, !503, !17, debug-location !504 + JCC_1 %bb.1.nou, 4, implicit $eflags + JMP_1 %bb.2.exit + + bb.1.nou: + successors: %bb.2.exit + + ; This block should receive the sunk copies and DBG_VALUE + ; CHECK-LABEL: bb.1.nou: + ; CHECK: [[T6COPY1:%[0-9]+]]:gr64 = MOV64ri 0 + ; CHECK-NEXT: [[T6COPY2:%[0-9]+]]:gr64 = COPY [[T6COPY1]] + ; CHECK-NEXT: [[T6COPY3:%[0-9]+]]:gr64 = COPY [[T6COPY2]] + ; CHECK-NEXT: DBG_VALUE [[T6COPY3]], $noreg, [[VAR6NUM]] + ; CHECK-NEXT: ADD64ri8 + ; CHECK-NEXT: JMP_1 + %1:gr64 = ADD64ri8 %8, 4, implicit-def dead $eflags + JMP_1 %bb.2.exit + + bb.2.exit: + $rax = MOV64ri 1 + RET 0 +...