diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h index 8554a019987364..ef6a147eb2a52a 100644 --- a/llvm/include/llvm-c/DebugInfo.h +++ b/llvm/include/llvm-c/DebugInfo.h @@ -169,7 +169,8 @@ enum { LLVMDICommonBlockMetadataKind, LLVMDIStringTypeMetadataKind, LLVMDIGenericSubrangeMetadataKind, - LLVMDIArgListMetadataKind + LLVMDIArgListMetadataKind, + LLVMDIAssignIDMetadataKind, }; typedef unsigned LLVMMetadataKind; diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index ee5669c6c6aa86..74a51d5ce69079 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -349,7 +349,8 @@ enum MetadataCodes { // info. METADATA_COMMON_BLOCK = 44, // [distinct, scope, name, variable,...] METADATA_GENERIC_SUBRANGE = 45, // [distinct, count, lo, up, stride] - METADATA_ARG_LIST = 46 // [n x [type num, value num]] + METADATA_ARG_LIST = 46, // [n x [type num, value num]] + METADATA_ASSIGN_ID = 47, // [distinct, ...] }; // The constants block (CONSTANTS_BLOCK_ID) describes emission for each diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index 5b20bf3ade99a1..f57691f6f9fc66 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -215,6 +215,7 @@ class DINode : public MDNode { case DIImportedEntityKind: case DIModuleKind: case DIGenericSubrangeKind: + case DIAssignIDKind: return true; } } @@ -295,6 +296,41 @@ class GenericDINode : public DINode { } }; +/// Assignment ID. +/// Used to link stores (as an attachment) and dbg.assigns (as an operand). +/// DIAssignID metadata is never uniqued as we compare instances using +/// referential equality (the instance/address is the ID). +class DIAssignID : public MDNode { + friend class LLVMContextImpl; + friend class MDNode; + + DIAssignID(LLVMContext &C, StorageType Storage) + : MDNode(C, DIAssignIDKind, Storage, None) {} + + ~DIAssignID() { dropAllReferences(); } + + static DIAssignID *getImpl(LLVMContext &Context, StorageType Storage, + bool ShouldCreate = true); + + TempDIAssignID cloneImpl() const { return getTemporary(getContext()); } + +public: + // This node has no operands to replace. + void replaceOperandWith(unsigned I, Metadata *New) = delete; + + static DIAssignID *getDistinct(LLVMContext &Context) { + return getImpl(Context, Distinct); + } + static TempDIAssignID getTemporary(LLVMContext &Context) { + return TempDIAssignID(getImpl(Context, Temporary)); + } + // NOTE: Do not define get(LLVMContext&) - see class comment. + + static bool classof(const Metadata *MD) { + return MD->getMetadataID() == DIAssignIDKind; + } +}; + /// Array subrange. /// /// TODO: Merge into node for DW_TAG_array_type, which should have a custom diff --git a/llvm/include/llvm/IR/FixedMetadataKinds.def b/llvm/include/llvm/IR/FixedMetadataKinds.def index 3d986325c5d339..8723bf2a0680c7 100644 --- a/llvm/include/llvm/IR/FixedMetadataKinds.def +++ b/llvm/include/llvm/IR/FixedMetadataKinds.def @@ -49,3 +49,4 @@ LLVM_FIXED_MD_KIND(MD_memprof, "memprof", 34) LLVM_FIXED_MD_KIND(MD_callsite, "callsite", 35) LLVM_FIXED_MD_KIND(MD_kcfi_type, "kcfi_type", 36) LLVM_FIXED_MD_KIND(MD_pcsections, "pcsections", 37) +LLVM_FIXED_MD_KIND(MD_DIAssignID, "DIAssignID", 38) diff --git a/llvm/include/llvm/IR/Metadata.def b/llvm/include/llvm/IR/Metadata.def index bbf349e6b508ca..36c34c1d2347c0 100644 --- a/llvm/include/llvm/IR/Metadata.def +++ b/llvm/include/llvm/IR/Metadata.def @@ -110,6 +110,7 @@ HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DILocalVariable) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DILabel) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIObjCProperty) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIImportedEntity) +HANDLE_SPECIALIZED_MDNODE_LEAF(DIAssignID) HANDLE_SPECIALIZED_MDNODE_BRANCH(DIMacroNode) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacro) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacroFile) diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 0fda0559b5b417..43e47aa33c863f 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -4646,6 +4646,24 @@ bool LLParser::parseDILocation(MDNode *&Result, bool IsDistinct) { return false; } +/// parseDIAssignID: +/// ::= distinct !DIAssignID() +bool LLParser::parseDIAssignID(MDNode *&Result, bool IsDistinct) { + if (!IsDistinct) + return Lex.Error("missing 'distinct', required for !DIAssignID()"); + + Lex.Lex(); + + // Now eat the parens. + if (parseToken(lltok::lparen, "expected '(' here")) + return true; + if (parseToken(lltok::rparen, "expected ')' here")) + return true; + + Result = DIAssignID::getDistinct(Context); + return false; +} + /// parseGenericDINode: /// ::= !GenericDINode(tag: 15, header: "...", operands: {...}) bool LLParser::parseGenericDINode(MDNode *&Result, bool IsDistinct) { diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp index 02d76f61695afe..1ac1502e8aefb5 100644 --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -856,6 +856,7 @@ MetadataLoader::MetadataLoaderImpl::lazyLoadModuleMetadataBlock() { case bitc::METADATA_TEMPLATE_VALUE: case bitc::METADATA_GLOBAL_VAR: case bitc::METADATA_LOCAL_VAR: + case bitc::METADATA_ASSIGN_ID: case bitc::METADATA_LABEL: case bitc::METADATA_EXPRESSION: case bitc::METADATA_OBJC_PROPERTY: @@ -1964,6 +1965,18 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( break; } + case bitc::METADATA_ASSIGN_ID: { + if (Record.size() != 1) + return error("Invalid DIAssignID record."); + + IsDistinct = Record[0] & 1; + if (!IsDistinct) + return error("Invalid DIAssignID record. Must be distinct"); + + MetadataList.assignValue(DIAssignID::getDistinct(Context), NextMetadataNo); + NextMetadataNo++; + break; + } case bitc::METADATA_LOCAL_VAR: { // 10th field is for the obseleted 'inlinedAt:' field. if (Record.size() < 8 || Record.size() > 10) diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 1ac4413f158eba..bed3ebad9874e3 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -340,6 +340,8 @@ class ModuleBitcodeWriter : public ModuleBitcodeWriterBase { unsigned Abbrev); void writeDIModule(const DIModule *N, SmallVectorImpl &Record, unsigned Abbrev); + void writeDIAssignID(const DIAssignID *N, SmallVectorImpl &Record, + unsigned Abbrev); void writeDITemplateTypeParameter(const DITemplateTypeParameter *N, SmallVectorImpl &Record, unsigned Abbrev); @@ -1955,6 +1957,15 @@ void ModuleBitcodeWriter::writeDIModule(const DIModule *N, Record.clear(); } +void ModuleBitcodeWriter::writeDIAssignID(const DIAssignID *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + // There are no arguments for this metadata type. + Record.push_back(N->isDistinct()); + Stream.EmitRecord(bitc::METADATA_ASSIGN_ID, Record, Abbrev); + Record.clear(); +} + void ModuleBitcodeWriter::writeDITemplateTypeParameter( const DITemplateTypeParameter *N, SmallVectorImpl &Record, unsigned Abbrev) { diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index 21e662bed6b256..d49b8710bc9a48 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -1865,6 +1865,12 @@ static void writeDILocation(raw_ostream &Out, const DILocation *DL, Out << ")"; } +static void writeDIAssignID(raw_ostream &Out, const DIAssignID *DL, + AsmWriterContext &WriterCtx) { + Out << "!DIAssignID()"; + MDFieldPrinter Printer(Out, WriterCtx); +} + static void writeDISubrange(raw_ostream &Out, const DISubrange *N, AsmWriterContext &WriterCtx) { Out << "!DISubrange("; diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index 8f6d58cb90b902..d30fca63067c0d 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -469,9 +469,13 @@ bool llvm::stripDebugInfo(Function &F) { if (NewLoopID != LoopID) I.setMetadata(LLVMContext::MD_loop, NewLoopID); } - // Strip heapallocsite attachments, they point into the DIType system. - if (I.hasMetadataOtherThanDebugLoc()) + // Strip other attachments that are or use debug info. + if (I.hasMetadataOtherThanDebugLoc()) { + // Heapallocsites point into the DIType system. I.setMetadata("heapallocsite", nullptr); + // DIAssignID are debug info metadata primitives. + I.setMetadata(LLVMContext::MD_DIAssignID, nullptr); + } } } return Changed; diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 9b4f92a63c5e22..2359e56c086849 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -1253,6 +1253,13 @@ bool DIExpression::startsWithDeref() const { return getNumElements() > 0 && getElement(0) == dwarf::DW_OP_deref; } +DIAssignID *DIAssignID::getImpl(LLVMContext &Context, StorageType Storage, + bool ShouldCreate) { + // Uniqued DIAssignID are not supported as the instance address *is* the ID. + assert(Storage != StorageType::Uniqued && "uniqued DIAssignID unsupported"); + return new (0u, Storage) DIAssignID(Context, Storage); +} + unsigned DIExpression::ExprOperand::getSize() const { uint64_t Op = getOp(); diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 0614f206981a16..c9b2d6aa5abf27 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -471,6 +471,7 @@ class Verifier : public InstVisitor, VerifierSupport { void visitCallStackMetadata(MDNode *MD); void visitMemProfMetadata(Instruction &I, MDNode *MD); void visitCallsiteMetadata(Instruction &I, MDNode *MD); + void visitDIAssignIDMetadata(Instruction &I, MDNode *MD); void visitAnnotationMetadata(MDNode *Annotation); void visitAliasScopeMetadata(const MDNode *MD); void visitAliasScopeListMetadata(const MDNode *MD); @@ -1483,6 +1484,11 @@ void Verifier::visitDILocalVariable(const DILocalVariable &N) { CheckDI(!isa(Ty), "invalid type", &N, N.getType()); } +void Verifier::visitDIAssignID(const DIAssignID &N) { + CheckDI(!N.getNumOperands(), "DIAssignID has no arguments", &N); + CheckDI(N.isDistinct(), "DIAssignID must be distinct", &N); +} + void Verifier::visitDILabel(const DILabel &N) { if (auto *S = N.getRawScope()) CheckDI(isa(S), "invalid scope", &N, S); @@ -4549,6 +4555,14 @@ void Verifier::visitProfMetadata(Instruction &I, MDNode *MD) { } } +void Verifier::visitDIAssignIDMetadata(Instruction &I, MDNode *MD) { + assert(I.hasMetadata(LLVMContext::MD_DIAssignID)); + bool ExpectedInstTy = + isa(I) || isa(I) || isa(I); + CheckDI(ExpectedInstTy, "!DIAssignID attached to unexpected instruction kind", + I, MD); +} + void Verifier::visitCallStackMetadata(MDNode *MD) { // Call stack metadata should consist of a list of at least 1 constant int // (representing a hash of the location). @@ -4850,6 +4864,9 @@ void Verifier::visitInstruction(Instruction &I) { if (MDNode *MD = I.getMetadata(LLVMContext::MD_callsite)) visitCallsiteMetadata(I, MD); + if (MDNode *MD = I.getMetadata(LLVMContext::MD_DIAssignID)) + visitDIAssignIDMetadata(I, MD); + if (MDNode *Annotation = I.getMetadata(LLVMContext::MD_annotation)) visitAnnotationMetadata(Annotation); diff --git a/llvm/test/DebugInfo/Generic/assignment-tracking/parse-and-verify/distinct.ll b/llvm/test/DebugInfo/Generic/assignment-tracking/parse-and-verify/distinct.ll new file mode 100644 index 00000000000000..2cc5452fe7d2a9 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/assignment-tracking/parse-and-verify/distinct.ll @@ -0,0 +1,9 @@ +; RUN: not opt -S %s -experimental-assignment-tracking 2>&1 \ +; RUN: | FileCheck %s + +;; Check that badly formed assignment tracking metadata is caught either +;; while parsing or by the verifier. + +; CHECK: error: missing 'distinct', required for !DIAssignID() + +!1 = !DIAssignID() diff --git a/llvm/test/DebugInfo/Generic/assignment-tracking/parse-and-verify/instruction-type.ll b/llvm/test/DebugInfo/Generic/assignment-tracking/parse-and-verify/instruction-type.ll new file mode 100644 index 00000000000000..d0f447ee200b6e --- /dev/null +++ b/llvm/test/DebugInfo/Generic/assignment-tracking/parse-and-verify/instruction-type.ll @@ -0,0 +1,36 @@ +; RUN: opt -S %s -verify -experimental-assignment-tracking 2>&1 \ +; RUN: | FileCheck %s + +;; NOTE: Expect opt to return zero because the badly formed debug info +;; is going to be stripped. + +;; Check that badly formed assignment tracking metadata is caught either +;; while parsing or by the verifier. + +;; Check verifier output. +; CHECK: !DIAssignID attached to unexpected instruction kind + +;; Check DIAssignID is stripped from IR. +; CHECK: define dso_local void @fun() { +; CHECK-NOT: DIAssignID + +define dso_local void @fun() !dbg !7 { +entry: + ret void, !DIAssignID !14 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 14.0.0"} +!7 = distinct !DISubprogram(name: "fun", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!14 = distinct !DIAssignID() diff --git a/llvm/test/DebugInfo/Generic/assignment-tracking/parse-and-verify/operands.ll b/llvm/test/DebugInfo/Generic/assignment-tracking/parse-and-verify/operands.ll new file mode 100644 index 00000000000000..79adcb9ce2d125 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/assignment-tracking/parse-and-verify/operands.ll @@ -0,0 +1,9 @@ +; RUN: not opt -S %s -experimental-assignment-tracking 2>&1 \ +; RUN: | FileCheck %s + +;; Check that badly formed assignment tracking metadata is caught either +;; while parsing or by the verifier. + +; CHECK: error: expected ')' here + +!1 = distinct !DIAssignID(0) diff --git a/llvm/test/DebugInfo/Generic/assignment-tracking/parse-and-verify/roundtrip.ll b/llvm/test/DebugInfo/Generic/assignment-tracking/parse-and-verify/roundtrip.ll new file mode 100644 index 00000000000000..1ddb95b79b0f0e --- /dev/null +++ b/llvm/test/DebugInfo/Generic/assignment-tracking/parse-and-verify/roundtrip.ll @@ -0,0 +1,33 @@ +; RUN: opt %s -verify -experimental-assignment-tracking \ +; RUN: | opt -verify -S -experimental-assignment-tracking \ +; RUN: | FileCheck %s + +;; Roundtrip test (text -> bitcode -> text) for DIAssignID attachments. + +; CHECK: %local = alloca i32, align 4, !DIAssignID ![[ID:[0-9]+]] +; CHECK-DAG: ![[ID]] = distinct !DIAssignID() + +define dso_local void @fun() !dbg !7 { +entry: + %local = alloca i32, align 4, !DIAssignID !14 + ret void, !dbg !13 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 14.0.0"} +!7 = distinct !DISubprogram(name: "fun", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!10 = !DILocalVariable(name: "local", scope: !7, file: !1, line: 2, type: !11) +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!13 = !DILocation(line: 3, column: 1, scope: !7) +!14 = distinct !DIAssignID()