/// 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);
/// 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
.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)
kw_exact,
kw_nofpexcept,
kw_debug_location,
+ kw_debug_instr_number,
kw_cfi_same_value,
kw_cfi_offset,
kw_cfi_rel_offset,
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<unsigned> TiedDefIdx;
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();
MI->setHeapAllocMarker(MF, HeapAllocMarker);
if (!MemOperands.empty())
MI->setMemRefs(MF, MemOperands);
+ if (InstrNum)
+ MI->setDebugInstrNum(InstrNum);
return false;
}
SMRange SourceRange);
void computeFunctionProperties(MachineFunction &MF);
+
+ void setupDebugValueTracking(MachineFunction &MF,
+ PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF);
};
} // end namespace llvm
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) {
if (initializeCallSiteInfo(PFS, YamlMF))
return false;
+ setupDebugValueTracking(MF, PFS, YamlMF);
+
MF.getSubtarget().mirFileLoaded(MF);
MF.verify();
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)
CallSitesInfo[New] = CSInfo;
}
+void MachineFunction::setDebugInstrNumberingCount(unsigned Num) {
+ DebugInstrNumberingCount = Num;
+}
+
/// \}
//===----------------------------------------------------------------------===//
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())
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<unsigned> 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() {
--- /dev/null
+# 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
+...
--- /dev/null
+# 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
+...
--- /dev/null
+# 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
+...