[mir] Serialize DILocation inline when not possible to use a metadata reference
Summary:
Sometimes MIR-level passes create DILocations that were not present in the
LLVM-IR. For example, it may merge two DILocations together to produce a
DILocation that points to line 0.
Previously, the address of these DILocations were printed which prevented the
MIR from being read back into LLVM. With this patch, DILocations will use
metadata references where possible and fall back on serializing them inline like so:
MOV32mr %stack.0.x.addr, 1, _, 0, _, %0, debug-location !DILocation(line: 1, scope: !15)
Reviewers: aprantl, vsk, arphaman
Reviewed By: aprantl
Subscribers: probinson, llvm-commits
Tags: #debug-info
Differential Revision: https://reviews.llvm.org/D55243
llvm-svn: 349035
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
index f7cc94e..6d6d551 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
@@ -576,6 +576,7 @@
.Case("!noalias", MIToken::md_noalias)
.Case("!range", MIToken::md_range)
.Case("!DIExpression", MIToken::md_diexpr)
+ .Case("!DILocation", MIToken::md_dilocation)
.Default(MIToken::Error);
}
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.h b/llvm/lib/CodeGen/MIRParser/MILexer.h
index dffa4f7..a52f620 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.h
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.h
@@ -126,6 +126,7 @@
md_noalias,
md_range,
md_diexpr,
+ md_dilocation,
// Identifier tokens
Identifier,
diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index 1a6174b..16cade0 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -226,6 +226,7 @@
bool parseMCSymbolOperand(MachineOperand &Dest);
bool parseMDNode(MDNode *&Node);
bool parseDIExpression(MDNode *&Expr);
+ bool parseDILocation(MDNode *&Expr);
bool parseMetadataOperand(MachineOperand &Dest);
bool parseCFIOffset(int &Offset);
bool parseCFIRegister(unsigned &Reg);
@@ -776,11 +777,15 @@
DebugLoc DebugLocation;
if (Token.is(MIToken::kw_debug_location)) {
lex();
- if (Token.isNot(MIToken::exclaim))
- return error("expected a metadata node after 'debug-location'");
MDNode *Node = nullptr;
- if (parseMDNode(Node))
- return true;
+ if (Token.is(MIToken::exclaim)) {
+ if (parseMDNode(Node))
+ return true;
+ } else if (Token.is(MIToken::md_dilocation)) {
+ if (parseDILocation(Node))
+ return true;
+ } else
+ return error("expected a metadata node after 'debug-location'");
if (!isa<DILocation>(Node))
return error("referenced metadata is not a DILocation");
DebugLocation = DebugLoc(Node);
@@ -898,6 +903,9 @@
} else if (Token.is(MIToken::md_diexpr)) {
if (parseDIExpression(Node))
return true;
+ } else if (Token.is(MIToken::md_dilocation)) {
+ if (parseDILocation(Node))
+ return true;
} else
return error("expected a metadata node");
if (Token.isNot(MIToken::Eof))
@@ -1684,6 +1692,109 @@
return false;
}
+bool MIParser::parseDILocation(MDNode *&Loc) {
+ assert(Token.is(MIToken::md_dilocation));
+ lex();
+
+ bool HaveLine = false;
+ unsigned Line = 0;
+ unsigned Column = 0;
+ MDNode *Scope = nullptr;
+ MDNode *InlinedAt = nullptr;
+ bool ImplicitCode;
+
+ if (expectAndConsume(MIToken::lparen))
+ return true;
+
+ if (Token.isNot(MIToken::rparen)) {
+ do {
+ if (Token.is(MIToken::Identifier)) {
+ if (Token.stringValue() == "line") {
+ lex();
+ if (expectAndConsume(MIToken::colon))
+ return true;
+ if (Token.isNot(MIToken::IntegerLiteral) ||
+ Token.integerValue().isSigned())
+ return error("expected unsigned integer");
+ Line = Token.integerValue().getZExtValue();
+ HaveLine = true;
+ lex();
+ continue;
+ }
+ if (Token.stringValue() == "column") {
+ lex();
+ if (expectAndConsume(MIToken::colon))
+ return true;
+ if (Token.isNot(MIToken::IntegerLiteral) ||
+ Token.integerValue().isSigned())
+ return error("expected unsigned integer");
+ Column = Token.integerValue().getZExtValue();
+ lex();
+ continue;
+ }
+ if (Token.stringValue() == "scope") {
+ lex();
+ if (expectAndConsume(MIToken::colon))
+ return true;
+ if (parseMDNode(Scope))
+ return error("expected metadata node");
+ if (!isa<DIScope>(Scope))
+ return error("expected DIScope node");
+ continue;
+ }
+ if (Token.stringValue() == "inlinedAt") {
+ lex();
+ if (expectAndConsume(MIToken::colon))
+ return true;
+ if (Token.is(MIToken::exclaim)) {
+ if (parseMDNode(InlinedAt))
+ return true;
+ } else if (Token.is(MIToken::md_dilocation)) {
+ if (parseDILocation(InlinedAt))
+ return true;
+ } else
+ return error("expected metadata node");
+ if (!isa<DILocation>(InlinedAt))
+ return error("expected DILocation node");
+ continue;
+ }
+ if (Token.stringValue() == "isImplicitCode") {
+ lex();
+ if (expectAndConsume(MIToken::colon))
+ return true;
+ if (!Token.is(MIToken::Identifier))
+ return error("expected true/false");
+ // As far as I can see, we don't have any existing need for parsing
+ // true/false in MIR yet. Do it ad-hoc until there's something else
+ // that needs it.
+ if (Token.stringValue() == "true")
+ ImplicitCode = true;
+ else if (Token.stringValue() == "false")
+ ImplicitCode = false;
+ else
+ return error("expected true/false");
+ lex();
+ continue;
+ }
+ }
+ return error(Twine("invalid DILocation argument '") +
+ Token.stringValue() + "'");
+ } while (consumeIfPresent(MIToken::comma));
+ }
+
+ if (expectAndConsume(MIToken::rparen))
+ return true;
+
+ if (!HaveLine)
+ return error("DILocation requires line number");
+ if (!Scope)
+ return error("DILocation requires a scope");
+
+ Loc = DILocation::get(MF.getFunction().getContext(), Line, Column, Scope,
+ InlinedAt, ImplicitCode);
+ return false;
+}
+
bool MIParser::parseMetadataOperand(MachineOperand &Dest) {
MDNode *Node = nullptr;
if (Token.is(MIToken::exclaim)) {
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index 23aee72..36f4f3a 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -2294,11 +2294,15 @@
Machine = MachineStorage.get();
}
int Slot = Machine->getMetadataSlot(N);
- if (Slot == -1)
+ if (Slot == -1) {
+ if (const DILocation *Loc = dyn_cast<DILocation>(N)) {
+ writeDILocation(Out, Loc, TypePrinter, Machine, Context);
+ return;
+ }
// Give the pointer value instead of "badref", since this comes up all
// the time when debugging.
Out << "<" << N << ">";
- else
+ } else
Out << '!' << Slot;
return;
}
diff --git a/llvm/test/CodeGen/Hexagon/packetize-debug-loc.mir b/llvm/test/CodeGen/Hexagon/packetize-debug-loc.mir
index 9bcc5ba..f86fb05 100644
--- a/llvm/test/CodeGen/Hexagon/packetize-debug-loc.mir
+++ b/llvm/test/CodeGen/Hexagon/packetize-debug-loc.mir
@@ -41,9 +41,9 @@
# CHECK-LABEL: name: test
# CHECK: BUNDLE
-# CHECK-SAME: debug-location [[DL1:[0-9x<>]+]]
+# CHECK-SAME: debug-location [[DL1:!DILocation([^)]+)]]
# CHECK-NEXT: L2_loadri_io $r1, 0, debug-location [[DL1]]
-# CHECK-NEXT: L2_loadri_io $r1, 0, debug-location [[DL2:[0-9x<>]+]]
+# CHECK-NEXT: L2_loadri_io $r1, 0, debug-location [[DL2:!DILocation([^)]+)]]
# CHECK: BUNDLE
# CHECK-SAME: debug-location [[DL1]]
diff --git a/llvm/test/CodeGen/MIR/X86/instructions-debug-location.mir b/llvm/test/CodeGen/MIR/X86/instructions-debug-location.mir
index 8b6c5cb..fe74f5c 100644
--- a/llvm/test/CodeGen/MIR/X86/instructions-debug-location.mir
+++ b/llvm/test/CodeGen/MIR/X86/instructions-debug-location.mir
@@ -22,6 +22,17 @@
ret i32 %0, !dbg !14
}
+ define i32 @test_mir_created(i32 %x) #0 !dbg !15 {
+ entry:
+ %x.addr = alloca i32, align 4
+ store i32 %x, i32* %x.addr, align 4
+ %0 = load i32, i32* %x.addr, align 4
+ %1 = load i32, i32* %x.addr, align 4
+ %2 = load i32, i32* %x.addr, align 4
+ %3 = load i32, i32* %x.addr, align 4
+ ret i32 %0, !dbg !16
+ }
+
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
attributes #0 = { nounwind "no-frame-pointer-elim"="false" }
@@ -45,6 +56,8 @@
!12 = !DILocalVariable(name: "x", arg: 1, scope: !4, file: !5, line: 4, type: !8)
!13 = !DILocation(line: 4, scope: !4)
!14 = !DILocation(line: 8, scope: !4)
+ !15 = distinct !DISubprogram(name: "test_mir_created", scope: !5, file: !5, line: 10, type: !6, isLocal: false, isDefinition: true, scopeLine: 10, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
+ !16 = !DILocation(line: 20, scope: !15)
...
---
@@ -96,3 +109,31 @@
$eax = COPY %0
RETQ $eax
...
+---
+name: test_mir_created
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gr32 }
+frameInfo:
+ maxAlignment: 4
+stack:
+ - { id: 0, name: x.addr, size: 4, alignment: 4 }
+body: |
+ bb.0.entry:
+ liveins: $edi
+
+ %0 = COPY $edi
+ ; CHECK-LABEL: name: test_mir_created
+ ; CHECK: MOV32mr %stack.0.x.addr, 1, $noreg, 0, $noreg, %0, debug-location !DILocation(line: 1, scope: !14)
+ ; CHECK: MOV32mr %stack.0.x.addr, 1, $noreg, 0, $noreg, %0, debug-location !DILocation(line: 2, column: 2, scope: !14)
+ ; CHECK: MOV32mr %stack.0.x.addr, 1, $noreg, 0, $noreg, %0, debug-location !DILocation(line: 3, column: 2, scope: !14, isImplicitCode: true)
+ ; CHECK: MOV32mr %stack.0.x.addr, 1, $noreg, 0, $noreg, %0, debug-location !DILocation(line: 4, scope: !14, inlinedAt: !15)
+ ; CHECK: MOV32mr %stack.0.x.addr, 1, $noreg, 0, $noreg, %0, debug-location !DILocation(line: 5, scope: !14, inlinedAt: !DILocation(line: 4, scope: !14))
+ MOV32mr %stack.0.x.addr, 1, _, 0, _, %0, debug-location !DILocation(line: 1, scope: !15)
+ MOV32mr %stack.0.x.addr, 1, _, 0, _, %0, debug-location !DILocation(line: 2, column: 2, scope: !15)
+ MOV32mr %stack.0.x.addr, 1, _, 0, _, %0, debug-location !DILocation(line: 3, column: 2, scope: !15, isImplicitCode: true)
+ MOV32mr %stack.0.x.addr, 1, _, 0, _, %0, debug-location !DILocation(line: 4, scope: !15, inlinedAt: !16)
+ MOV32mr %stack.0.x.addr, 1, _, 0, _, %0, debug-location !DILocation(line: 5, scope: !15, inlinedAt: !DILocation(line: 4, scope: !15))
+ $eax = COPY %0
+ RETQ $eax
+...