diff --git a/include/llvm/CodeGen/MIRYamlMapping.h b/include/llvm/CodeGen/MIRYamlMapping.h index 4097398b264..14d3744741c 100644 --- a/include/llvm/CodeGen/MIRYamlMapping.h +++ b/include/llvm/CodeGen/MIRYamlMapping.h @@ -196,6 +196,9 @@ struct MachineStackObject { unsigned Alignment = 0; StringValue CalleeSavedRegister; Optional LocalOffset; + StringValue DebugVar; + StringValue DebugExpr; + StringValue DebugLoc; }; template <> struct ScalarEnumerationTraits { @@ -221,6 +224,12 @@ template <> struct MappingTraits { 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; diff --git a/lib/CodeGen/MIRParser/MIParser.cpp b/lib/CodeGen/MIRParser/MIParser.cpp index 3ec039285b3..edfca5f88a4 100644 --- a/lib/CodeGen/MIRParser/MIParser.cpp +++ b/lib/CodeGen/MIRParser/MIParser.cpp @@ -100,6 +100,7 @@ public: bool parseStandaloneNamedRegister(unsigned &Reg); bool parseStandaloneVirtualRegister(unsigned &Reg); bool parseStandaloneStackObject(int &FI); + bool parseStandaloneMDNode(MDNode *&Node); bool parseBasicBlockDefinition(DenseMap &MBBSlots); @@ -677,6 +678,17 @@ bool MIParser::parseStandaloneStackObject(int &FI) { 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"; @@ -1858,3 +1870,9 @@ bool llvm::parseStackObjectReference(int &FI, SourceMgr &SM, 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); +} diff --git a/lib/CodeGen/MIRParser/MIParser.h b/lib/CodeGen/MIRParser/MIParser.h index 9e997efa54c..8aef704ab36 100644 --- a/lib/CodeGen/MIRParser/MIParser.h +++ b/lib/CodeGen/MIRParser/MIParser.h @@ -23,6 +23,7 @@ class BasicBlock; class MachineBasicBlock; class MachineInstr; class MachineFunction; +class MDNode; struct SlotMapping; class SMDiagnostic; class SourceMgr; @@ -89,6 +90,10 @@ bool parseStackObjectReference(int &FI, SourceMgr &SM, MachineFunction &MF, 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 diff --git a/lib/CodeGen/MIRParser/MIRParser.cpp b/lib/CodeGen/MIRParser/MIRParser.cpp index 95df67ea7a9..422efbc5ce5 100644 --- a/lib/CodeGen/MIRParser/MIRParser.cpp +++ b/lib/CodeGen/MIRParser/MIRParser.cpp @@ -23,6 +23,7 @@ #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" @@ -113,6 +114,11 @@ public: 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, @@ -123,6 +129,9 @@ public: 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); @@ -489,6 +498,8 @@ bool MIRParserImpl::initializeFrameInfo(MachineFunction &MF, 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()) @@ -522,6 +533,56 @@ bool MIRParserImpl::parseCalleeSavedRegister( return false; } +/// Verify that given node is of a certain type. Return true on error. +template +static bool typecheckMDNode(T *&Result, MDNode *Node, + const yaml::StringValue &Source, + StringRef TypeString, MIRParserImpl &Parser) { + if (!Node) + return false; + Result = dyn_cast(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, diff --git a/lib/CodeGen/MIRPrinter.cpp b/lib/CodeGen/MIRPrinter.cpp index 67fd5c226a5..faeb9055c23 100644 --- a/lib/CodeGen/MIRPrinter.cpp +++ b/lib/CodeGen/MIRPrinter.cpp @@ -84,7 +84,8 @@ public: 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: @@ -171,7 +172,7 @@ void MIRPrinter::print(const MachineFunction &MF) { 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); @@ -265,6 +266,7 @@ void MIRPrinter::convert(ModuleSlotTracker &MST, void MIRPrinter::convertStackObjects(yaml::MachineFunction &MF, const MachineFrameInfo &MFI, + MachineModuleInfo &MMI, ModuleSlotTracker &MST, const TargetRegisterInfo *TRI) { // Process fixed stack objects. @@ -342,6 +344,29 @@ void MIRPrinter::convertStackObjects(yaml::MachineFunction &MF, 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, diff --git a/test/CodeGen/MIR/X86/expected-metadata-node-in-stack-object.mir b/test/CodeGen/MIR/X86/expected-metadata-node-in-stack-object.mir new file mode 100644 index 00000000000..9a4696779fb --- /dev/null +++ b/test/CodeGen/MIR/X86/expected-metadata-node-in-stack-object.mir @@ -0,0 +1,25 @@ +# 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 +... diff --git a/test/CodeGen/MIR/X86/invalid-metadata-node-type.mir b/test/CodeGen/MIR/X86/invalid-metadata-node-type.mir new file mode 100644 index 00000000000..d0c1b2c31b0 --- /dev/null +++ b/test/CodeGen/MIR/X86/invalid-metadata-node-type.mir @@ -0,0 +1,53 @@ +# 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 +... diff --git a/test/CodeGen/MIR/X86/stack-object-debug-info.mir b/test/CodeGen/MIR/X86/stack-object-debug-info.mir new file mode 100644 index 00000000000..dc1ec1c9388 --- /dev/null +++ b/test/CodeGen/MIR/X86/stack-object-debug-info.mir @@ -0,0 +1,65 @@ +# 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 +...