unsigned Alignment = 0;
StringValue CalleeSavedRegister;
Optional<int64_t> LocalOffset;
+ StringValue DebugVar;
+ StringValue DebugExpr;
+ StringValue DebugLoc;
};
template <> struct ScalarEnumerationTraits<MachineStackObject::ObjectType> {
YamlIO.mapOptional("callee-saved-register", Object.CalleeSavedRegister,
StringValue()); // Don't print it out when it's empty.
YamlIO.mapOptional("local-offset", Object.LocalOffset);
+ YamlIO.mapOptional("di-variable", Object.DebugVar,
+ StringValue()); // Don't print it out when it's empty.
+ YamlIO.mapOptional("di-expression", Object.DebugExpr,
+ StringValue()); // Don't print it out when it's empty.
+ YamlIO.mapOptional("di-location", Object.DebugLoc,
+ StringValue()); // Don't print it out when it's empty.
}
static const bool flow = true;
bool parseStandaloneNamedRegister(unsigned &Reg);
bool parseStandaloneVirtualRegister(unsigned &Reg);
bool parseStandaloneStackObject(int &FI);
+ bool parseStandaloneMDNode(MDNode *&Node);
bool
parseBasicBlockDefinition(DenseMap<unsigned, MachineBasicBlock *> &MBBSlots);
return false;
}
+bool MIParser::parseStandaloneMDNode(MDNode *&Node) {
+ lex();
+ if (Token.isNot(MIToken::exclaim))
+ return error("expected a metadata node");
+ if (parseMDNode(Node))
+ return true;
+ if (Token.isNot(MIToken::Eof))
+ return error("expected end of string after the metadata node");
+ return false;
+}
+
static const char *printImplicitRegisterFlag(const MachineOperand &MO) {
assert(MO.isImplicit());
return MO.isDef() ? "implicit-def" : "implicit";
return MIParser(SM, MF, Error, Src, PFS, IRSlots)
.parseStandaloneStackObject(FI);
}
+
+bool llvm::parseMDNode(MDNode *&Node, SourceMgr &SM, MachineFunction &MF,
+ StringRef Src, const PerFunctionMIParsingState &PFS,
+ const SlotMapping &IRSlots, SMDiagnostic &Error) {
+ return MIParser(SM, MF, Error, Src, PFS, IRSlots).parseStandaloneMDNode(Node);
+}
class MachineBasicBlock;
class MachineInstr;
class MachineFunction;
+class MDNode;
struct SlotMapping;
class SMDiagnostic;
class SourceMgr;
const PerFunctionMIParsingState &PFS,
const SlotMapping &IRSlots, SMDiagnostic &Error);
+bool parseMDNode(MDNode *&Node, SourceMgr &SM, MachineFunction &MF,
+ StringRef Src, const PerFunctionMIParsingState &PFS,
+ const SlotMapping &IRSlots, SMDiagnostic &Error);
+
} // end namespace llvm
#endif
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MIRYamlMapping.h"
#include "llvm/IR/BasicBlock.h"
const yaml::StringValue &RegisterSource,
int FrameIdx);
+ bool parseStackObjectsDebugInfo(MachineFunction &MF,
+ PerFunctionMIParsingState &PFS,
+ const yaml::MachineStackObject &Object,
+ int FrameIdx);
+
bool initializeConstantPool(MachineConstantPool &ConstantPool,
const yaml::MachineFunction &YamlMF,
const MachineFunction &MF,
PerFunctionMIParsingState &PFS);
private:
+ bool parseMDNode(MDNode *&Node, const yaml::StringValue &Source,
+ MachineFunction &MF, const PerFunctionMIParsingState &PFS);
+
bool parseMBBReference(MachineBasicBlock *&MBB,
const yaml::StringValue &Source, MachineFunction &MF,
const PerFunctionMIParsingState &PFS);
return true;
if (Object.LocalOffset)
MFI.mapLocalFrameObject(ObjectIdx, Object.LocalOffset.getValue());
+ if (parseStackObjectsDebugInfo(MF, PFS, Object, ObjectIdx))
+ return true;
}
MFI.setCalleeSavedInfo(CSIInfo);
if (!CSIInfo.empty())
return false;
}
+/// Verify that given node is of a certain type. Return true on error.
+template <typename T>
+static bool typecheckMDNode(T *&Result, MDNode *Node,
+ const yaml::StringValue &Source,
+ StringRef TypeString, MIRParserImpl &Parser) {
+ if (!Node)
+ return false;
+ Result = dyn_cast<T>(Node);
+ if (!Result)
+ return Parser.error(Source.SourceRange.Start,
+ "expected a reference to a '" + TypeString +
+ "' metadata node");
+ return false;
+}
+
+bool MIRParserImpl::parseStackObjectsDebugInfo(
+ MachineFunction &MF, PerFunctionMIParsingState &PFS,
+ const yaml::MachineStackObject &Object, int FrameIdx) {
+ // Debug information can only be attached to stack objects; Fixed stack
+ // objects aren't supported.
+ assert(FrameIdx >= 0 && "Expected a stack object frame index");
+ MDNode *Var = nullptr, *Expr = nullptr, *Loc = nullptr;
+ if (parseMDNode(Var, Object.DebugVar, MF, PFS) ||
+ parseMDNode(Expr, Object.DebugExpr, MF, PFS) ||
+ parseMDNode(Loc, Object.DebugLoc, MF, PFS))
+ return true;
+ if (!Var && !Expr && !Loc)
+ return false;
+ DILocalVariable *DIVar = nullptr;
+ DIExpression *DIExpr = nullptr;
+ DILocation *DILoc = nullptr;
+ if (typecheckMDNode(DIVar, Var, Object.DebugVar, "DILocalVariable", *this) ||
+ typecheckMDNode(DIExpr, Expr, Object.DebugExpr, "DIExpression", *this) ||
+ typecheckMDNode(DILoc, Loc, Object.DebugLoc, "DILocation", *this))
+ return true;
+ MF.getMMI().setVariableDbgInfo(DIVar, DIExpr, unsigned(FrameIdx), DILoc);
+ return false;
+}
+
+bool MIRParserImpl::parseMDNode(MDNode *&Node, const yaml::StringValue &Source,
+ MachineFunction &MF,
+ const PerFunctionMIParsingState &PFS) {
+ if (Source.Value.empty())
+ return false;
+ SMDiagnostic Error;
+ if (llvm::parseMDNode(Node, SM, MF, Source.Value, PFS, IRSlots, Error))
+ return error(Error, Source.SourceRange);
+ return false;
+}
+
bool MIRParserImpl::initializeConstantPool(
MachineConstantPool &ConstantPool, const yaml::MachineFunction &YamlMF,
const MachineFunction &MF,
void convert(ModuleSlotTracker &MST, yaml::MachineJumpTable &YamlJTI,
const MachineJumpTableInfo &JTI);
void convertStackObjects(yaml::MachineFunction &MF,
- const MachineFrameInfo &MFI, ModuleSlotTracker &MST,
+ const MachineFrameInfo &MFI, MachineModuleInfo &MMI,
+ ModuleSlotTracker &MST,
const TargetRegisterInfo *TRI);
private:
ModuleSlotTracker MST(MF.getFunction()->getParent());
MST.incorporateFunction(*MF.getFunction());
convert(MST, YamlMF.FrameInfo, *MF.getFrameInfo());
- convertStackObjects(YamlMF, *MF.getFrameInfo(), MST,
+ convertStackObjects(YamlMF, *MF.getFrameInfo(), MF.getMMI(), MST,
MF.getSubtarget().getRegisterInfo());
if (const auto *ConstantPool = MF.getConstantPool())
convert(YamlMF, *ConstantPool);
void MIRPrinter::convertStackObjects(yaml::MachineFunction &MF,
const MachineFrameInfo &MFI,
+ MachineModuleInfo &MMI,
ModuleSlotTracker &MST,
const TargetRegisterInfo *TRI) {
// Process fixed stack objects.
MIPrinter(StrOS, MST, RegisterMaskIds, StackObjectOperandMapping)
.printStackObjectReference(MFI.getStackProtectorIndex());
}
+
+ // Print the debug variable information.
+ for (MachineModuleInfo::VariableDbgInfo &DebugVar :
+ MMI.getVariableDbgInfo()) {
+ auto StackObjectInfo = StackObjectOperandMapping.find(DebugVar.Slot);
+ assert(StackObjectInfo != StackObjectOperandMapping.end() &&
+ "Invalid stack object index");
+ const FrameIndexOperand &StackObject = StackObjectInfo->second;
+ assert(!StackObject.IsFixed && "Expected a non-fixed stack object");
+ auto &Object = MF.StackObjects[StackObject.ID];
+ {
+ raw_string_ostream StrOS(Object.DebugVar.Value);
+ DebugVar.Var->printAsOperand(StrOS, MST);
+ }
+ {
+ raw_string_ostream StrOS(Object.DebugExpr.Value);
+ DebugVar.Expr->printAsOperand(StrOS, MST);
+ }
+ {
+ raw_string_ostream StrOS(Object.DebugLoc.Value);
+ DebugVar.Loc->printAsOperand(StrOS, MST);
+ }
+ }
}
void MIRPrinter::convert(yaml::MachineFunction &MF,
--- /dev/null
+# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s
+--- |
+ define i32 @test(i32 %x) {
+ entry:
+ %xa = alloca i32, align 4
+ store i32 %x, i32* %xa, align 4
+ %0 = load i32, i32* %xa, align 4
+ ret i32 %0
+ }
+...
+---
+name: test
+liveins:
+ - { reg: '%edi' }
+stack:
+# CHECK: [[@LINE+1]]:74: expected a metadata node
+ - { id: 0, name: xa, offset: -12, size: 4, alignment: 4, di-variable: '0' }
+body: |
+ bb.0.entry:
+ liveins: %edi
+
+ MOV32mr %rsp, 1, _, -4, _, %edi :: (store 4 into %ir.xa)
+ %eax = COPY killed %edi
+ RETQ killed %eax
+...
--- /dev/null
+# RUN: not llc -march=x86-64 -start-after machine-sink -stop-after machine-sink -o /dev/null %s 2>&1 | FileCheck %s
+--- |
+ declare void @llvm.dbg.declare(metadata, metadata, metadata) #0
+
+ define void @foo() #1 {
+ entry:
+ %x.i = alloca i8, align 1
+ %y.i = alloca [256 x i8], align 16
+ %0 = bitcast [256 x i8]* %y.i to i8*
+ br label %for.body
+
+ for.body:
+ %1 = bitcast [256 x i8]* %y.i to i8*
+ call void @llvm.dbg.declare(metadata i8* %0, metadata !4, metadata !7) #3, !dbg !8
+ br label %for.body
+ }
+
+ attributes #0 = { nounwind readnone }
+ attributes #1 = { nounwind ssp uwtable }
+ attributes #3 = { nounwind }
+
+ !llvm.dbg.cu = !{!0}
+ !llvm.module.flags = !{!3}
+
+ !0 = distinct !DICompileUnit(language: DW_LANG_C89, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: 0, enums: !2, retainedTypes: !2)
+ !1 = !DIFile(filename: "t.c", directory: "")
+ !2 = !{}
+ !3 = !{i32 1, !"Debug Info Version", i32 3}
+ !4 = !DILocalVariable(name: "x", scope: !5, file: !1, line: 16, type: !6)
+ !5 = !DISubprogram(scope: null, isLocal: false, isDefinition: true, isOptimized: false)
+ !6 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char)
+ !7 = !DIExpression()
+ !8 = !DILocation(line: 0, scope: !5)
+...
+---
+name: foo
+isSSA: true
+tracksRegLiveness: true
+frameInfo:
+ maxAlignment: 16
+stack:
+# CHECK: [[@LINE+1]]:75: expected a reference to a 'DILocalVariable' metadata node
+ - { id: 0, name: y.i, offset: 0, size: 256, alignment: 16, di-variable: '!8',
+ di-expression: '!7', di-location: '!8' }
+body: |
+ bb.0.entry:
+ successors: %bb.1.for.body
+ bb.1.for.body:
+ successors: %bb.1.for.body
+
+ DBG_VALUE %stack.0.y.i, 0, !4, !7, debug-location !8
+ JMP_1 %bb.1.for.body
+...
--- /dev/null
+# RUN: llc -march=x86-64 -start-after machine-sink -stop-after machine-sink -o /dev/null %s | FileCheck %s
+# This test ensures that the MIR parser parses the stack object's debug info
+# correctly.
+--- |
+ declare void @llvm.dbg.declare(metadata, metadata, metadata) #0
+
+ define void @foo() #1 {
+ entry:
+ %x.i = alloca i8, align 1
+ %y.i = alloca [256 x i8], align 16
+ %0 = bitcast [256 x i8]* %y.i to i8*
+ br label %for.body
+
+ for.body:
+ %1 = bitcast [256 x i8]* %y.i to i8*
+ call void @llvm.lifetime.end(i64 -1, i8* %1) #3
+ call void @llvm.lifetime.start(i64 -1, i8* %0) #3
+ call void @llvm.dbg.declare(metadata i8* %0, metadata !4, metadata !7) #3, !dbg !8
+ br label %for.body
+ }
+
+ declare void @llvm.lifetime.start(i64, i8* nocapture) #2
+
+ declare void @llvm.lifetime.end(i64, i8* nocapture) #2
+
+ attributes #0 = { nounwind readnone }
+ attributes #1 = { nounwind ssp uwtable }
+ attributes #2 = { nounwind argmemonly }
+ attributes #3 = { nounwind }
+
+ !llvm.dbg.cu = !{!0}
+ !llvm.module.flags = !{!3}
+
+ !0 = distinct !DICompileUnit(language: DW_LANG_C89, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: 0, enums: !2, retainedTypes: !2)
+ !1 = !DIFile(filename: "t.c", directory: "")
+ !2 = !{}
+ !3 = !{i32 1, !"Debug Info Version", i32 3}
+ !4 = !DILocalVariable(name: "x", scope: !5, file: !1, line: 16, type: !6)
+ !5 = !DISubprogram(scope: null, isLocal: false, isDefinition: true, isOptimized: false)
+ !6 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char)
+ !7 = !DIExpression()
+ !8 = !DILocation(line: 0, scope: !5)
+...
+---
+name: foo
+isSSA: true
+tracksRegLiveness: true
+frameInfo:
+ maxAlignment: 16
+# CHECK-LABEL: foo
+# CHECK: stack:
+# CHECK: - { id: 0, name: y.i, offset: 0, size: 256, alignment: 16, di-variable: '!4',
+# CHECK-NEXT: di-expression: '!7', di-location: '!8' }
+stack:
+ - { id: 0, name: y.i, offset: 0, size: 256, alignment: 16, di-variable: '!4',
+ di-expression: '!7', di-location: '!8' }
+body: |
+ bb.0.entry:
+ successors: %bb.1.for.body
+ bb.1.for.body:
+ successors: %bb.1.for.body
+
+ DBG_VALUE %stack.0.y.i, 0, !4, !7, debug-location !8
+ JMP_1 %bb.1.for.body
+...