Index: llvm/include/llvm/CodeGen/MachineFunction.h =================================================================== --- llvm/include/llvm/CodeGen/MachineFunction.h +++ llvm/include/llvm/CodeGen/MachineFunction.h @@ -436,6 +436,10 @@ /// next instruction number. unsigned DebugInstrNumberingCount = 0; + /// Set value of DebugInstrNumberingCount field. Avoid using this unless + /// you're deserializing this data. + void setDebugInstrNumberingCount(unsigned Num); + MachineFunction(Function &F, const LLVMTargetMachine &Target, const TargetSubtargetInfo &STI, unsigned FunctionNum, MachineModuleInfo &MMI); Index: llvm/include/llvm/CodeGen/MachineInstr.h =================================================================== --- llvm/include/llvm/CodeGen/MachineInstr.h +++ llvm/include/llvm/CodeGen/MachineInstr.h @@ -453,6 +453,10 @@ /// it hasn't been assigned a number yet. unsigned peekDebugInstrNum() const { return DebugInstrNum; } + /// Set instruction number of this MachineInstr. Avoid using unless you're + /// deserializing this information. + void setDebugInstrNum(unsigned Num) { DebugInstrNum = Num; } + /// Emit an error referring to the source location of this instruction. /// This should only be used for inline assembly that is somehow /// impossible to compile. Other errors should have been handled much Index: llvm/lib/CodeGen/MIRParser/MILexer.h =================================================================== --- llvm/lib/CodeGen/MIRParser/MILexer.h +++ llvm/lib/CodeGen/MIRParser/MILexer.h @@ -74,6 +74,7 @@ kw_exact, kw_nofpexcept, kw_debug_location, + kw_debug_instr_number, kw_cfi_same_value, kw_cfi_offset, kw_cfi_rel_offset, Index: llvm/lib/CodeGen/MIRParser/MILexer.cpp =================================================================== --- llvm/lib/CodeGen/MIRParser/MILexer.cpp +++ llvm/lib/CodeGen/MIRParser/MILexer.cpp @@ -217,6 +217,7 @@ .Case("exact" , MIToken::kw_exact) .Case("nofpexcept", MIToken::kw_nofpexcept) .Case("debug-location", MIToken::kw_debug_location) + .Case("debug-instr-number", MIToken::kw_debug_instr_number) .Case("same_value", MIToken::kw_cfi_same_value) .Case("offset", MIToken::kw_cfi_offset) .Case("rel_offset", MIToken::kw_cfi_rel_offset) Index: llvm/lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- llvm/lib/CodeGen/MIRParser/MIParser.cpp +++ llvm/lib/CodeGen/MIRParser/MIParser.cpp @@ -984,6 +984,7 @@ Token.isNot(MIToken::kw_post_instr_symbol) && Token.isNot(MIToken::kw_heap_alloc_marker) && Token.isNot(MIToken::kw_debug_location) && + Token.isNot(MIToken::kw_debug_instr_number) && Token.isNot(MIToken::coloncolon) && Token.isNot(MIToken::lbrace)) { auto Loc = Token.location(); Optional TiedDefIdx; @@ -1014,6 +1015,19 @@ if (parseHeapAllocMarker(HeapAllocMarker)) return true; + unsigned InstrNum = 0; + if (Token.is(MIToken::kw_debug_instr_number)) { + lex(); + if (Token.isNot(MIToken::IntegerLiteral)) + return error("expected an integer literal after 'debug-instr-number'"); + if (getUnsigned(InstrNum)) + return true; + lex(); + // Lex past trailing comma if present. + if (Token.is(MIToken::comma)) + lex(); + } + DebugLoc DebugLocation; if (Token.is(MIToken::kw_debug_location)) { lex(); @@ -1070,6 +1084,8 @@ MI->setHeapAllocMarker(MF, HeapAllocMarker); if (!MemOperands.empty()) MI->setMemRefs(MF, MemOperands); + if (InstrNum) + MI->setDebugInstrNum(InstrNum); return false; } Index: llvm/lib/CodeGen/MIRParser/MIRParser.cpp =================================================================== --- llvm/lib/CodeGen/MIRParser/MIRParser.cpp +++ llvm/lib/CodeGen/MIRParser/MIRParser.cpp @@ -161,6 +161,9 @@ SMRange SourceRange); void computeFunctionProperties(MachineFunction &MF); + + void setupDebugValueTracking(MachineFunction &MF, + PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF); }; } // end namespace llvm @@ -397,6 +400,18 @@ return false; } +void MIRParserImpl::setupDebugValueTracking(MachineFunction &MF, + PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF) { + // For now, we only compute the value of the "next instruction number" + // field. + unsigned MaxInstrNum = 0; + for (auto &MBB : MF) + for (auto &MI : MBB) + MaxInstrNum = std::max((unsigned)MI.peekDebugInstrNum(), MaxInstrNum); + MF.setDebugInstrNumberingCount(MaxInstrNum); +} + + bool MIRParserImpl::initializeMachineFunction(const yaml::MachineFunction &YamlMF, MachineFunction &MF) { @@ -507,6 +522,8 @@ if (initializeCallSiteInfo(PFS, YamlMF)) return false; + setupDebugValueTracking(MF, PFS, YamlMF); + MF.getSubtarget().mirFileLoaded(MF); MF.verify(); Index: llvm/lib/CodeGen/MIRPrinter.cpp =================================================================== --- llvm/lib/CodeGen/MIRPrinter.cpp +++ llvm/lib/CodeGen/MIRPrinter.cpp @@ -818,6 +818,13 @@ NeedComma = true; } + if (auto Num = MI.peekDebugInstrNum()) { + if (NeedComma) + OS << ','; + OS << " debug-instr-number " << Num; + NeedComma = true; + } + if (PrintLocations) { if (const DebugLoc &DL = MI.getDebugLoc()) { if (NeedComma) Index: llvm/lib/CodeGen/MachineFunction.cpp =================================================================== --- llvm/lib/CodeGen/MachineFunction.cpp +++ llvm/lib/CodeGen/MachineFunction.cpp @@ -974,6 +974,10 @@ CallSitesInfo[New] = CSInfo; } +void MachineFunction::setDebugInstrNumberingCount(unsigned Num) { + DebugInstrNumberingCount = Num; +} + /// \} //===----------------------------------------------------------------------===// Index: llvm/lib/CodeGen/MachineVerifier.cpp =================================================================== --- llvm/lib/CodeGen/MachineVerifier.cpp +++ llvm/lib/CodeGen/MachineVerifier.cpp @@ -1464,6 +1464,11 @@ if (!MI->getDebugLoc()) report("Missing DebugLoc for debug instruction", MI); + // Meta instructions should never be the subject of debug value tracking, + // they don't create a value in the output program at all. + if (MI->isMetaInstruction() && MI->peekDebugInstrNum()) + report("Metadata instruction should not have a value tracking number", MI); + // Check the MachineMemOperands for basic consistency. for (MachineMemOperand *Op : MI->memoperands()) { if (Op->isLoad() && !MI->mayLoad()) @@ -2445,6 +2450,21 @@ for (auto CSInfo : MF->getCallSitesInfo()) if (!CSInfo.first->isCall()) report("Call site info referencing instruction that is not call", MF); + + // If there's debug-info, check that we don't have any duplicate value + // tracking numbers. + if (MF->getFunction().getSubprogram()) { + DenseSet SeenNumbers; + for (auto &MBB : *MF) { + for (auto &MI : MBB) { + if (auto Num = MI.peekDebugInstrNum()) { + auto Result = SeenNumbers.insert((unsigned)Num); + if (!Result.second) + report("Instruction has a duplicated value tracking number", &MI); + } + } + } + } } void MachineVerifier::verifyLiveVariables() { Index: llvm/test/DebugInfo/MIR/InstrRef/instr-ref-roundtrip.mir =================================================================== --- /dev/null +++ llvm/test/DebugInfo/MIR/InstrRef/instr-ref-roundtrip.mir @@ -0,0 +1,16 @@ +# RUN: llc %s -march=x86-64 -run-pass=machineverifier -o - -experimental-debug-variable-locations | FileCheck %s +# +# CHECK: MOV64rr $rdi, debug-instr-number 1 +--- +name: test +tracksRegLiveness: true +liveins: + - { reg: '$rdi', virtual-reg: '' } +body: | + bb.0: + liveins: $rdi, $rax + $rbp = MOV64rr $rdi, debug-instr-number 1 + dead $rcx = MOV64ri 0 + CMP64ri8 renamable $rax, 1, implicit-def $eflags + RETQ $rax +... Index: llvm/test/DebugInfo/MIR/InstrRef/no-duplicates.mir =================================================================== --- /dev/null +++ llvm/test/DebugInfo/MIR/InstrRef/no-duplicates.mir @@ -0,0 +1,38 @@ +# RUN: not --crash llc %s -march=x86-64 -run-pass=machineverifier -o - 2>&1 | FileCheck %s +# +# CHECK: Instruction has a duplicated value tracking number +--- | + define i32 @test(i32 %bar) local_unnamed_addr !dbg !7 { + entry: + ret i32 0, !dbg !12 + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3, !4, !5, !6} + !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug) + !1 = !DIFile(filename: "foo.cpp", directory: ".") + !2 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !3 = !{i32 2, !"Dwarf Version", i32 4} + !4 = !{i32 2, !"Debug Info Version", i32 3} + !5 = !{i32 1, !"wchar_size", i32 2} + !6 = !{i32 7, !"PIC Level", i32 2} + !7 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: !1, file: !1, line: 6, type: !8, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10) + !8 = !DISubroutineType(types: !9) + !9 = !{!2, !2} + !10 = !{!11} + !11 = !DILocalVariable(name: "baz", scope: !7, file: !1, line: 7, type: !2) + !12 = !DILocation(line: 10, scope: !7) +... +--- +name: test +tracksRegLiveness: true +liveins: + - { reg: '$rdi', virtual-reg: '' } +body: | + bb.0: + liveins: $rdi, $rax + $rbp = MOV64rr $rdi, debug-instr-number 1, debug-location !12 + dead $rcx = MOV64ri 0, debug-instr-number 1, debug-location !12 + CMP64ri8 renamable $rax, 1, implicit-def $eflags + RETQ $rax +... Index: llvm/test/DebugInfo/MIR/InstrRef/no-metainstrs.mir =================================================================== --- /dev/null +++ llvm/test/DebugInfo/MIR/InstrRef/no-metainstrs.mir @@ -0,0 +1,39 @@ +# RUN: not --crash llc %s -march=x86-64 -run-pass=machineverifier -o - 2>&1 | FileCheck %s +# +# CHECK: Metadata instruction should not have a value tracking number +--- | + define i32 @test(i32 %bar) local_unnamed_addr !dbg !7 { + entry: + ret i32 0, !dbg !12 + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3, !4, !5, !6} + !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug) + !1 = !DIFile(filename: "foo.cpp", directory: ".") + !2 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !3 = !{i32 2, !"Dwarf Version", i32 4} + !4 = !{i32 2, !"Debug Info Version", i32 3} + !5 = !{i32 1, !"wchar_size", i32 2} + !6 = !{i32 7, !"PIC Level", i32 2} + !7 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: !1, file: !1, line: 6, type: !8, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10) + !8 = !DISubroutineType(types: !9) + !9 = !{!2, !2} + !10 = !{!11} + !11 = !DILocalVariable(name: "baz", scope: !7, file: !1, line: 7, type: !2) + !12 = !DILocation(line: 10, scope: !7) +... +--- +name: test +tracksRegLiveness: true +liveins: + - { reg: '$rdi', virtual-reg: '' } +body: | + bb.0: + liveins: $rdi, $rax + $rbp = MOV64rr $rdi, debug-instr-number 1, debug-location !12 + $ebp = KILL killed $rbp, debug-instr-number 2, debug-location !12 + dead $rcx = MOV64ri 0 + CMP64ri8 renamable $rax, 1, implicit-def $eflags + RETQ $rax +...