LLVMDICommonBlockMetadataKind,
LLVMDIStringTypeMetadataKind,
LLVMDIGenericSubrangeMetadataKind,
- LLVMDIArgListMetadataKind
+ LLVMDIArgListMetadataKind,
+ LLVMDIAssignIDMetadataKind,
};
typedef unsigned LLVMMetadataKind;
// 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
case DIImportedEntityKind:
case DIModuleKind:
case DIGenericSubrangeKind:
+ case DIAssignIDKind:
return true;
}
}
}
};
+/// 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
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)
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)
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) {
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:
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)
unsigned Abbrev);
void writeDIModule(const DIModule *N, SmallVectorImpl<uint64_t> &Record,
unsigned Abbrev);
+ void writeDIAssignID(const DIAssignID *N, SmallVectorImpl<uint64_t> &Record,
+ unsigned Abbrev);
void writeDITemplateTypeParameter(const DITemplateTypeParameter *N,
SmallVectorImpl<uint64_t> &Record,
unsigned Abbrev);
Record.clear();
}
+void ModuleBitcodeWriter::writeDIAssignID(const DIAssignID *N,
+ SmallVectorImpl<uint64_t> &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<uint64_t> &Record,
unsigned Abbrev) {
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(";
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;
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 storeImpl(new (0u, Storage) DIAssignID(Context, Storage), Storage);
+}
+
unsigned DIExpression::ExprOperand::getSize() const {
uint64_t Op = getOp();
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);
CheckDI(!isa<DISubroutineType>(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<DIScope>(S), "invalid scope", &N, S);
}
}
+void Verifier::visitDIAssignIDMetadata(Instruction &I, MDNode *MD) {
+ assert(I.hasMetadata(LLVMContext::MD_DIAssignID));
+ bool ExpectedInstTy =
+ isa<AllocaInst>(I) || isa<StoreInst>(I) || isa<MemIntrinsic>(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).
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);
--- /dev/null
+; 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()
--- /dev/null
+; 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()
--- /dev/null
+; 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)
--- /dev/null
+; 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()