diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 99e12da0081af..ef3aeb201fb5f 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -56,6 +56,16 @@ using namespace clang; using namespace clang::CodeGen; +// Temporarily hide new format for btf_type_tags / DW_TAG_LLVM_annotation +// behind an option to allow transitory period for tooling dependent on +// this annotation. The goal is to remove this flag after transitory period. +static llvm::cl::opt BTFTypeTagV2( + "btf-type-tag-v2", llvm::cl::Hidden, + llvm::cl::desc("For __attribute__((btf_type_tag(...))) generate " + "DW_TAG_LLVM_annotation tags with DW_AT_name 'btf:type_tag' " + "attached to annotated type itself"), + llvm::cl::init(false)); + static uint32_t getTypeAlignIfRequired(const Type *Ty, const ASTContext &Ctx) { auto TI = Ctx.getTypeInfo(Ty); if (TI.isAlignRequired()) @@ -1194,6 +1204,129 @@ CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty, return RetTy; } +static QualType collectBTFTypeTagAnnotations( + llvm::LLVMContext &Context, llvm::DIBuilder &DBuilder, + llvm::SmallVectorImpl &Annots, + const BTFTagAttributedType *BTFAttrTy, const char *TagName) { + QualType WrappedTy; + + do { + StringRef TagValue = BTFAttrTy->getAttr()->getBTFTypeTag(); + if (!TagValue.empty()) { + llvm::Metadata *Ops[] = { + llvm::MDString::get(Context, TagName), + llvm::MDString::get(Context, TagValue), + }; + Annots.insert(Annots.begin(), llvm::MDNode::get(Context, Ops)); + } + WrappedTy = BTFAttrTy->getWrappedType(); + BTFAttrTy = dyn_cast(WrappedTy); + } while (BTFAttrTy); + + return WrappedTy; +} + +static bool retreiveCVR(llvm::DIDerivedType *DTy, QualifierCollector &Qc) { + switch (DTy->getTag()) { + case llvm::dwarf::DW_TAG_const_type: + Qc.addConst(); + return true; + case llvm::dwarf::DW_TAG_volatile_type: + Qc.addVolatile(); + return true; + case llvm::dwarf::DW_TAG_restrict_type: + Qc.addRestrict(); + return true; + default: + return false; + } +} + +// Tags returned by QualifierCollector::getNextQualifier() should be +// applied in the reverse order, thus use recursive function. +static llvm::DIType *applyQualifiers(llvm::DIBuilder &DBuilder, + llvm::DIType *Ty, QualifierCollector &Qc) { + llvm::dwarf::Tag Tag = getNextQualifier(Qc); + if (!Tag) + return Ty; + Ty = applyQualifiers(DBuilder, Ty, Qc); + return DBuilder.createQualifiedType(Tag, Ty); +} + +static bool isAnnotationsPlaceholder(llvm::DIDerivedType *DTy) { + return DTy->isTemporary() && + DTy->getTag() == llvm::dwarf::DW_TAG_LLVM_annotation; +} + +llvm::DIType *CGDebugInfo::CreateType(const BTFTagAttributedType *Ty, + llvm::DIFile *Unit) { + SmallVector Annotations; + auto WrappedTy = collectBTFTypeTagAnnotations( + CGM.getLLVMContext(), DBuilder, Annotations, Ty, "btf:type_tag"); + + if (!BTFTypeTagV2 || Annotations.empty()) + return getOrCreateType(WrappedTy, Unit); + + // After discussion with GCC BPF team in [1] it was decided to avoid + // attaching BTF type tags to const/volatile/restrict DWARF DIEs. + // So, strip qualifiers from WrappedTy and apply those to a final + // annotations placeholder instance at the end of this function. + // + // [1] https://reviews.llvm.org/D143967 + QualifierCollector Qc; + Qc.addCVRQualifiers(WrappedTy.getLocalCVRQualifiers()); + WrappedTy.removeLocalFastQualifiers(Qualifiers::CVRMask); + + llvm::DIType *WrappedDI = getOrCreateType(WrappedTy, Unit); + if (!WrappedDI) + WrappedDI = DBuilder.createUnspecifiedType("void"); + + // Stripping local CVR qualifiers might not be enough in cases like this: + // + // #define __tag __attribute__((btf_type_tag("tag"))) + // const int *foo; + // const int *bar(void) { + // return (typeof(*foo) __tag *)(0); + // } + // + // Here the AST looks like: + // + // BTFTagAttributedType + // | 'typeof (*foo) __attribute__((btf_type_tag("tag")))' sugar + // `-TypeOfExprType 'typeof (*foo)' sugar + // |-ParenExpr 'const int' lvalue + // | `- ... + // `-QualType 'const int' const + // `-BuiltinType 'int' + // + // The BTFTagAttributedType is applied to TypeOfExpr. + // For TypeOfExpr the getOrCreateType(), would return instance of + // DIDerivedType with tag DW_TAG_const_type. + // + // To avoid repeating UnwrapTypeForDebugInfo() logic here just + // rebuild CVR metadata nodes if necessary. + // The above local CVR qualifiers processing is redundant, + // but avoids rebuilding metadata nodes in the most common case. + while (auto *DTy = dyn_cast(WrappedDI)) { + if (!retreiveCVR(DTy, Qc)) + break; + WrappedDI = DTy->getBaseType(); + } + + if (auto *DTy = dyn_cast(WrappedDI)) + if (isAnnotationsPlaceholder(DTy)) { + WrappedDI = DTy->getBaseType(); + for (llvm::Metadata *O : DTy->getAnnotations()->operands()) + Annotations.push_back(O); + } + + auto *Placeholder = DBuilder.createAnnotationsPlaceholder( + WrappedDI, DBuilder.getOrCreateArray(Annotations)); + AnnotationPlaceholders.push_back(Placeholder); + + return applyQualifiers(DBuilder, Placeholder, Qc); +} + llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty, QualType PointeeTy, @@ -1206,32 +1339,23 @@ llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag, CGM.getTarget().getDWARFAddressSpace( CGM.getTypes().getTargetAddressSpace(PointeeTy)); - SmallVector Annots; - auto *BTFAttrTy = dyn_cast(PointeeTy); - while (BTFAttrTy) { - StringRef Tag = BTFAttrTy->getAttr()->getBTFTypeTag(); - if (!Tag.empty()) { - llvm::Metadata *Ops[2] = { - llvm::MDString::get(CGM.getLLVMContext(), StringRef("btf_type_tag")), - llvm::MDString::get(CGM.getLLVMContext(), Tag)}; - Annots.insert(Annots.begin(), - llvm::MDNode::get(CGM.getLLVMContext(), Ops)); - } - BTFAttrTy = dyn_cast(BTFAttrTy->getWrappedType()); - } - llvm::DINodeArray Annotations = nullptr; - if (Annots.size() > 0) - Annotations = DBuilder.getOrCreateArray(Annots); + auto *BTFAttrTy = dyn_cast(PointeeTy.getTypePtr()); + if (!BTFTypeTagV2 && BTFAttrTy) { + SmallVector AnnotationsVec; + collectBTFTypeTagAnnotations(CGM.getLLVMContext(), DBuilder, AnnotationsVec, + BTFAttrTy, "btf_type_tag"); + Annotations = DBuilder.getOrCreateArray(AnnotationsVec); + } if (Tag == llvm::dwarf::DW_TAG_reference_type || Tag == llvm::dwarf::DW_TAG_rvalue_reference_type) return DBuilder.createReferenceType(Tag, getOrCreateType(PointeeTy, Unit), Size, Align, DWARFAddressSpace); - else - return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size, - Align, DWARFAddressSpace, StringRef(), - Annotations); + + return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size, + Align, DWARFAddressSpace, StringRef(), + Annotations); } llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name, @@ -3552,9 +3676,6 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { case Type::Attributed: T = cast(T)->getEquivalentType(); break; - case Type::BTFTagAttributed: - T = cast(T)->getWrappedType(); - break; case Type::CountAttributed: T = cast(T)->desugar(); break; @@ -3754,10 +3875,12 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { case Type::TemplateSpecialization: return CreateType(cast(Ty), Unit); + case Type::BTFTagAttributed: + return CreateType(cast(Ty), Unit); + case Type::CountAttributed: case Type::Auto: case Type::Attributed: - case Type::BTFTagAttributed: case Type::Adjusted: case Type::Decayed: case Type::DeducedTemplateSpecialization: @@ -5930,6 +6053,35 @@ void CGDebugInfo::setDwoId(uint64_t Signature) { TheCU->setDWOId(Signature); } +static llvm::DIType *copyAnnotations(llvm::DIBuilder &DBuilder, + llvm::DIDerivedType *Placeholder) { + auto *WrappedDI = Placeholder->getBaseType(); + SmallVector Annotations; + + for (const llvm::Metadata *O : Placeholder->getAnnotations()->operands()) + Annotations.push_back(const_cast(O)); + + auto AddAnnotations = [&](auto *Type) { + if (llvm::DINodeArray OldAnnotations = Type->getAnnotations()) + for (const llvm::Metadata *O : OldAnnotations->operands()) + Annotations.push_back(const_cast(O)); + auto Clone = Type->clone(); + Clone->replaceAnnotations(DBuilder.getOrCreateArray(Annotations)); + return llvm::MDNode::replaceWithPermanent(std::move(Clone)); + }; + + if (auto *Ty = dyn_cast(WrappedDI)) + return AddAnnotations(Ty); + if (auto *Ty = dyn_cast(WrappedDI)) + return AddAnnotations(Ty); + if (auto *Ty = dyn_cast(WrappedDI)) + return AddAnnotations(Ty); + if (auto *Ty = dyn_cast(WrappedDI)) + return AddAnnotations(Ty); + + return WrappedDI; +} + void CGDebugInfo::finalize() { // Creating types might create further types - invalidating the current // element and the size(), so don't cache/reference them. @@ -6003,6 +6155,10 @@ void CGDebugInfo::finalize() { if (auto MD = TypeCache[RT]) DBuilder.retainType(cast(MD)); + for (auto &Placeholder : AnnotationPlaceholders) + DBuilder.replaceTemporary(llvm::TempDIType(Placeholder), + copyAnnotations(DBuilder, Placeholder)); + DBuilder.finalize(); } diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 8fe738be21568..1f2f473cc190c 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -171,6 +171,8 @@ class CGDebugInfo { /// The key is coroutine real parameters, value is DIVariable in LLVM IR. Param2DILocTy ParamDbgMappings; + std::vector AnnotationPlaceholders; + /// Helper functions for getOrCreateType. /// @{ /// Currently the checksum of an interface includes the number of @@ -218,6 +220,7 @@ class CGDebugInfo { llvm::DIType *CreateType(const MemberPointerType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const AtomicType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const PipeType *Ty, llvm::DIFile *F); + llvm::DIType *CreateType(const BTFTagAttributedType *Ty, llvm::DIFile *F); /// Get enumeration type. llvm::DIType *CreateEnumType(const EnumType *Ty); llvm::DIType *CreateTypeDefinition(const EnumType *Ty); diff --git a/clang/test/CodeGen/attr-btf_type_tag-circular.c b/clang/test/CodeGen/attr-btf_type_tag-circular.c new file mode 100644 index 0000000000000..ca2a1a07fd4c8 --- /dev/null +++ b/clang/test/CodeGen/attr-btf_type_tag-circular.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \ +// RUN: -mllvm -btf-type-tag-v2 -emit-llvm -o - %s | FileCheck %s + +#define __tag1 __attribute__((btf_type_tag("tag1"))) + +struct st { + struct st __tag1 *self; +} g; + +// CHECK: distinct !DIGlobalVariable(name: "g", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L1:[0-9]+]], isLocal: false, isDefinition: true) +// CHECK: ![[L1]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "st", file: ![[#]], line: [[#]], size: [[#]], elements: ![[L2:[0-9]+]]) +// CHECK: ![[L2]] = !{![[L3:[0-9]+]]} +// CHECK: ![[L3]] = !DIDerivedType(tag: DW_TAG_member, name: "self", scope: ![[L1]], file: ![[#]], line: [[#]], baseType: ![[L4:[0-9]+]], size: [[#]]) +// CHECK: ![[L4]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L5:[0-9]+]], size: [[#]]) +// CHECK: ![[L5]] = !DICompositeType(tag: DW_TAG_structure_type, name: "st", file: ![[#]], line: [[#]], size: [[#]], elements: ![[L2]], annotations: ![[L7:[0-9]+]]) +// CHECK: ![[L7]] = !{![[L8:[0-9]+]]} +// CHECK: ![[L8]] = !{!"btf:type_tag", !"tag1"} diff --git a/clang/test/CodeGen/attr-btf_type_tag-const.c b/clang/test/CodeGen/attr-btf_type_tag-const.c new file mode 100644 index 0000000000000..5e25a95e91f5c --- /dev/null +++ b/clang/test/CodeGen/attr-btf_type_tag-const.c @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \ +// RUN: -mllvm -btf-type-tag-v2 -emit-llvm -o - %s | FileCheck %s + +// Check that BTF type tags are not attached to DW_TAG_const_type DIEs +// in presence of "sugar" expressions that are transparent for +// CGDebugInfo.cpp:UnwrapTypeForDebugInfo(), but are not transparent +// for local qualifiers. +// +// For details see: +// CGDebugInfo::CreateType(const BTFTagAttributedType, llvm::DIFile) + +#define __tag1 __attribute__((btf_type_tag("tag1"))) +#define __tag2 __attribute__((btf_type_tag("tag2"))) +#define __tag3 __attribute__((btf_type_tag("tag3"))) + +const int *foo; +typeof(*foo) __tag1 bar; + +// CHECK: distinct !DIGlobalVariable(name: "bar", {{.*}}, type: ![[L01:[0-9]+]], {{.*}}) +// CHECK: ![[L01]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L02:[0-9]+]]) +// CHECK: ![[L02]] = !DIBasicType(name: "int", {{.*}}, annotations: ![[L03:[0-9]+]]) +// CHECK: ![[L03]] = !{![[L04:[0-9]+]]} +// CHECK: ![[L04]] = !{!"btf:type_tag", !"tag1"} + +const int __tag2 *buz; + +// CHECK: distinct !DIGlobalVariable(name: "buz", {{.*}}, type: ![[L05:[0-9]+]], {{.*}}) +// CHECK: ![[L05]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L06:[0-9]+]], {{.*}}) +// CHECK: ![[L06]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L08:[0-9]+]]) +// CHECK: ![[L08]] = !DIBasicType(name: "int", size: [[#]], {{.*}}, annotations: ![[L09:[0-9]+]]) +// CHECK: ![[L09]] = !{![[L10:[0-9]+]]} +// CHECK: ![[L10]] = !{!"btf:type_tag", !"tag2"} + +typeof(*buz) __tag3 quux; + +// CHECK: distinct !DIGlobalVariable(name: "quux", {{.*}}, type: ![[L12:[0-9]+]], {{.*}}) +// CHECK: ![[L12]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L13:[0-9]+]]) +// CHECK: ![[L13]] = !DIBasicType(name: "int", {{.*}}, annotations: ![[L14:[0-9]+]]) +// CHECK: ![[L14]] = !{![[L15:[0-9]+]], ![[L10]]} +// CHECK: ![[L15]] = !{!"btf:type_tag", !"tag3"} diff --git a/clang/test/CodeGen/attr-btf_type_tag-func-ptr.c b/clang/test/CodeGen/attr-btf_type_tag-func-ptr.c index 26935c882a017..8567864692202 100644 --- a/clang/test/CodeGen/attr-btf_type_tag-func-ptr.c +++ b/clang/test/CodeGen/attr-btf_type_tag-func-ptr.c @@ -1,4 +1,8 @@ // RUN: %clang_cc1 -triple %itanium_abi_triple -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \ +// RUN: -mllvm -btf-type-tag-v2 -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefix CHECK-V2 %s struct t { int (__attribute__((btf_type_tag("rcu"))) *f)(); @@ -8,8 +12,13 @@ int foo(struct t *arg) { return arg->a; } -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "f" -// CHECK-SAME: baseType: ![[L18:[0-9]+]] -// CHECK: ![[L18]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[#]], size: [[#]], annotations: ![[L21:[0-9]+]]) -// CHECK: ![[L21]] = !{![[L22:[0-9]+]]} -// CHECK: ![[L22]] = !{!"btf_type_tag", !"rcu"} +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "f", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L1:[0-9]+]], size: [[#]]) +// CHECK: ![[L1]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[#]], size: [[#]], annotations: ![[L2:[0-9]+]]) +// CHECK: ![[L2]] = !{![[L3:[0-9]+]]} +// CHECK: ![[L3]] = !{!"btf_type_tag", !"rcu"} + +// CHECK-V2: !DIDerivedType(tag: DW_TAG_member, name: "f", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L1:[0-9]+]], size: [[#]]) +// CHECK-V2: ![[L1]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L2:[0-9]+]], size: [[#]]) +// CHECK-V2: ![[L2]] = !DISubroutineType(types: ![[#]], annotations: ![[L4:[0-9]+]]) +// CHECK-V2: ![[L4]] = !{![[L5:[0-9]+]]} +// CHECK-V2: ![[L5]] = !{!"btf:type_tag", !"rcu"} diff --git a/clang/test/CodeGen/attr-btf_type_tag-func.c b/clang/test/CodeGen/attr-btf_type_tag-func.c index dbb8864759148..890d3ab35428b 100644 --- a/clang/test/CodeGen/attr-btf_type_tag-func.c +++ b/clang/test/CodeGen/attr-btf_type_tag-func.c @@ -1,5 +1,17 @@ -// RUN: %clang_cc1 -triple %itanium_abi_triple -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s -// RUN: %clang_cc1 -triple %itanium_abi_triple -DDOUBLE_BRACKET_ATTRS=1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \ +// RUN: -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -DDOUBLE_BRACKET_ATTRS=1 -debug-info-kind=limited \ +// RUN: -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \ +// RUN: -mllvm -btf-type-tag-v2 -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes CHECK-V2 %s +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -DDOUBLE_BRACKET_ATTRS=1 \ +// RUN: -debug-info-kind=limited -mllvm -btf-type-tag-v2 -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes CHECK-V2 %s #if DOUBLE_BRACKET_ATTRS #define __tag1 [[clang::btf_type_tag("tag1")]] @@ -15,14 +27,26 @@ int __tag1 * __tag2 *foo(int __tag1 * __tag2 *arg) { return arg; } -// CHECK: distinct !DISubprogram(name: "foo", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L9:[0-9]+]] -// CHECK: ![[L9]] = !DISubroutineType(types: ![[L10:[0-9]+]] -// CHECK: ![[L10]] = !{![[L11:[0-9]+]], ![[L11]]} -// CHECK: ![[L11]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L12:[0-9]+]], size: [[#]], annotations: ![[L16:[0-9]+]] -// CHECK: ![[L12]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L13:[0-9]+]], size: [[#]], annotations: ![[L14:[0-9]+]] -// CHECK: ![[L13]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed -// CHECK: ![[L14]] = !{![[L15:[0-9]+]]} -// CHECK: ![[L15]] = !{!"btf_type_tag", !"tag1"} -// CHECK: ![[L16]] = !{![[L17:[0-9]+]]} -// CHECK: ![[L17]] = !{!"btf_type_tag", !"tag2"} -// CHECK: !DILocalVariable(name: "arg", arg: 1, scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L11]]) +// CHECK: distinct !DISubprogram(name: "foo", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L01:[0-9]+]], {{.*}}) +// CHECK: ![[L01]] = !DISubroutineType(types: ![[L02:[0-9]+]]) +// CHECK: ![[L02]] = !{![[L03:[0-9]+]], ![[L03]]} +// CHECK: ![[L03]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L04:[0-9]+]], size: [[#]], annotations: ![[L05:[0-9]+]]) +// CHECK: ![[L04]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L06:[0-9]+]], size: [[#]], annotations: ![[L07:[0-9]+]]) +// CHECK: ![[L06]] = !DIBasicType(name: "int", size: [[#]], encoding: DW_ATE_signed) +// CHECK: ![[L07]] = !{![[L11:[0-9]+]]} +// CHECK: ![[L11]] = !{!"btf_type_tag", !"tag1"} +// CHECK: ![[L05]] = !{![[L12:[0-9]+]]} +// CHECK: ![[L12]] = !{!"btf_type_tag", !"tag2"} +// CHECK: !DILocalVariable(name: "arg", arg: 1, scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L03]]) + +// CHECK-V2: distinct !DISubprogram(name: "foo", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L01:[0-9]+]], {{.*}}) +// CHECK-V2: ![[L01]] = !DISubroutineType(types: ![[L02:[0-9]+]]) +// CHECK-V2: ![[L02]] = !{![[L03:[0-9]+]], ![[L03]]} +// CHECK-V2: ![[L03]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L04:[0-9]+]], size: [[#]]) +// CHECK-V2: ![[L04]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L06:[0-9]+]], size: [[#]], annotations: ![[L07:[0-9]+]]) +// CHECK-V2: ![[L06]] = !DIBasicType(name: "int", size: [[#]], encoding: DW_ATE_signed, annotations: ![[L08:[0-9]+]]) +// CHECK-V2: ![[L08]] = !{![[L09:[0-9]+]]} +// CHECK-V2: ![[L09]] = !{!"btf:type_tag", !"tag1"} +// CHECK-V2: ![[L07]] = !{![[L10:[0-9]+]]} +// CHECK-V2: ![[L10]] = !{!"btf:type_tag", !"tag2"} +// CHECK-V2: !DILocalVariable(name: "arg", arg: 1, scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L03]]) diff --git a/clang/test/CodeGen/attr-btf_type_tag-restrict.c b/clang/test/CodeGen/attr-btf_type_tag-restrict.c new file mode 100644 index 0000000000000..ce25fbcae41a1 --- /dev/null +++ b/clang/test/CodeGen/attr-btf_type_tag-restrict.c @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \ +// RUN: -mllvm -btf-type-tag-v2 -emit-llvm -o - %s | FileCheck %s + +// See attr-btf_type_tag-const.c for reasoning behind this test. +// Alternatively, see the following method: +// CGDebugInfo::CreateType(const BTFTagAttributedType, llvm::DIFile) + +#define __tag1 __attribute__((btf_type_tag("tag1"))) + +void foo(int * restrict bar, typeof(bar) __tag1 buz) {} + +// CHECK: ![[#]] = !DISubroutineType(types: ![[L1:[0-9]+]]) +// CHECK: ![[L1]] = !{null, ![[L2:[0-9]+]], ![[L3:[0-9]+]]} +// CHECK: ![[L2]] = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: ![[L4:[0-9]+]]) +// CHECK: ![[L4]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L5:[0-9]+]], {{.*}}) +// CHECK: ![[L5]] = !DIBasicType(name: "int", {{.*}}, encoding: DW_ATE_signed) +// CHECK: ![[L3]] = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: ![[L6:[0-9]+]]) +// CHECK: ![[L6]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L5]], {{.*}}, annotations: ![[L7:[0-9]+]]) +// CHECK: ![[L7]] = !{![[L8:[0-9]+]]} +// CHECK: ![[L8]] = !{!"btf:type_tag", !"tag1"} diff --git a/clang/test/CodeGen/attr-btf_type_tag-similar-type.c b/clang/test/CodeGen/attr-btf_type_tag-similar-type.c index 3960d6f5c93fb..25a99c076619b 100644 --- a/clang/test/CodeGen/attr-btf_type_tag-similar-type.c +++ b/clang/test/CodeGen/attr-btf_type_tag-similar-type.c @@ -1,4 +1,9 @@ -// RUN: %clang_cc1 -triple %itanium_abi_triple -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \ +// RUN: -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \ +// RUN: -mllvm -btf-type-tag-v2 -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK-V2 %s struct map_value { int __attribute__((btf_type_tag("tag1"))) __attribute__((btf_type_tag("tag3"))) *a; @@ -12,15 +17,31 @@ int test(struct map_value *arg) return *arg->a; } -// CHECK: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "map_value", file: ![[#]], line: [[#]], size: [[#]], elements: ![[L14:[0-9]+]] -// CHECK: ![[L14]] = !{![[L15:[0-9]+]], ![[L20:[0-9]+]]} -// CHECK: ![[L15]] = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L16:[0-9]+]] -// CHECK: ![[L16]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[#]], size: [[#]], annotations: ![[L17:[0-9]+]] -// CHECK: ![[L17]] = !{![[L18:[0-9]+]], ![[L19:[0-9]+]]} -// CHECK: ![[L18]] = !{!"btf_type_tag", !"tag1"} -// CHECK: ![[L19]] = !{!"btf_type_tag", !"tag3"} -// CHECK: ![[L20]] = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L21:[0-9]+]] -// CHECK: ![[L21:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[#]], size: [[#]], annotations: ![[L22:[0-9]+]] -// CHECK: ![[L22]] = !{![[L23:[0-9]+]], ![[L24:[0-9]+]]} -// CHECK: ![[L23]] = !{!"btf_type_tag", !"tag2"} -// CHECK: ![[L24]] = !{!"btf_type_tag", !"tag4"} +// CHECK: ![[L05:[0-9]+]] = !DIBasicType(name: "int", size: [[#]], encoding: DW_ATE_signed) +// CHECK: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "map_value", file: ![[#]], line: [[#]], size: [[#]], elements: ![[L01:[0-9]+]]) +// CHECK: ![[L01]] = !{![[L02:[0-9]+]], ![[L03:[0-9]+]]} +// CHECK: ![[L02]] = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L04:[0-9]+]], size: [[#]]) +// CHECK: ![[L04]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L05]], size: [[#]], annotations: ![[L06:[0-9]+]]) +// CHECK: ![[L06]] = !{![[L10:[0-9]+]], ![[L11:[0-9]+]]} +// CHECK: ![[L10]] = !{!"btf_type_tag", !"tag1"} +// CHECK: ![[L11]] = !{!"btf_type_tag", !"tag3"} +// CHECK: ![[L03]] = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L12:[0-9]+]], size: [[#]], offset: [[#]]) +// CHECK: ![[L12]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L05]], size: [[#]], annotations: ![[L14:[0-9]+]]) +// CHECK: ![[L14]] = !{![[L18:[0-9]+]], ![[L19:[0-9]+]]} +// CHECK: ![[L18]] = !{!"btf_type_tag", !"tag2"} +// CHECK: ![[L19]] = !{!"btf_type_tag", !"tag4"} + +// CHECK-V2: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "map_value", file: ![[#]], line: [[#]], size: [[#]], elements: ![[L01:[0-9]+]]) +// CHECK-V2: ![[L01]] = !{![[L02:[0-9]+]], ![[L03:[0-9]+]]} +// CHECK-V2: ![[L02]] = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L04:[0-9]+]], size: [[#]]) +// CHECK-V2: ![[L04]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L05:[0-9]+]], size: [[#]]) +// CHECK-V2: ![[L05]] = !DIBasicType(name: "int", size: [[#]], encoding: DW_ATE_signed, annotations: ![[L07:[0-9]+]]) +// CHECK-V2: ![[L07]] = !{![[L08:[0-9]+]], ![[L09:[0-9]+]]} +// CHECK-V2: ![[L08]] = !{!"btf:type_tag", !"tag1"} +// CHECK-V2: ![[L09]] = !{!"btf:type_tag", !"tag3"} +// CHECK-V2: ![[L03]] = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L12:[0-9]+]], size: [[#]], offset: [[#]]) +// CHECK-V2: ![[L12]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L13:[0-9]+]], size: [[#]]) +// CHECK-V2: ![[L13]] = !DIBasicType(name: "int", size: [[#]], encoding: DW_ATE_signed, annotations: ![[L15:[0-9]+]]) +// CHECK-V2: ![[L15]] = !{![[L16:[0-9]+]], ![[L17:[0-9]+]]} +// CHECK-V2: ![[L16]] = !{!"btf:type_tag", !"tag2"} +// CHECK-V2: ![[L17]] = !{!"btf:type_tag", !"tag4"} diff --git a/clang/test/CodeGen/attr-btf_type_tag-typedef-field.c b/clang/test/CodeGen/attr-btf_type_tag-typedef-field.c index 5c8955fbf89a8..ceb4e83aa428b 100644 --- a/clang/test/CodeGen/attr-btf_type_tag-typedef-field.c +++ b/clang/test/CodeGen/attr-btf_type_tag-typedef-field.c @@ -1,4 +1,9 @@ -// RUN: %clang_cc1 -triple %itanium_abi_triple -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \ +// RUN: -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \ +// RUN: -mllvm -btf-type-tag-v2 -emit-llvm -o - %s | FileCheck %s --check-prefixes CHECK-V2 #define __tag1 __attribute__((btf_type_tag("tag1"))) #define __tag2 __attribute__((btf_type_tag("tag2"))) @@ -14,22 +19,43 @@ int *foo1(struct t *a1) { return (int *)a1->c; } -// CHECK: ![[L4:[0-9]+]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) -// CHECK: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: ![[#]], line: [[#]], size: [[#]], elements: ![[L16:[0-9]+]]) -// CHECK: ![[L16]] = !{![[L17:[0-9]+]], ![[L24:[0-9]+]], ![[L31:[0-9]+]]} -// CHECK: ![[L17]] = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L18:[0-9]+]], size: [[#]]) -// CHECK: ![[L18]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L19:[0-9]+]], size: [[#]], annotations: ![[L22:[0-9]+]]) -// CHECK: ![[L19]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L4]], size: [[#]], annotations: ![[L20:[0-9]+]]) -// CHECK: ![[L20]] = !{![[L21:[0-9]+]]} -// CHECK: ![[L21]] = !{!"btf_type_tag", !"tag1"} -// CHECK: ![[L22]] = !{![[L23:[0-9]+]]} -// CHECK: ![[L23]] = !{!"btf_type_tag", !"tag2"} -// CHECK: ![[L24]] = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L25:[0-9]+]] -// CHECK: ![[L25]] = !DIDerivedType(tag: DW_TAG_typedef, name: "__fn2_t", file: ![[#]], line: [[#]], baseType: ![[L26:[0-9]+]]) -// CHECK: ![[L26]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L27:[0-9]+]], size: [[#]], annotations: ![[L30:[0-9]+]]) -// CHECK: ![[L27]] = !DIDerivedType(tag: DW_TAG_typedef, name: "__fn_t", file: ![[#]], line: [[#]], baseType: ![[L28:[0-9]+]]) -// CHECK: ![[L28]] = !DISubroutineType(types: ![[L29:[0-9]+]]) -// CHECK: ![[L29]] = !{null, ![[L4]]} -// CHECK: ![[L30]] = !{![[L21]], ![[L23]]} -// CHECK: ![[L31]] = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: ![[#]], file: ![[#]], line: [[#]]1, baseType: ![[L32:[0-9]+]] -// CHECK: ![[L32]] = !DIBasicType(name: "long", size: [[#]], encoding: DW_ATE_signed) +// CHECK: ![[L01:[0-9]+]] = !DIBasicType(name: "int", size: [[#]], encoding: DW_ATE_signed) +// CHECK: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: ![[#]], line: [[#]], size: [[#]], elements: ![[L02:[0-9]+]]) +// CHECK: ![[L02]] = !{![[L03:[0-9]+]], ![[L04:[0-9]+]], ![[L05:[0-9]+]]} +// CHECK: ![[L03]] = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L06:[0-9]+]], size: [[#]]) +// CHECK: ![[L06]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L07:[0-9]+]], size: [[#]], annotations: ![[L08:[0-9]+]]) +// CHECK: ![[L07]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L01]], size: [[#]], annotations: ![[L10:[0-9]+]]) +// CHECK: ![[L10]] = !{![[L14:[0-9]+]]} +// CHECK: ![[L14]] = !{!"btf_type_tag", !"tag1"} +// CHECK: ![[L08]] = !{![[L15:[0-9]+]]} +// CHECK: ![[L15]] = !{!"btf_type_tag", !"tag2"} +// CHECK: ![[L04]] = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L16:[0-9]+]], size: [[#]], offset: [[#]]) +// CHECK: ![[L16]] = !DIDerivedType(tag: DW_TAG_typedef, name: "__fn2_t", file: ![[#]], line: [[#]], baseType: ![[L17:[0-9]+]]) +// CHECK: ![[L17]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L18:[0-9]+]], size: [[#]], annotations: ![[L19:[0-9]+]]) +// CHECK: ![[L18]] = !DIDerivedType(tag: DW_TAG_typedef, name: "__fn_t", file: ![[#]], line: [[#]], baseType: ![[L20:[0-9]+]]) +// CHECK: ![[L20]] = !DISubroutineType(types: ![[L22:[0-9]+]]) +// CHECK: ![[L22]] = !{null, ![[L01]]} +// CHECK: ![[L19]] = !{![[L14]], ![[L15]]} +// CHECK: ![[L05]] = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L23:[0-9]+]], size: [[#]], offset: [[#]]) +// CHECK: ![[L23]] = !DIBasicType(name: "long", size: [[#]], encoding: DW_ATE_signed) + +// CHECK-V2: ![[L01:[0-9]+]] = !DIBasicType(name: "int", size: [[#]], encoding: DW_ATE_signed) +// CHECK-V2: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: ![[#]], line: [[#]], size: [[#]], elements: ![[L02:[0-9]+]]) +// CHECK-V2: ![[L02]] = !{![[L03:[0-9]+]], ![[L04:[0-9]+]], ![[L05:[0-9]+]]} +// CHECK-V2: ![[L03]] = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L06:[0-9]+]], size: [[#]]) +// CHECK-V2: ![[L06]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L07:[0-9]+]], size: [[#]]) +// CHECK-V2: ![[L07]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L09:[0-9]+]], size: [[#]], annotations: ![[L08:[0-9]+]]) +// CHECK-V2: ![[L09]] = !DIBasicType(name: "int", size: [[#]], encoding: DW_ATE_signed, annotations: ![[L10:[0-9]+]]) +// CHECK-V2: ![[L10]] = !{![[L14:[0-9]+]]} +// CHECK-V2: ![[L14]] = !{!"btf:type_tag", !"tag1"} +// CHECK-V2: ![[L08]] = !{![[L15:[0-9]+]]} +// CHECK-V2: ![[L15]] = !{!"btf:type_tag", !"tag2"} +// CHECK-V2: ![[L04]] = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L16:[0-9]+]], size: [[#]], offset: [[#]]) +// CHECK-V2: ![[L16]] = !DIDerivedType(tag: DW_TAG_typedef, name: "__fn2_t", file: ![[#]], line: [[#]], baseType: ![[L17:[0-9]+]]) +// CHECK-V2: ![[L17]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L18:[0-9]+]], size: [[#]]) +// CHECK-V2: ![[L18]] = !DIDerivedType(tag: DW_TAG_typedef, name: "__fn_t", file: ![[#]], line: [[#]], baseType: ![[L20:[0-9]+]], annotations: ![[L19:[0-9]+]]) +// CHECK-V2: ![[L20]] = !DISubroutineType(types: ![[L22:[0-9]+]]) +// CHECK-V2: ![[L22]] = !{null, ![[L01]]} +// CHECK-V2: ![[L19]] = !{![[L14]], ![[L15]]} +// CHECK-V2: ![[L05]] = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L23:[0-9]+]], size: [[#]], offset: [[#]]) +// CHECK-V2: ![[L23]] = !DIBasicType(name: "long", size: [[#]], encoding: DW_ATE_signed) diff --git a/clang/test/CodeGen/attr-btf_type_tag-var.c b/clang/test/CodeGen/attr-btf_type_tag-var.c index ed729e245fbcb..eca61b8742fb1 100644 --- a/clang/test/CodeGen/attr-btf_type_tag-var.c +++ b/clang/test/CodeGen/attr-btf_type_tag-var.c @@ -1,5 +1,17 @@ -// RUN: %clang_cc1 -triple %itanium_abi_triple -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s -// RUN: %clang_cc1 -triple %itanium_abi_triple -DDOUBLE_BRACKET_ATTRS=1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \ +// RUN: -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -DDOUBLE_BRACKET_ATTRS=1 \ +// RUN: -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \ +// RUN: -mllvm -btf-type-tag-v2 -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes CHECK-V2 %s +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -DDOUBLE_BRACKET_ATTRS=1 -debug-info-kind=limited \ +// RUN: -mllvm -btf-type-tag-v2 -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes CHECK-V2 %s #if DOUBLE_BRACKET_ATTRS #define __tag1 [[clang::btf_type_tag("tag1")]] @@ -21,23 +33,44 @@ const volatile int __tag1 __tag2 * __tag3 __tag4 const volatile * __tag5 __tag6 const int __tag1 __tag2 volatile * const __tag3 __tag4 volatile * __tag5 __tag6 const volatile * g; #endif -// CHECK: distinct !DIGlobalVariable(name: "g", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L6:[0-9]+]] -// CHECK: ![[L6]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L7:[0-9]+]], size: [[#]], annotations: ![[L22:[0-9]+]] -// CHECK: ![[L7]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L8:[0-9]+]] -// CHECK: ![[L8]] = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: ![[L9:[0-9]+]] -// CHECK: ![[L9]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L10:[0-9]+]], size: [[#]], annotations: ![[L19:[0-9]+]] -// CHECK: ![[L10]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L11:[0-9]+]] -// CHECK: ![[L11]] = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: ![[L12:[0-9]+]] -// CHECK: ![[L12]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L13:[0-9]+]], size: [[#]], annotations: ![[L16:[0-9]+]] -// CHECK: ![[L13]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L14:[0-9]+]] -// CHECK: ![[L14]] = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: ![[L15:[0-9]+]] -// CHECK: ![[L15]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed -// CHECK: ![[L16]] = !{![[L17:[0-9]+]], ![[L18:[0-9]+]]} -// CHECK: ![[L17]] = !{!"btf_type_tag", !"tag1"} -// CHECK: ![[L18]] = !{!"btf_type_tag", !"tag2"} -// CHECK: ![[L19]] = !{![[L20:[0-9]+]], ![[L21:[0-9]+]]} -// CHECK: ![[L20]] = !{!"btf_type_tag", !"tag3"} -// CHECK: ![[L21]] = !{!"btf_type_tag", !"tag4"} -// CHECK: ![[L22]] = !{![[L23:[0-9]+]], ![[L24:[0-9]+]]} -// CHECK: ![[L23]] = !{!"btf_type_tag", !"tag5"} -// CHECK: ![[L24]] = !{!"btf_type_tag", !"tag6"} +// CHECK: distinct !DIGlobalVariable(name: "g", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L01:[0-9]+]], isLocal: false, isDefinition: true) +// CHECK: ![[L01]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L02:[0-9]+]], size: [[#]], annotations: ![[L03:[0-9]+]]) +// CHECK: ![[L02]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L04:[0-9]+]]) +// CHECK: ![[L04]] = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: ![[L05:[0-9]+]]) +// CHECK: ![[L05]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L06:[0-9]+]], size: [[#]], annotations: ![[L07:[0-9]+]]) +// CHECK: ![[L06]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L08:[0-9]+]]) +// CHECK: ![[L08]] = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: ![[L09:[0-9]+]]) +// CHECK: ![[L09]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L10:[0-9]+]], size: [[#]], annotations: ![[L11:[0-9]+]]) +// CHECK: ![[L10]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L12:[0-9]+]]) +// CHECK: ![[L12]] = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: ![[L13:[0-9]+]]) +// CHECK: ![[L13]] = !DIBasicType(name: "int", size: [[#]], encoding: DW_ATE_signed) +// CHECK: ![[L11]] = !{![[L19:[0-9]+]], ![[L20:[0-9]+]]} +// CHECK: ![[L19]] = !{!"btf_type_tag", !"tag1"} +// CHECK: ![[L20]] = !{!"btf_type_tag", !"tag2"} +// CHECK: ![[L07]] = !{![[L23:[0-9]+]], ![[L24:[0-9]+]]} +// CHECK: ![[L23]] = !{!"btf_type_tag", !"tag3"} +// CHECK: ![[L24]] = !{!"btf_type_tag", !"tag4"} +// CHECK: ![[L03]] = !{![[L25:[0-9]+]], ![[L26:[0-9]+]]} +// CHECK: ![[L25]] = !{!"btf_type_tag", !"tag5"} +// CHECK: ![[L26]] = !{!"btf_type_tag", !"tag6"} + +// CHECK-V2: distinct !DIGlobalVariable(name: "g", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L01:[0-9]+]], isLocal: false, isDefinition: true) +// CHECK-V2: ![[L01]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L02:[0-9]+]], size: [[#]]) +// CHECK-V2: ![[L02]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L04:[0-9]+]]) +// CHECK-V2: ![[L04]] = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: ![[L05:[0-9]+]]) +// CHECK-V2: ![[L05]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L06:[0-9]+]], size: [[#]], annotations: ![[L07:[0-9]+]]) +// CHECK-V2: ![[L06]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L08:[0-9]+]]) +// CHECK-V2: ![[L08]] = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: ![[L09:[0-9]+]]) +// CHECK-V2: ![[L09]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L10:[0-9]+]], size: [[#]], annotations: ![[L11:[0-9]+]]) +// CHECK-V2: ![[L10]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L12:[0-9]+]]) +// CHECK-V2: ![[L12]] = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: ![[L13:[0-9]+]]) +// CHECK-V2: ![[L13]] = !DIBasicType(name: "int", size: [[#]], encoding: DW_ATE_signed, annotations: ![[L14:[0-9]+]]) +// CHECK-V2: ![[L14]] = !{![[L15:[0-9]+]], ![[L16:[0-9]+]]} +// CHECK-V2: ![[L15]] = !{!"btf:type_tag", !"tag1"} +// CHECK-V2: ![[L16]] = !{!"btf:type_tag", !"tag2"} +// CHECK-V2: ![[L11]] = !{![[L17:[0-9]+]], ![[L18:[0-9]+]]} +// CHECK-V2: ![[L17]] = !{!"btf:type_tag", !"tag3"} +// CHECK-V2: ![[L18]] = !{!"btf:type_tag", !"tag4"} +// CHECK-V2: ![[L07]] = !{![[L21:[0-9]+]], ![[L22:[0-9]+]]} +// CHECK-V2: ![[L21]] = !{!"btf:type_tag", !"tag5"} +// CHECK-V2: ![[L22]] = !{!"btf:type_tag", !"tag6"} diff --git a/clang/test/CodeGen/attr-btf_type_tag-void.c b/clang/test/CodeGen/attr-btf_type_tag-void.c new file mode 100644 index 0000000000000..0f580f0119e10 --- /dev/null +++ b/clang/test/CodeGen/attr-btf_type_tag-void.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \ +// RUN: -mllvm -btf-type-tag-v2 -emit-llvm -o - %s | FileCheck %s + +#define __tag1 __attribute__((btf_type_tag("tag1"))) +void __tag1 *g; + +// CHECK: distinct !DIGlobalVariable(name: "g", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L1:[0-9]+]], isLocal: false, isDefinition: true) +// CHECK: ![[L1]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L2:[0-9]+]], size: [[#]]) +// CHECK: ![[L2]] = !DIBasicType(tag: DW_TAG_unspecified_type, name: "void", annotations: ![[L4:[0-9]+]]) +// CHECK: ![[L4]] = !{![[L5:[0-9]+]]} +// CHECK: ![[L5]] = !{!"btf:type_tag", !"tag1"} diff --git a/clang/test/CodeGen/attr-btf_type_tag-volatile.c b/clang/test/CodeGen/attr-btf_type_tag-volatile.c new file mode 100644 index 0000000000000..109e42167107c --- /dev/null +++ b/clang/test/CodeGen/attr-btf_type_tag-volatile.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 \ +// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \ +// RUN: -mllvm -btf-type-tag-v2 -emit-llvm -o - %s | FileCheck %s + +// See attr-btf_type_tag-const.c for reasoning behind this test. +// Alternatively, see the following method: +// CGDebugInfo::CreateType(const BTFTagAttributedType, llvm::DIFile) + +#define __tag1 __attribute__((btf_type_tag("tag1"))) + +volatile int foo; +typeof(foo) __tag1 bar; + +// CHECK: ![[#]] = distinct !DIGlobalVariable(name: "bar", {{.*}}, type: ![[L1:[0-9]+]], {{.*}}) +// CHECK: ![[L1]] = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: ![[L2:[0-9]+]]) +// CHECK: ![[L2]] = !DIBasicType(name: "int", size: [[#]], {{.*}}, annotations: ![[L3:[0-9]+]]) +// CHECK: ![[L3]] = !{![[L4:[0-9]+]]} +// CHECK: ![[L4]] = !{!"btf:type_tag", !"tag1"} diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index 97ea38f041baa..03d16a1a2ad07 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -328,6 +328,9 @@ namespace llvm { DINode::DIFlags Flags = DINode::FlagZero, DINodeArray Annotations = nullptr); + DIDerivedType *createAnnotationsPlaceholder(DIType *Ty, + DINodeArray Annotations); + /// Create debugging information entry for a 'friend'. DIDerivedType *createFriend(DIType *Ty, DIType *FriendTy); diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index c15d64b842293..d87cb3d27e752 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -828,40 +828,45 @@ class DIBasicType : public DIType { static DIBasicType *getImpl(LLVMContext &Context, unsigned Tag, StringRef Name, uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, - DIFlags Flags, StorageType Storage, - bool ShouldCreate = true) { + DIFlags Flags, DINodeArray Annotations, + StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Tag, getCanonicalMDString(Context, Name), - SizeInBits, AlignInBits, Encoding, Flags, Storage, - ShouldCreate); + SizeInBits, AlignInBits, Encoding, Flags, Annotations.get(), + Storage, ShouldCreate); } static DIBasicType *getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, - DIFlags Flags, StorageType Storage, - bool ShouldCreate = true); + DIFlags Flags, Metadata *Annotations, + StorageType Storage, bool ShouldCreate = true); TempDIBasicType cloneImpl() const { return getTemporary(getContext(), getTag(), getName(), getSizeInBits(), - getAlignInBits(), getEncoding(), getFlags()); + getAlignInBits(), getEncoding(), getFlags(), + getAnnotations()); } public: DEFINE_MDNODE_GET(DIBasicType, (unsigned Tag, StringRef Name), - (Tag, Name, 0, 0, 0, FlagZero)) + (Tag, Name, 0, 0, 0, FlagZero, {})) DEFINE_MDNODE_GET(DIBasicType, (unsigned Tag, StringRef Name, uint64_t SizeInBits), - (Tag, Name, SizeInBits, 0, 0, FlagZero)) + (Tag, Name, SizeInBits, 0, 0, FlagZero, {})) DEFINE_MDNODE_GET(DIBasicType, (unsigned Tag, MDString *Name, uint64_t SizeInBits), - (Tag, Name, SizeInBits, 0, 0, FlagZero)) + (Tag, Name, SizeInBits, 0, 0, FlagZero, {})) DEFINE_MDNODE_GET(DIBasicType, (unsigned Tag, StringRef Name, uint64_t SizeInBits, - uint32_t AlignInBits, unsigned Encoding, DIFlags Flags), - (Tag, Name, SizeInBits, AlignInBits, Encoding, Flags)) + uint32_t AlignInBits, unsigned Encoding, DIFlags Flags, + DINodeArray Annotations = {}), + (Tag, Name, SizeInBits, AlignInBits, Encoding, Flags, + Annotations)) DEFINE_MDNODE_GET(DIBasicType, (unsigned Tag, MDString *Name, uint64_t SizeInBits, - uint32_t AlignInBits, unsigned Encoding, DIFlags Flags), - (Tag, Name, SizeInBits, AlignInBits, Encoding, Flags)) + uint32_t AlignInBits, unsigned Encoding, DIFlags Flags, + Metadata *Annotations = nullptr), + (Tag, Name, SizeInBits, AlignInBits, Encoding, Flags, + Annotations)) TempDIBasicType clone() const { return cloneImpl(); } @@ -873,6 +878,16 @@ class DIBasicType : public DIType { /// neither signed nor unsigned. std::optional getSignedness() const; + Metadata *getRawAnnotations() const { return getOperand(3); } + + DINodeArray getAnnotations() const { + return cast_or_null(getRawAnnotations()); + } + + void replaceAnnotations(DINodeArray Annotations) { + replaceOperandWith(3, Annotations.get()); + } + static bool classof(const Metadata *MD) { return MD->getMetadataID() == DIBasicTypeKind; } @@ -1112,6 +1127,10 @@ class DIDerivedType : public DIType { } Metadata *getRawAnnotations() const { return getOperand(5); } + void replaceAnnotations(DINodeArray Annotations) { + replaceOperandWith(5, Annotations.get()); + } + /// Get casted version of extra data. /// @{ DIType *getClassType() const; @@ -1339,6 +1358,10 @@ class DICompositeType : public DIType { return cast_or_null(getRawAnnotations()); } + void replaceAnnotations(DINodeArray Annotations) { + replaceOperandWith(13, Annotations.get()); + } + /// Replace operands. /// /// If this \a isUniqued() and not \a isResolved(), on a uniquing collision @@ -1385,26 +1408,30 @@ class DISubroutineType : public DIType { static DISubroutineType *getImpl(LLVMContext &Context, DIFlags Flags, uint8_t CC, DITypeRefArray TypeArray, - StorageType Storage, + DINodeArray Annotations, StorageType Storage, bool ShouldCreate = true) { - return getImpl(Context, Flags, CC, TypeArray.get(), Storage, ShouldCreate); + return getImpl(Context, Flags, CC, TypeArray.get(), Annotations.get(), + Storage, ShouldCreate); } static DISubroutineType *getImpl(LLVMContext &Context, DIFlags Flags, uint8_t CC, Metadata *TypeArray, - StorageType Storage, + Metadata *Annotations, StorageType Storage, bool ShouldCreate = true); TempDISubroutineType cloneImpl() const { - return getTemporary(getContext(), getFlags(), getCC(), getTypeArray()); + return getTemporary(getContext(), getFlags(), getCC(), getTypeArray(), + getAnnotations()); } public: DEFINE_MDNODE_GET(DISubroutineType, - (DIFlags Flags, uint8_t CC, DITypeRefArray TypeArray), - (Flags, CC, TypeArray)) + (DIFlags Flags, uint8_t CC, DITypeRefArray TypeArray, + DINodeArray Annotations = nullptr), + (Flags, CC, TypeArray, Annotations)) DEFINE_MDNODE_GET(DISubroutineType, - (DIFlags Flags, uint8_t CC, Metadata *TypeArray), - (Flags, CC, TypeArray)) + (DIFlags Flags, uint8_t CC, Metadata *TypeArray, + Metadata *Annotations = nullptr), + (Flags, CC, TypeArray, Annotations)) TempDISubroutineType clone() const { return cloneImpl(); } // Returns a new temporary DISubroutineType with updated CC @@ -1422,6 +1449,15 @@ class DISubroutineType : public DIType { Metadata *getRawTypeArray() const { return getOperand(3); } + Metadata *getRawAnnotations() const { return getOperand(4); } + DINodeArray getAnnotations() const { + return cast_or_null(getRawAnnotations()); + } + + void replaceAnnotations(DINodeArray Annotations) { + replaceOperandWith(4, Annotations.get()); + } + static bool classof(const Metadata *MD) { return MD->getMetadataID() == DISubroutineTypeKind; } diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index f0fde9ae4df5c..2cf54448597d9 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -5252,7 +5252,7 @@ bool LLParser::parseDIEnumerator(MDNode *&Result, bool IsDistinct) { /// parseDIBasicType: /// ::= !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, -/// encoding: DW_ATE_encoding, flags: 0) +/// encoding: DW_ATE_encoding, flags: 0, annotations: !1) bool LLParser::parseDIBasicType(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ OPTIONAL(tag, DwarfTagField, (dwarf::DW_TAG_base_type)); \ @@ -5260,12 +5260,14 @@ bool LLParser::parseDIBasicType(MDNode *&Result, bool IsDistinct) { OPTIONAL(size, MDUnsignedField, (0, UINT64_MAX)); \ OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX)); \ OPTIONAL(encoding, DwarfAttEncodingField, ); \ - OPTIONAL(flags, DIFlagField, ); + OPTIONAL(flags, DIFlagField, ); \ + OPTIONAL(annotations, MDField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS - Result = GET_OR_DISTINCT(DIBasicType, (Context, tag.Val, name.Val, size.Val, - align.Val, encoding.Val, flags.Val)); + Result = GET_OR_DISTINCT(DIBasicType, + (Context, tag.Val, name.Val, size.Val, align.Val, + encoding.Val, flags.Val, annotations.Val)); return false; } @@ -5402,12 +5404,13 @@ bool LLParser::parseDISubroutineType(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ OPTIONAL(flags, DIFlagField, ); \ OPTIONAL(cc, DwarfCCField, ); \ - REQUIRED(types, MDField, ); + REQUIRED(types, MDField, ); \ + OPTIONAL(annotations, MDField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS - Result = GET_OR_DISTINCT(DISubroutineType, - (Context, flags.Val, cc.Val, types.Val)); + Result = GET_OR_DISTINCT(DISubroutineType, (Context, flags.Val, cc.Val, + types.Val, annotations.Val)); return false; } diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp index 9102f3a60cffc..bc06c55f1662c 100644 --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1527,7 +1527,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( break; } case bitc::METADATA_BASIC_TYPE: { - if (Record.size() < 6 || Record.size() > 7) + if (Record.size() < 6 || Record.size() > 8) return error("Invalid record"); IsDistinct = Record[0]; @@ -1535,10 +1535,14 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( ? static_cast(Record[6]) : DINode::FlagZero; + Metadata *Annotations = nullptr; + if (Record.size() > 7 && Record[7]) + Annotations = getMDOrNull(Record[7]); + MetadataList.assignValue( GET_OR_DISTINCT(DIBasicType, (Context, Record[1], getMDString(Record[2]), Record[3], - Record[4], Record[5], Flags)), + Record[4], Record[5], Flags, Annotations)), NextMetadataNo); NextMetadataNo++; break; @@ -1703,7 +1707,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( break; } case bitc::METADATA_SUBROUTINE_TYPE: { - if (Record.size() < 3 || Record.size() > 4) + if (Record.size() < 3 || Record.size() > 5) return error("Invalid record"); bool IsOldTypeRefArray = Record[0] < 2; unsigned CC = (Record.size() > 3) ? Record[3] : 0; @@ -1713,9 +1717,13 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( Metadata *Types = getMDOrNull(Record[2]); if (LLVM_UNLIKELY(IsOldTypeRefArray)) Types = MetadataList.upgradeTypeRefArray(Types); + Metadata *Annotations = nullptr; + if (Record.size() > 4 && Record[4]) + Annotations = getMDOrNull(Record[4]); MetadataList.assignValue( - GET_OR_DISTINCT(DISubroutineType, (Context, Flags, CC, Types)), + GET_OR_DISTINCT(DISubroutineType, + (Context, Flags, CC, Types, Annotations)), NextMetadataNo); NextMetadataNo++; break; diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index b08d5c50e5ae3..f3e87310310ec 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1816,6 +1816,7 @@ void ModuleBitcodeWriter::writeDIBasicType(const DIBasicType *N, Record.push_back(N->getAlignInBits()); Record.push_back(N->getEncoding()); Record.push_back(N->getFlags()); + Record.push_back(VE.getMetadataOrNullID(N->getRawAnnotations())); Stream.EmitRecord(bitc::METADATA_BASIC_TYPE, Record, Abbrev); Record.clear(); @@ -1911,6 +1912,7 @@ void ModuleBitcodeWriter::writeDISubroutineType( Record.push_back(N->getFlags()); Record.push_back(VE.getMetadataOrNullID(N->getTypeArray().get())); Record.push_back(N->getCC()); + Record.push_back(VE.getMetadataOrNullID(N->getRawAnnotations())); Stream.EmitRecord(bitc::METADATA_SUBROUTINE_TYPE, Record, Abbrev); Record.clear(); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 6c04fa1c67a95..08be3a51862ca 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -712,7 +712,9 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) { if (!Name.empty()) addString(Buffer, dwarf::DW_AT_name, Name); - // An unspecified type only has a name attribute. + addAnnotation(Buffer, BTy->getAnnotations()); + + // An unspecified type only has a name attribute & annotations. if (BTy->getTag() == dwarf::DW_TAG_unspecified_type) return; @@ -881,6 +883,8 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DISubroutineType *CTy) { if (CTy->isRValueReference()) addFlag(Buffer, dwarf::DW_AT_rvalue_reference); + + addAnnotation(Buffer, CTy->getAnnotations()); } void DwarfUnit::addAnnotation(DIE &Buffer, DINodeArray Annotations) { diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index 0bf8be9ac55f9..16e51307ddb71 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2122,9 +2122,9 @@ static void writeDIEnumerator(raw_ostream &Out, const DIEnumerator *N, } static void writeDIBasicType(raw_ostream &Out, const DIBasicType *N, - AsmWriterContext &) { + AsmWriterContext &WriterCtx) { Out << "!DIBasicType("; - MDFieldPrinter Printer(Out); + MDFieldPrinter Printer(Out, WriterCtx); if (N->getTag() != dwarf::DW_TAG_base_type) Printer.printTag(N); Printer.printString("name", N->getName()); @@ -2133,6 +2133,7 @@ static void writeDIBasicType(raw_ostream &Out, const DIBasicType *N, Printer.printDwarfEnum("encoding", N->getEncoding(), dwarf::AttributeEncodingString); Printer.printDIFlags("flags", N->getFlags()); + Printer.printMetadata("annotations", N->getRawAnnotations()); Out << ")"; } @@ -2228,6 +2229,7 @@ static void writeDISubroutineType(raw_ostream &Out, const DISubroutineType *N, Printer.printDwarfEnum("cc", N->getCC(), dwarf::ConventionString); Printer.printMetadata("types", N->getRawTypeArray(), /* ShouldSkipNull */ false); + Printer.printMetadata("annotations", N->getRawAnnotations()); Out << ")"; } diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index f39149ae0dad4..457de32a0507f 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -367,6 +367,17 @@ DIBuilder::createTemplateAlias(DIType *Ty, StringRef Name, DIFile *File, TParams.get(), Annotations); } +DIDerivedType * +DIBuilder::createAnnotationsPlaceholder(DIType *Ty, DINodeArray Annotations) { + auto *RetTy = DIDerivedType::getTemporary( + VMContext, dwarf::DW_TAG_LLVM_annotation, "", nullptr, 0, + nullptr, Ty, 0, 0, 0, std::nullopt, std::nullopt, + DINode::FlagZero, nullptr, Annotations) + .release(); + trackIfUnresolved(RetTy); + return RetTy; +} + DIDerivedType *DIBuilder::createFriend(DIType *Ty, DIType *FriendTy) { assert(Ty && "Invalid type!"); assert(FriendTy && "Invalid friend type!"); diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 2b45932093f0f..52d3a6c7d423c 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -663,12 +663,12 @@ DIEnumerator *DIEnumerator::getImpl(LLVMContext &Context, const APInt &Value, DIBasicType *DIBasicType::getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, - DIFlags Flags, StorageType Storage, - bool ShouldCreate) { + DIFlags Flags, Metadata *Annotations, + StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP(DIBasicType, - (Tag, Name, SizeInBits, AlignInBits, Encoding, Flags)); - Metadata *Ops[] = {nullptr, nullptr, Name}; + DEFINE_GETIMPL_LOOKUP(DIBasicType, (Tag, Name, SizeInBits, AlignInBits, + Encoding, Flags, Annotations)); + Metadata *Ops[] = {nullptr, nullptr, Name, Annotations}; DEFINE_GETIMPL_STORE(DIBasicType, (Tag, SizeInBits, AlignInBits, Encoding, Flags), Ops); } @@ -872,10 +872,11 @@ DISubroutineType::DISubroutineType(LLVMContext &C, StorageType Storage, DISubroutineType *DISubroutineType::getImpl(LLVMContext &Context, DIFlags Flags, uint8_t CC, Metadata *TypeArray, + Metadata *Annotations, StorageType Storage, bool ShouldCreate) { - DEFINE_GETIMPL_LOOKUP(DISubroutineType, (Flags, CC, TypeArray)); - Metadata *Ops[] = {nullptr, nullptr, nullptr, TypeArray}; + DEFINE_GETIMPL_LOOKUP(DISubroutineType, (Flags, CC, TypeArray, Annotations)); + Metadata *Ops[] = {nullptr, nullptr, nullptr, TypeArray, Annotations}; DEFINE_GETIMPL_STORE(DISubroutineType, (Flags, CC), Ops); } diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index 392e0d16f1761..8fb55d9c719d1 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -465,25 +465,29 @@ template <> struct MDNodeKeyImpl { uint32_t AlignInBits; unsigned Encoding; unsigned Flags; + Metadata *Annotations; MDNodeKeyImpl(unsigned Tag, MDString *Name, uint64_t SizeInBits, - uint32_t AlignInBits, unsigned Encoding, unsigned Flags) + uint32_t AlignInBits, unsigned Encoding, unsigned Flags, + Metadata *Annotations) : Tag(Tag), Name(Name), SizeInBits(SizeInBits), AlignInBits(AlignInBits), - Encoding(Encoding), Flags(Flags) {} + Encoding(Encoding), Flags(Flags), Annotations(Annotations) {} MDNodeKeyImpl(const DIBasicType *N) : Tag(N->getTag()), Name(N->getRawName()), SizeInBits(N->getSizeInBits()), AlignInBits(N->getAlignInBits()), Encoding(N->getEncoding()), - Flags(N->getFlags()) {} + Flags(N->getFlags()), Annotations(N->getRawAnnotations()) {} bool isKeyOf(const DIBasicType *RHS) const { return Tag == RHS->getTag() && Name == RHS->getRawName() && SizeInBits == RHS->getSizeInBits() && AlignInBits == RHS->getAlignInBits() && - Encoding == RHS->getEncoding() && Flags == RHS->getFlags(); + Encoding == RHS->getEncoding() && Flags == RHS->getFlags() && + Annotations == RHS->getRawAnnotations(); } unsigned getHashValue() const { - return hash_combine(Tag, Name, SizeInBits, AlignInBits, Encoding); + return hash_combine(Tag, Name, SizeInBits, AlignInBits, Encoding, + Annotations); } }; @@ -712,18 +716,24 @@ template <> struct MDNodeKeyImpl { unsigned Flags; uint8_t CC; Metadata *TypeArray; + Metadata *Annotations; - MDNodeKeyImpl(unsigned Flags, uint8_t CC, Metadata *TypeArray) - : Flags(Flags), CC(CC), TypeArray(TypeArray) {} + MDNodeKeyImpl(unsigned Flags, uint8_t CC, Metadata *TypeArray, + Metadata *Annotations) + : Flags(Flags), CC(CC), TypeArray(TypeArray), Annotations(Annotations) {} MDNodeKeyImpl(const DISubroutineType *N) - : Flags(N->getFlags()), CC(N->getCC()), TypeArray(N->getRawTypeArray()) {} + : Flags(N->getFlags()), CC(N->getCC()), TypeArray(N->getRawTypeArray()), + Annotations(N->getRawAnnotations()) {} bool isKeyOf(const DISubroutineType *RHS) const { return Flags == RHS->getFlags() && CC == RHS->getCC() && - TypeArray == RHS->getRawTypeArray(); + TypeArray == RHS->getRawTypeArray() && + Annotations == RHS->getRawAnnotations(); } - unsigned getHashValue() const { return hash_combine(Flags, CC, TypeArray); } + unsigned getHashValue() const { + return hash_combine(Flags, CC, TypeArray, Annotations); + } }; template <> struct MDNodeKeyImpl { diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp index b6d3b460005c9..f92de243a840c 100644 --- a/llvm/lib/Target/BPF/BTFDebug.cpp +++ b/llvm/lib/Target/BPF/BTFDebug.cpp @@ -14,6 +14,8 @@ #include "BPF.h" #include "BPFCORE.h" #include "MCTargetDesc/BPFMCTargetDesc.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineModuleInfo.h" @@ -69,11 +71,10 @@ BTFTypeDerived::BTFTypeDerived(const DIDerivedType *DTy, unsigned Tag, BTFType.Info = Kind << 24; } -/// Used by DW_TAG_pointer_type only. -BTFTypeDerived::BTFTypeDerived(unsigned NextTypeId, unsigned Tag, +BTFTypeDerived::BTFTypeDerived(unsigned NextTypeId, enum BTF::TypeKinds _Kind, StringRef Name) : DTy(nullptr), NeedsFixup(false), Name(Name) { - Kind = BTF::BTF_KIND_PTR; + Kind = _Kind; BTFType.Info = Kind << 24; BTFType.Type = NextTypeId; } @@ -106,6 +107,8 @@ void BTFTypeDerived::setPointeeType(uint32_t PointeeType) { BTFType.Type = PointeeType; } +uint32_t BTFTypeDerived::getPointeeType() { return BTFType.Type; } + /// Represent a struct/union forward declaration. BTFTypeFwd::BTFTypeFwd(StringRef Name, bool IsUnion) : Name(Name) { Kind = BTF::BTF_KIND_FWD; @@ -490,6 +493,10 @@ void BTFTypeTypeTag::completeType(BTFDebug &BDebug) { } } +uint32_t BTFTypeTypeTag::getNextTypeId() { return BTFType.Type; } + +StringRef BTFTypeTypeTag::getTag() { return Tag; } + uint32_t BTFStringTable::addString(StringRef S) { // Check whether the string already exists. for (auto &OffsetM : OffsetToIdMap) { @@ -511,13 +518,278 @@ BTFDebug::BTFDebug(AsmPrinter *AP) addString("\0"); } +static DINodeArray lookupAnnotations(const DIType *Ty) { + DINodeArray Annots = {}; + if (auto *SubTy = dyn_cast(Ty)) + Annots = SubTy->getAnnotations(); + else if (auto *SubTy = dyn_cast(Ty)) + Annots = SubTy->getAnnotations(); + else if (auto *SubTy = dyn_cast(Ty)) + Annots = SubTy->getAnnotations(); + else if (auto *SubTy = dyn_cast(Ty)) + Annots = SubTy->getAnnotations(); + return Annots; +} + +static void collectBTFTypeTags(const DIType *Ty, + SmallVectorImpl &Tags, + StringRef AnnotName) { + DINodeArray Annots = lookupAnnotations(Ty); + if (!Annots) + return; + + for (const Metadata *Annotations : Annots->operands()) { + const MDNode *MD = cast(Annotations); + if (MD->getNumOperands() != 2) + continue; + const MDString *Name = dyn_cast(MD->getOperand(0)); + if (!Name) + continue; + if (!Name->getString().equals(AnnotName)) + continue; + // For type with "int __tag1 __tag2 *p", the Tags will have + // content: [__tag1, __tag2]. + Tags.push_back(cast(MD->getOperand(1))); + } +} + +/// Generate btf_type_tag chains. +uint32_t BTFDebug::genBTFTypeTags(const DIType *Ty, int BaseId, + const DIDerivedType *DTy, + StringRef AnnotName) { + SmallVector MDStrs; + collectBTFTypeTags(Ty, MDStrs, AnnotName); + // With MDStrs [__tag1, __tag2], the output type chain looks like + // PTR -> __tag2 -> __tag1 -> BaseType + // In the below, we construct BTF types with the order of __tag1, __tag2 + // and PTR. + for (unsigned I = 0; I < MDStrs.size(); I++) { + const MDString *Value = MDStrs[I]; + auto TagEntry = + BaseId == -1 + ? std::make_unique(DTy, Value->getString()) + : std::make_unique(BaseId, Value->getString()); + BaseId = addType(std::move(TagEntry)); + } + return BaseId; +} + +uint32_t BTFDebug::genBTFTypeTagsV1(const DIDerivedType *DTy) { + return genBTFTypeTags(DTy, -1, DTy, "btf_type_tag"); +} + +uint32_t BTFDebug::genBTFTypeTagsV2(const DIType *Ty, uint32_t BaseId) { + return genBTFTypeTags(Ty, BaseId, nullptr, "btf:type_tag"); +} + +static hash_code hashElements(const DICompositeType *Ty) { + hash_code Hash = hash_value(Ty->getElements().size()); + for (auto *Node : Ty->getElements()) { + if (Node->getTag() == dwarf::DW_TAG_member) { + auto *Member = cast(Node); + Hash = hash_combine(Hash, Member->getName()); + } + if (Node->getTag() == dwarf::DW_TAG_enumerator) { + auto *Member = cast(Node); + Hash = hash_combine(Hash, Member->getName()); + } + } + return Hash; +} + +static bool compareElements(const DICompositeType *A, + const DICompositeType *B) { + if (A->getElements().size() != B->getElements().size()) + return false; + + auto AI = A->getElements().begin(); + auto AE = A->getElements().end(); + auto BI = B->getElements().begin(); + for (; AI != AE; ++AI, ++BI) { + if ((*AI)->getTag() != (*BI)->getTag()) + return false; + + if ((*AI)->getTag() == dwarf::DW_TAG_member) { + auto *MA = cast(*AI); + auto *MB = cast(*BI); + if (!MA->getName().equals(MB->getName()) || + MA->getBaseType() != MB->getBaseType() || + MA->getOffsetInBits() != MB->getOffsetInBits()) + return false; + } + + if ((*AI)->getTag() == dwarf::DW_TAG_enumerator) { + auto *MA = cast(*AI); + auto *MB = cast(*BI); + if (!MA->getName().equals(MB->getName()) || + MA->isUnsigned() != MB->isUnsigned() || + MA->getValue().getZExtValue() != MB->getValue().getZExtValue()) + return false; + } + } + + return true; +} + +bool BTFTypeDedupKey::operator==(const BTFTypeDedupKey &Other) const { + auto *OtherTy = Other.CanonTy; + + if (CanonTy->getTag() != OtherTy->getTag()) + return false; + + if (!CanonTy->getName().equals(OtherTy->getName())) + return false; + + switch (CanonTy->getTag()) { + case dwarf::DW_TAG_base_type: { + auto *A = cast(CanonTy); + auto *B = cast(OtherTy); + return A->getEncoding() == B->getEncoding() && + A->getOffsetInBits() == B->getOffsetInBits() && + A->getSizeInBits() == B->getSizeInBits(); + } + + case dwarf::DW_TAG_typedef: { + auto *A = cast(CanonTy); + auto *B = cast(OtherTy); + return A->getBaseType() == B->getBaseType(); + } + + case dwarf::DW_TAG_enumeration_type: + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_union_type: { + auto *A = cast(CanonTy); + auto *B = cast(OtherTy); + return A->isForwardDecl() == B->isForwardDecl() && compareElements(A, B); + } + + case dwarf::DW_TAG_subroutine_type: { + auto *A = cast(CanonTy); + auto *B = cast(OtherTy); + return std::equal(A->getTypeArray().begin(), A->getTypeArray().end(), + B->getTypeArray().begin()); + } + + default: + llvm_unreachable("Comparing unexpected dedup key"); + } +} + +size_t BTFTypeDedupKey::Hash::operator()(BTFTypeDedupKey const &Key) const { + auto *Ty = Key.CanonTy; + hash_code Hash = + hash_combine(Ty->getTag(), Ty->getName(), Ty->getSizeInBits()); + + switch (Ty->getTag()) { + case dwarf::DW_TAG_base_type: { + auto *BTy = cast(Ty); + Hash = hash_combine(BTy->getEncoding(), BTy->getOffsetInBits(), + BTy->getSizeInBits()); + break; + } + + case dwarf::DW_TAG_typedef: + // Nothing to be done, name & tag suffice + break; + + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_union_type: + case dwarf::DW_TAG_enumeration_type: + Hash = hash_combine(Hash, hashElements(cast(Key.CanonTy))); + break; + + case dwarf::DW_TAG_subroutine_type: { + auto *STy = cast(Key.CanonTy); + Hash = hash_combine(Hash, STy->getTypeArray().size()); + for (DIType *Param : STy->getTypeArray()) + Hash = hash_combine(Hash, + Param ? hash_value(Param->getName()) : hash_value(0)); + break; + } + + default: + llvm_unreachable("Hashing unexpected dedup key"); + }; + + return Hash; +} + +static std::optional makeDedupKey(const DIType *Ty) { + if (Ty == nullptr) + return std::nullopt; + + switch (Ty->getTag()) { + case dwarf::DW_TAG_base_type: + case dwarf::DW_TAG_typedef: + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_union_type: + case dwarf::DW_TAG_enumeration_type: + case dwarf::DW_TAG_subroutine_type: + return std::optional(BTFTypeDedupKey(Ty)); + default: + return std::nullopt; + } +} + +// `btf_type_tag`s are encoded in DI classes as `annotations` fields, +// this might lead to some DI info duplication. +// For example, the following C code: +// +// #define __tag1 __attribute__((btf_type_tag("tag1"))) +// +// struct foo {}; +// struct bar { +// struct foo __tag1 a; +// struct foo b; +// } g; +// +// Generates the following DI representation: +// +// !5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bar", +// ..., elements: !6) +// !6 = !{!7, !8} +// !7 = !DIDerivedType(tag: DW_TAG_member, name: "a", ..., baseType: !10) +// !8 = !DIDerivedType(tag: DW_TAG_member, name: "b", ..., baseType: !9) +// !9 = !DICompositeType(tag: DW_TAG_structure_type, name: "foo", ...) +// !10 = !DICompositeType(tag: DW_TAG_structure_type, name: "foo", ..., +// annotations: !11) +// !11 = !{!12} +// !12 = !{!"btf:type_tag", !"tag1"} +// +// Note two instances of structure "foo", one with annotations, one without. +// +// In order to avoid such duplication in generated BTF two things are used: +// - a map `BTFDebug::DIDedupMap` +// - special logic in `BTFDebug::addType` +// +// The key of `BTFDebug::DIDedupMap` is `DIType*` wrapped in an auxiliary +// type that provides custom hashing and equality operations. +// +// The value of `BTFDebug::DIDedupMap` is BTF id of the type w/o type tags. +// +// Hashing and equality functions of `BTFDebug::DIDedupMap` ignore +// `annotations` field on a first level and compare all other fields +// significant for BTF generation. +// +// The `BTFDebug::addType(..., DIType *Ty, ...)` operates as follows: +// - establishes a base type: +// - if a type similar to `Ty` could be found in `BTFDebug::DIDedupMap` +// it is used as base; +// - otherwise a fresh BTF type is used as base; +// - adds btf type tag wrappers: +// - a series of new BTF_TYPE_TAG types is generated wrapping one +// another, with first type wrapping the base type. uint32_t BTFDebug::addType(std::unique_ptr TypeEntry, - const DIType *Ty) { - TypeEntry->setId(TypeEntries.size() + 1); - uint32_t Id = TypeEntry->getId(); - DIToIdMap[Ty] = Id; - TypeEntries.push_back(std::move(TypeEntry)); - return Id; + const DIType *Ty, uint32_t *RealId) { + uint32_t Id = TypeEntry ? addType(std::move(TypeEntry)) : 0; + auto Key = makeDedupKey(Ty); + if (Key.has_value()) + DIDedupMap[*Key] = Id; + uint32_t TagId = genBTFTypeTagsV2(Ty, Id); + DIToIdMap[Ty] = TagId; + if (RealId) + *RealId = Id; + return TagId; } uint32_t BTFDebug::addType(std::unique_ptr TypeEntry) { @@ -527,7 +799,35 @@ uint32_t BTFDebug::addType(std::unique_ptr TypeEntry) { return Id; } +uint32_t BTFDebug::replaceType(uint32_t Id, + std::unique_ptr TypeEntry) { + TypeEntry->setId(Id); + TypeEntries[Id - 1] = std::move(TypeEntry); + return Id; +} + +std::optional BTFDebug::lookupType(const DIType *Ty) { + if (DIToIdMap.find(Ty) != DIToIdMap.end()) + return std::optional(DIToIdMap[Ty]); + + auto Key = makeDedupKey(Ty); + if (!Key.has_value() || (DIDedupMap.find(*Key) == DIDedupMap.end())) + return std::nullopt; + + auto TagId = genBTFTypeTagsV2(Ty, DIDedupMap[*Key]); + DIToIdMap[Ty] = TagId; + return TagId; +} + void BTFDebug::visitBasicType(const DIBasicType *BTy, uint32_t &TypeId) { + // Such "void" entries might arise from use btf_type_tag, e.g.: + // void __attribute__((btf_type_tag("foo"))) *p; + if (BTy->getTag() == dwarf::DW_TAG_unspecified_type && + BTy->getName() == "void") { + TypeId = addType(nullptr, BTy); + return; + } + // Only int and binary floating point types are supported in BTF. uint32_t Encoding = BTy->getEncoding(); std::unique_ptr TypeEntry; @@ -617,46 +917,6 @@ uint32_t BTFDebug::processDISubprogram(const DISubprogram *SP, return FuncId; } -/// Generate btf_type_tag chains. -int BTFDebug::genBTFTypeTags(const DIDerivedType *DTy, int BaseTypeId) { - SmallVector MDStrs; - DINodeArray Annots = DTy->getAnnotations(); - if (Annots) { - // For type with "int __tag1 __tag2 *p", the MDStrs will have - // content: [__tag1, __tag2]. - for (const Metadata *Annotations : Annots->operands()) { - const MDNode *MD = cast(Annotations); - const MDString *Name = cast(MD->getOperand(0)); - if (Name->getString() != "btf_type_tag") - continue; - MDStrs.push_back(cast(MD->getOperand(1))); - } - } - - if (MDStrs.size() == 0) - return -1; - - // With MDStrs [__tag1, __tag2], the output type chain looks like - // PTR -> __tag2 -> __tag1 -> BaseType - // In the below, we construct BTF types with the order of __tag1, __tag2 - // and PTR. - unsigned TmpTypeId; - std::unique_ptr TypeEntry; - if (BaseTypeId >= 0) - TypeEntry = - std::make_unique(BaseTypeId, MDStrs[0]->getString()); - else - TypeEntry = std::make_unique(DTy, MDStrs[0]->getString()); - TmpTypeId = addType(std::move(TypeEntry)); - - for (unsigned I = 1; I < MDStrs.size(); I++) { - const MDString *Value = MDStrs[I]; - TypeEntry = std::make_unique(TmpTypeId, Value->getString()); - TmpTypeId = addType(std::move(TypeEntry)); - } - return TmpTypeId; -} - /// Handle structure/union types. void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct, uint32_t &TypeId) { @@ -678,17 +938,18 @@ void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct, auto TypeEntry = std::make_unique(CTy, IsStruct, HasBitField, VLen); StructTypes.push_back(TypeEntry.get()); - TypeId = addType(std::move(TypeEntry), CTy); + uint32_t StructId; + TypeId = addType(std::move(TypeEntry), CTy, &StructId); // Check struct/union annotations - processDeclAnnotations(CTy->getAnnotations(), TypeId, -1); + processDeclAnnotations(CTy->getAnnotations(), StructId, -1); // Visit all struct members. int FieldNo = 0; for (const auto *Element : Elements) { const auto Elem = cast(Element); visitTypeEntry(Elem); - processDeclAnnotations(Elem->getAnnotations(), TypeId, FieldNo); + processDeclAnnotations(Elem->getAnnotations(), StructId, FieldNo); FieldNo++; } } @@ -822,22 +1083,20 @@ void BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId, } if (Tag == dwarf::DW_TAG_pointer_type) { - int TmpTypeId = genBTFTypeTags(DTy, -1); - if (TmpTypeId >= 0) { - auto TypeDEntry = - std::make_unique(TmpTypeId, Tag, DTy->getName()); - TypeId = addType(std::move(TypeDEntry), DTy); - } else { - auto TypeEntry = std::make_unique(DTy, Tag, false); - TypeId = addType(std::move(TypeEntry), DTy); - } + int TmpTypeId = genBTFTypeTagsV1(DTy); + auto TypeEntry = TmpTypeId == -1 + ? std::make_unique(DTy, Tag, false) + : std::make_unique( + TmpTypeId, BTF::BTF_KIND_PTR, DTy->getName()); + TypeId = addType(std::move(TypeEntry), DTy); } else if (Tag == dwarf::DW_TAG_typedef || Tag == dwarf::DW_TAG_const_type || Tag == dwarf::DW_TAG_volatile_type || Tag == dwarf::DW_TAG_restrict_type) { auto TypeEntry = std::make_unique(DTy, Tag, false); - TypeId = addType(std::move(TypeEntry), DTy); + uint32_t RealId = 0; + TypeId = addType(std::move(TypeEntry), DTy, &RealId); if (Tag == dwarf::DW_TAG_typedef) - processDeclAnnotations(DTy->getAnnotations(), TypeId, -1); + processDeclAnnotations(DTy->getAnnotations(), RealId, -1); } else if (Tag != dwarf::DW_TAG_member) { return; } @@ -860,8 +1119,13 @@ void BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId, /// will be generated. void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId, bool CheckPointer, bool SeenPointer) { - if (!Ty || DIToIdMap.find(Ty) != DIToIdMap.end()) { + if (!Ty) { TypeId = DIToIdMap[Ty]; + return; + } + + if (auto OptTypeId = lookupType(Ty)) { + TypeId = *OptTypeId; // To handle the case like the following: // struct t; @@ -892,14 +1156,14 @@ void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId, // We will traverse const/ptr/volatile which already have corresponding // BTF types and generate type for 'struct' which might be in Fixup // state. - if (Ty && (!CheckPointer || !SeenPointer)) { + if (!CheckPointer || !SeenPointer) { if (const auto *DTy = dyn_cast(Ty)) { while (DTy) { const DIType *BaseTy = DTy->getBaseType(); if (!BaseTy) break; - if (DIToIdMap.find(BaseTy) != DIToIdMap.end()) { + if (lookupType(BaseTy)) { DTy = dyn_cast(BaseTy); } else { if (CheckPointer && DTy->getTag() == dwarf::DW_TAG_pointer_type) { @@ -1242,6 +1506,26 @@ void BTFDebug::endFunctionImpl(const MachineFunction *MF) { SecNameOff = 0; } +BTFTypeBase *BTFDebug::getType(uint32_t Id) { + return TypeEntries[Id - 1].get(); +} + +uint32_t BTFDebug::skipBTFTypeTags(uint32_t Id) { + for (;;) { + if (Id == 0) + break; + + BTFTypeBase *Ty = getType(Id); + if (Ty->getKind() != BTF::BTF_KIND_TYPE_TAG) + break; + + auto *TagTy = static_cast(Ty); + Id = TagTy->getNextTypeId(); + } + + return Id; +} + /// On-demand populate types as requested from abstract member /// accessing or preserve debuginfo type. unsigned BTFDebug::populateType(const DIType *Ty) { @@ -1249,7 +1533,10 @@ unsigned BTFDebug::populateType(const DIType *Ty) { visitTypeEntry(Ty, Id, false, false); for (const auto &TypeEntry : TypeEntries) TypeEntry->completeType(*this); - return Id; + + // Skip type tags, libbpf expects each relocation entry to point to + // struct/union/enum. + return skipBTFTypeTags(Id); } /// Generate a struct member field relocation. @@ -1448,6 +1735,9 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) { break; } + // Kernel does not handle VARs with type 'TYPE_TAG -> something' + GVTypeId = skipBTFTypeTags(GVTypeId); + // Only support the following globals: // . static variables // . non-static weak or non-weak global variables @@ -1581,6 +1871,196 @@ void BTFDebug::processFuncPrototypes(const Function *F) { } } +// Cache IDs for BTF types with shape: +// - (TYPE_TAG ) +// - (CONST ) +// - (VOLATILE ) +// - (RESTRICT ) +class BTFDebug::QualifiedTypesCache { +public: + struct Entry { + const StringRef Tag; + const uint32_t Id; + const BTF::TypeKinds Kind; + + Entry(uint32_t Id, StringRef Tag) + : Tag(Tag), Id(Id), Kind(BTF::BTF_KIND_TYPE_TAG) {} + Entry(uint32_t Id, BTF::TypeKinds Kind) + : Tag(StringRef()), Id(Id), Kind(Kind) {} + }; + + struct EntryHash { + std::size_t operator()(Entry const &E) const { + return hash_combine(E.Tag, E.Id, E.Kind); + } + }; + + struct EntryEq { + bool operator()(const Entry &LHS, const Entry &RHS) const { + return std::tie(LHS.Tag, LHS.Id, LHS.Kind) == + std::tie(RHS.Tag, RHS.Id, RHS.Kind); + } + }; + +private: + std::unordered_map Cache; + + uint32_t lookup(const Entry &Entry) { + auto Cached = Cache.find(Entry); + if (Cached != Cache.end()) + return Cached->second; + return 0; + } + +public: + void add(uint32_t Id, BTFTypeDerived *Type) { + Cache[Entry(Type->getPointeeType(), (BTF::TypeKinds)Type->getKind())] = Id; + } + + void add(uint32_t Id, BTFTypeTypeTag *Type) { + Cache[Entry(Type->getNextTypeId(), Type->getTag())] = Id; + } + + uint32_t lookupQualified(uint32_t Id, BTF::TypeKinds Kind) { + return lookup(Entry(Id, Kind)); + } + + uint32_t lookupTypeTag(uint32_t Id, StringRef Tag) { + return lookup(Entry(Id, Tag)); + } +}; + +// Convert BTF type chain of shape: +// CONST -> VOLATILE -> RESTRICT -> TYPE_TAG -> ... +// ^ +// '- TopId +// +// To: +// TYPE_TAG -> CONST -> VOLATILE -> RESTRICT -> ... +// ^ +// '- TopId +void BTFDebug::rebuildTypeTagsChain(uint32_t TopId, + QualifiedTypesCache &Cache) { + SmallSet Qualifiers; + SmallVector Tags; + uint32_t Id = TopId; + + // First, get to the bottom of the chain, accumulating CVR + // qualifiers and type tags + for (;;) { + if (Id == 0) + break; + auto *Type = getType(Id); + if (!Type) + break; + switch (Type->getKind()) { + case BTF::BTF_KIND_CONST: + case BTF::BTF_KIND_VOLATILE: + case BTF::BTF_KIND_RESTRICT: + Qualifiers.insert((BTF::TypeKinds)Type->getKind()); + Id = static_cast(Type)->getPointeeType(); + continue; + case BTF::BTF_KIND_TYPE_TAG: + Tags.push_back(static_cast(Type)->getTag()); + Id = static_cast(Type)->getNextTypeId(); + continue; + } + break; + } + + if (Qualifiers.empty() || Tags.empty()) + return; + + // Next, rebuild the chain using shape (Tags (Qualifiers Id)). + // Track intermediate result in 'Id'. + for (auto Kind : + {BTF::BTF_KIND_RESTRICT, BTF::BTF_KIND_VOLATILE, BTF::BTF_KIND_CONST}) { + if (!Qualifiers.contains(Kind)) + continue; + if (uint32_t CachedId = Cache.lookupQualified(Id, Kind)) { + Id = CachedId; + continue; + } + auto Type = std::make_unique(Id, Kind); + auto *TypePtr = Type.get(); + Type->completeType(*this); + Id = addType(std::move(Type)); + Cache.add(Id, TypePtr); + } + + // All but last type tags could use cache + for (int I = Tags.size() - 1; I > 0; --I) { + if (uint32_t CachedId = Cache.lookupTypeTag(Id, Tags[I])) { + Id = CachedId; + continue; + } + auto Type = std::make_unique(Id, Tags[I]); + auto *TypePtr = Type.get(); + Type->completeType(*this); + Id = addType(std::move(Type)); + Cache.add(Id, TypePtr); + } + + // Last type tag has to be built anew because it needs to replace + // entry at TopId + auto Type = std::make_unique(Id, Tags[0]); + Type->completeType(*this); + Cache.add(TopId, Type.get()); + replaceType(TopId, std::move(Type)); +} + +// Linux Kernel expects type tags to precede CVR qualifiers, but this +// is not guaranteed by the way BTF is generated from DWARF. +// Use a post-processing step to ensure this property. +// +// Convert each chain of shape: +// +// CONST -> VOLATILE -> TYPE_TAG -> ... +// ^ ^ ^ +// '- Id_A '- Id_B '- Id_C +// +// To a set of chains: +// +// TYPE_TAG -> CONST -> VOLATILE -> ... +// ^ \ / +// '- Id_A new ids +// | +// TYPE_TAG -> VOLATILE -> ... +// ^ +// '- Id_B +// +// TYPE_TAG -> ... +// ^ +// '- Id_C +// +// Here TYPE_TAG entries for Id_A and Id_B are newly created and might +// be redundant, however removing such redundancy would require deletion +// of Id_B and Id_C entries and update of all BTF ids and references. +// +// For now, assume that this should not lead to significant BTF +// increase in practice and keep redundant entries. +void BTFDebug::moveTypeTagsBeforeCVR() { + const size_t N = TypeEntries.size() + 1; + QualifiedTypesCache Cache; + + for (uint32_t Id = 1; Id < N; ++Id) { + BTFTypeBase *Type = getType(Id); + switch (Type->getKind()) { + case BTF::BTF_KIND_CONST: + case BTF::BTF_KIND_VOLATILE: + case BTF::BTF_KIND_RESTRICT: + Cache.add(Id, static_cast(Type)); + break; + case BTF::BTF_KIND_TYPE_TAG: + Cache.add(Id, static_cast(Type)); + break; + } + } + + for (uint32_t Id = 1; Id < N; ++Id) + rebuildTypeTagsChain(Id, Cache); +} + void BTFDebug::endModule() { // Collect MapDef globals if not collected yet. if (MapDefNotCollected) { @@ -1602,23 +2082,19 @@ void BTFDebug::endModule() { // Search through struct types uint32_t StructTypeId = 0; - for (const auto &StructType : StructTypes) { - if (StructType->getName() == TypeName) { - StructTypeId = StructType->getId(); - break; - } - } + if (auto OptId = lookupType(CTy)) + StructTypeId = *OptId; if (StructTypeId == 0) { auto FwdTypeEntry = std::make_unique(TypeName, IsUnion); - StructTypeId = addType(std::move(FwdTypeEntry)); + StructTypeId = addType(std::move(FwdTypeEntry), CTy); } for (auto &TypeInfo : Fixup.second) { const DIDerivedType *DTy = TypeInfo.first; BTFTypeDerived *BDType = TypeInfo.second; - int TmpTypeId = genBTFTypeTags(DTy, StructTypeId); + int TmpTypeId = genBTFTypeTagsV1(DTy); if (TmpTypeId >= 0) BDType->setPointeeType(TmpTypeId); else @@ -1630,6 +2106,9 @@ void BTFDebug::endModule() { for (const auto &TypeEntry : TypeEntries) TypeEntry->completeType(*this); + // BTF to BTF transformations + moveTypeTagsBeforeCVR(); + // Emit BTF sections. emitBTFSection(); emitBTFExtSection(); diff --git a/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h index 11a0c59ba6c90..6ded6958491c2 100644 --- a/llvm/lib/Target/BPF/BTFDebug.h +++ b/llvm/lib/Target/BPF/BTFDebug.h @@ -48,6 +48,7 @@ class BTFTypeBase { virtual ~BTFTypeBase() = default; void setId(uint32_t Id) { this->Id = Id; } uint32_t getId() { return Id; } + uint32_t getKind() { return Kind; } uint32_t roundupToBytes(uint32_t NumBits) { return (NumBits + 7) >> 3; } /// Get the size of this BTF type entry. virtual uint32_t getSize() { return BTF::CommonTypeSize; } @@ -68,10 +69,12 @@ class BTFTypeDerived : public BTFTypeBase { public: BTFTypeDerived(const DIDerivedType *Ty, unsigned Tag, bool NeedsFixup); - BTFTypeDerived(unsigned NextTypeId, unsigned Tag, StringRef Name); + BTFTypeDerived(unsigned NextTypeId, enum BTF::TypeKinds Kind, + StringRef Name = StringRef()); void completeType(BTFDebug &BDebug) override; void emitType(MCStreamer &OS) override; void setPointeeType(uint32_t PointeeType); + uint32_t getPointeeType(); }; /// Handle struct or union forward declaration. @@ -240,6 +243,8 @@ class BTFTypeTypeTag : public BTFTypeBase { BTFTypeTypeTag(uint32_t NextTypeId, StringRef Tag); BTFTypeTypeTag(const DIDerivedType *DTy, StringRef Tag); void completeType(BTFDebug &BDebug) override; + uint32_t getNextTypeId(); + StringRef getTag(); }; /// String table. @@ -285,6 +290,20 @@ struct BTFFieldReloc { uint32_t RelocKind; ///< What to patch the instruction }; +/// Used for de-duplication for types annotated with btf_type_tag annotation, +/// See comment at BTFDebug.cpp:addType() for details. +struct BTFTypeDedupKey { + const DIType *CanonTy; + + BTFTypeDedupKey(const DIType *CanonTy) : CanonTy(CanonTy) {} + + bool operator==(const BTFTypeDedupKey &Other) const; + + struct Hash { + size_t operator()(BTFTypeDedupKey const &Key) const; + }; +}; + /// Collect and emit BTF information. class BTFDebug : public DebugHandlerBase { MCStreamer &OS; @@ -296,6 +315,8 @@ class BTFDebug : public DebugHandlerBase { BTFStringTable StringTable; std::vector> TypeEntries; std::unordered_map DIToIdMap; + std::unordered_map + DIDedupMap; std::map> FuncInfoTable; std::map> LineInfoTable; std::map> FieldRelocTable; @@ -311,11 +332,17 @@ class BTFDebug : public DebugHandlerBase { /// Add types to TypeEntries. /// @{ /// Add types to TypeEntries and DIToIdMap. - uint32_t addType(std::unique_ptr TypeEntry, const DIType *Ty); + uint32_t addType(std::unique_ptr TypeEntry, const DIType *Ty, + uint32_t *RealId = nullptr); /// Add types to TypeEntries only and return type id. uint32_t addType(std::unique_ptr TypeEntry); + uint32_t replaceType(uint32_t Id, std::unique_ptr TypeEntry); /// @} + BTFTypeBase *getType(uint32_t Id); + + std::optional lookupType(const DIType *Ty); + /// IR type visiting functions. /// @{ void visitTypeEntry(const DIType *Ty); @@ -368,7 +395,10 @@ class BTFDebug : public DebugHandlerBase { /// the base type of DTy. Return the type id of the first BTF type_tag /// in the chain. If no type_tag's are generated, a negative value /// is returned. - int genBTFTypeTags(const DIDerivedType *DTy, int BaseTypeId); + uint32_t genBTFTypeTags(const DIType *Ty, int BaseId, + const DIDerivedType *DTy, StringRef AnnotName); + uint32_t genBTFTypeTagsV1(const DIDerivedType *DTy); + uint32_t genBTFTypeTagsV2(const DIType *Ty, uint32_t BaseId); /// Generate one field relocation record. void generatePatchImmReloc(const MCSymbol *ORSym, uint32_t RootId, @@ -390,6 +420,16 @@ class BTFDebug : public DebugHandlerBase { /// Emit the .BTF.ext section. void emitBTFExtSection(); + uint32_t skipBTFTypeTags(uint32_t Id); + + /// BTF post processing phase rewriting type chains like below: + /// CONST -> TYPE_TAG '...' -> ... + /// To: + /// TYPE_TAG '...' -> CONST -> ... + void moveTypeTagsBeforeCVR(); + class QualifiedTypesCache; + void rebuildTypeTagsChain(uint32_t Id, QualifiedTypesCache &Cache); + protected: /// Gather pre-function debug information. void beginFunctionImpl(const MachineFunction *MF) override; diff --git a/llvm/test/Bitcode/attr-btf_tag-dibasic.ll b/llvm/test/Bitcode/attr-btf_tag-dibasic.ll new file mode 100644 index 0000000000000..7a73f921466d9 --- /dev/null +++ b/llvm/test/Bitcode/attr-btf_tag-dibasic.ll @@ -0,0 +1,36 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; int __tag1 g; +; Compilation flag: +; clang -S -g -emit-llvm test.c + +@g = dso_local global i32 0, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!8, !9, !10, !11, !12, !13, !14} +!llvm.ident = !{!15} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 2, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang version 17.0.0 (https://github.com/llvm/llvm-project.git c15ba1bb9498fa04f6c374337313df43486c9713)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/home/eddy/work/tmp", checksumkind: CSK_MD5, checksum: "79feb01d60b549b43abc493c324fe2a8") +!4 = !{!0} +!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed, annotations: !6) +!6 = !{!7} +!7 = !{!"btf:type_tag", !"tag1"} + +; CHECK: distinct !DIGlobalVariable(name: "g", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L1:[0-9]+]], isLocal: false, isDefinition: true) +; CHECK: ![[L1]] = !DIBasicType(name: "int", size: [[#]], encoding: DW_ATE_signed, annotations: ![[L2:[0-9]+]]) +; CHECK: ![[L2]] = !{![[L3:[0-9]+]]} +; CHECK: ![[L3]] = !{!"btf:type_tag", !"tag1"} + +!8 = !{i32 7, !"Dwarf Version", i32 5} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{i32 8, !"PIC Level", i32 2} +!12 = !{i32 7, !"PIE Level", i32 2} +!13 = !{i32 7, !"uwtable", i32 2} +!14 = !{i32 7, !"frame-pointer", i32 2} +!15 = !{!"clang version 17.0.0 (https://github.com/llvm/llvm-project.git c15ba1bb9498fa04f6c374337313df43486c9713)"} diff --git a/llvm/test/Bitcode/attr-btf_tag-disubroutine.ll b/llvm/test/Bitcode/attr-btf_tag-disubroutine.ll new file mode 100644 index 0000000000000..277348c3eb461 --- /dev/null +++ b/llvm/test/Bitcode/attr-btf_tag-disubroutine.ll @@ -0,0 +1,41 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; int (__tag1 * g)(void); + +; Compilation flag: +; clang -S -g -emit-llvm test.c + +@g = dso_local global ptr null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!11, !12, !13, !14, !15, !16, !17} +!llvm.ident = !{!18} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 2, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang version 17.0.0 (https://github.com/llvm/llvm-project.git c15ba1bb9498fa04f6c374337313df43486c9713)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/home/eddy/work/tmp", checksumkind: CSK_MD5, checksum: "2ed8742fd12b44b948de1ac5e433bd63") +!4 = !{!0} +!5 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64) +!6 = !DISubroutineType(types: !7, annotations: !9) +!7 = !{!8} +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !{!10} +!10 = !{!"btf:type_tag", !"tag1"} + +; CHECK: distinct !DIGlobalVariable(name: "g", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L1:[0-9]+]], isLocal: false, isDefinition: true) +; CHECK: ![[L1]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L2:[0-9]+]], size: [[#]]) +; CHECK: ![[L2]] = !DISubroutineType(types: ![[#]], annotations: ![[L3:[0-9]+]]) +; CHECK: ![[L3]] = !{![[L4:[0-9]+]]} +; CHECK: ![[L4]] = !{!"btf:type_tag", !"tag1"} + +!11 = !{i32 7, !"Dwarf Version", i32 5} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{i32 8, !"PIC Level", i32 2} +!15 = !{i32 7, !"PIE Level", i32 2} +!16 = !{i32 7, !"uwtable", i32 2} +!17 = !{i32 7, !"frame-pointer", i32 2} +!18 = !{!"clang version 17.0.0 (https://github.com/llvm/llvm-project.git c15ba1bb9498fa04f6c374337313df43486c9713)"} diff --git a/llvm/test/CodeGen/BPF/BTF/print_btf.py b/llvm/test/CodeGen/BPF/BTF/print_btf.py new file mode 100755 index 0000000000000..d6ebbe23edcdb --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/print_btf.py @@ -0,0 +1,300 @@ +#!/usr/bin/env python3 + +# Ad-hoc script to print BTF file in a readable format. +# Follows the same printing conventions as bpftool with format 'raw'. +# Usage: +# +# ./print_btf.py +# +# Parameters: +# +# :: a file name or '-' to read from stdin. +# +# Intended usage: +# +# llvm-objcopy --dump-section .BTF=- | ./print_btf.py - +# +# Kernel documentation contains detailed format description: +# https://www.kernel.org/doc/html/latest/bpf/btf.html + +import struct +import ctypes +import sys + + +class SafeDict(dict): + def __getitem__(self, key): + try: + return dict.__getitem__(self, key) + except KeyError: + return f"" + + +KINDS = SafeDict( + { + 0: "UNKN", + 1: "INT", + 2: "PTR", + 3: "ARRAY", + 4: "STRUCT", + 5: "UNION", + 6: "ENUM", + 7: "FWD", + 8: "TYPEDEF", + 9: "VOLATILE", + 10: "CONST", + 11: "RESTRICT", + 12: "FUNC", + 13: "FUNC_PROTO", + 14: "VAR", + 15: "DATASEC", + 16: "FLOAT", + 17: "DECL_TAG", + 18: "TYPE_TAG", + 19: "ENUM64", + } +) + +INT_ENCODING = SafeDict( + {0 << 0: "(none)", 1 << 0: "SIGNED", 1 << 1: "CHAR", 1 << 2: "BOOL"} +) + +ENUM_ENCODING = SafeDict({0: "UNSIGNED", 1: "SIGNED"}) + +FUNC_LINKAGE = SafeDict({0: "static", 1: "global", 2: "extern"}) + +VAR_LINKAGE = SafeDict( + { + 0: "static", + 1: "global", + } +) + +FWD_KIND = SafeDict( + { + 0: "struct", + 1: "union", + } +) + +for val, name in KINDS.items(): + globals()["BTF_KIND_" + name] = val + + +def warn(message): + print(message, file=sys.stderr) + + +def print_btf(filename): + if filename == "-": + buf = sys.stdin.buffer.read() + else: + with open(filename, "rb") as file: + buf = file.read() + + fmt_cache = {} + endian_pfx = "" + off = 0 + + def unpack(fmt): + nonlocal off, endian_pfx + fmt = endian_pfx + fmt + if fmt not in fmt_cache: + fmt_cache[fmt] = struct.Struct(fmt) + st = fmt_cache[fmt] + r = st.unpack_from(buf, off) + off += st.size + return r + + # Use magic number at the header start to determine endianness + (magic,) = unpack("H") + if magic == 0xEB9F: + endian_pfx = "<" + elif magic == 0x9FEB: + endian_pfx = ">" + else: + warn(f"Unexpected BTF magic: {magic:02x}") + return + + # Rest of the header + version, flags, hdr_len = unpack("BBI") + type_off, type_len, str_off, str_len = unpack("IIII") + + # Offsets in the header are relative to the end of a header + type_off += hdr_len + str_off += hdr_len + off = hdr_len + type_end = type_off + type_len + + def string(rel_off): + try: + start = str_off + rel_off + end = buf.index(b"\0", start) + if start == end: + return "(anon)" + return buf[start:end].decode("utf8") + except ValueError as e: + warn(f"Can't get string at offset {str_off} + {rel_off}: {e}") + return f"" + + idx = 1 + while off < type_end: + name_off, info, size = unpack("III") + kind = (info >> 24) & 0x1F + vlen = info & 0xFFFF + kflag = info >> 31 + kind_name = KINDS[kind] + name = string(name_off) + + def warn_nonzero(val, name): + nonlocal idx + if val != 0: + warn(f"<{idx}> {name} should be 0 but is {val}") + + if kind == BTF_KIND_INT: + (info,) = unpack("I") + encoding = (info & 0x0F000000) >> 24 + offset = (info & 0x00FF0000) >> 16 + bits = info & 0x000000FF + enc_name = INT_ENCODING[encoding] + print( + f"[{idx}] {kind_name} '{name}' size={size} " + f"bits_offset={offset} " + f"nr_bits={bits} encoding={enc_name}" + ) + warn_nonzero(kflag, "kflag") + warn_nonzero(vlen, "vlen") + + elif kind in [ + BTF_KIND_PTR, + BTF_KIND_CONST, + BTF_KIND_VOLATILE, + BTF_KIND_RESTRICT, + ]: + print(f"[{idx}] {kind_name} '{name}' type_id={size}") + warn_nonzero(name_off, "name_off") + warn_nonzero(kflag, "kflag") + warn_nonzero(vlen, "vlen") + + elif kind == BTF_KIND_ARRAY: + warn_nonzero(name_off, "name_off") + warn_nonzero(kflag, "kflag") + warn_nonzero(vlen, "vlen") + warn_nonzero(size, "size") + type, index_type, nelems = unpack("III") + print( + f"[{idx}] {kind_name} '{name}' type_id={type} " + f"index_type_id={index_type} nr_elems={nelems}" + ) + + elif kind in [BTF_KIND_STRUCT, BTF_KIND_UNION]: + print(f"[{idx}] {kind_name} '{name}' size={size} vlen={vlen}") + if kflag not in [0, 1]: + warn(f"<{idx}> kflag should 0 or 1: {kflag}") + for _ in range(0, vlen): + name_off, type, offset = unpack("III") + if kflag == 0: + print( + f"\t'{string(name_off)}' type_id={type} " + f"bits_offset={offset}" + ) + else: + bits_offset = offset & 0xFFFFFF + bitfield_size = offset >> 24 + print( + f"\t'{string(name_off)}' type_id={type} " + f"bits_offset={bits_offset} " + f"bitfield_size={bitfield_size}" + ) + + elif kind == BTF_KIND_ENUM: + encoding = ENUM_ENCODING[kflag] + print( + f"[{idx}] {kind_name} '{name}' encoding={encoding} " + f"size={size} vlen={vlen}" + ) + for _ in range(0, vlen): + (name_off,) = unpack("I") + (val,) = unpack("i" if kflag == 1 else "I") + print(f"\t'{string(name_off)}' val={val}") + + elif kind == BTF_KIND_ENUM64: + encoding = ENUM_ENCODING[kflag] + print( + f"[{idx}] {kind_name} '{name}' encoding={encoding} " + f"size={size} vlen={vlen}" + ) + for _ in range(0, vlen): + name_off, lo, hi = unpack("III") + val = hi << 32 | lo + if kflag == 1: + val = ctypes.c_long(val).value + print(f"\t'{string(name_off)}' val={val}LL") + + elif kind == BTF_KIND_FWD: + print(f"[{idx}] {kind_name} '{name}' fwd_kind={FWD_KIND[kflag]}") + warn_nonzero(vlen, "vlen") + warn_nonzero(size, "size") + + elif kind in [BTF_KIND_TYPEDEF, BTF_KIND_TYPE_TAG]: + print(f"[{idx}] {kind_name} '{name}' type_id={size}") + warn_nonzero(kflag, "kflag") + warn_nonzero(kflag, "vlen") + + elif kind == BTF_KIND_FUNC: + linkage = FUNC_LINKAGE[vlen] + print(f"[{idx}] {kind_name} '{name}' type_id={size} " f"linkage={linkage}") + warn_nonzero(kflag, "kflag") + + elif kind == BTF_KIND_FUNC_PROTO: + print(f"[{idx}] {kind_name} '{name}' ret_type_id={size} " f"vlen={vlen}") + warn_nonzero(name_off, "name_off") + warn_nonzero(kflag, "kflag") + for _ in range(0, vlen): + name_off, type = unpack("II") + print(f"\t'{string(name_off)}' type_id={type}") + + elif kind == BTF_KIND_VAR: + (linkage,) = unpack("I") + linkage = VAR_LINKAGE[linkage] + print(f"[{idx}] {kind_name} '{name}' type_id={size}, " f"linkage={linkage}") + warn_nonzero(kflag, "kflag") + warn_nonzero(vlen, "vlen") + + elif kind == BTF_KIND_DATASEC: + print(f"[{idx}] {kind_name} '{name}' size={size} vlen={vlen}") + warn_nonzero(kflag, "kflag") + warn_nonzero(size, "size") + for _ in range(0, vlen): + type, offset, size = unpack("III") + print(f"\ttype_id={type} offset={offset} size={size}") + + elif kind == BTF_KIND_FLOAT: + print(f"[{idx}] {kind_name} '{name}' size={size}") + warn_nonzero(kflag, "kflag") + warn_nonzero(vlen, "vlen") + + elif kind == BTF_KIND_DECL_TAG: + (component_idx,) = unpack("i") + print( + f"[{idx}] {kind_name} '{name}' type_id={size} " + + f"component_idx={component_idx}" + ) + warn_nonzero(kflag, "kflag") + warn_nonzero(vlen, "vlen") + + else: + warn( + f"<{idx}> Unexpected entry: kind={kind_name} " + f"name_off={name_off} " + f"vlen={vlen} kflag={kflag} size={size}" + ) + + idx += 1 + + +if __name__ == "__main__": + if len(sys.argv) != 2: + warn(f"Usage: {sys.argv[0]} ") + sys.exit(1) + print_btf(sys.argv[1]) diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-multiple-tags-reuse.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-multiple-tags-reuse.ll new file mode 100644 index 0000000000000..6bf4322dfc845 --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-multiple-tags-reuse.ll @@ -0,0 +1,64 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; +; const volatile __tag1 __tag2 int a; +; const volatile __tag1 int b; +; +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -S -g -emit-llvm test.c -o test.ll + +; Check that const->volatile->int chain is reused for variables 'a' and 'b'. + +; CHECK: [1] TYPE_TAG 'tag2' type_id=14 +; CHECK: [2] TYPE_TAG 'tag2' type_id=15 +; CHECK: [3] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED +; CHECK: [4] TYPE_TAG 'tag1' type_id=3 +; CHECK: [5] TYPE_TAG 'tag2' type_id=4 +; CHECK: [6] VAR 'a' type_id=1, linkage=global +; CHECK: [7] TYPE_TAG 'tag1' type_id=13 +; CHECK: [8] TYPE_TAG 'tag1' type_id=12 +; CHECK: [9] TYPE_TAG 'tag1' type_id=3 +; CHECK: [10] VAR 'b' type_id=7, linkage=global +; CHECK: [11] DATASEC '.rodata' size=0 vlen=2 +; CHECK: type_id=6 offset=0 size=4 +; CHECK: type_id=10 offset=0 size=4 +; CHECK: [12] VOLATILE '(anon)' type_id=3 +; CHECK: [13] CONST '(anon)' type_id=12 +; CHECK: [14] TYPE_TAG 'tag1' type_id=13 +; CHECK: [15] TYPE_TAG 'tag1' type_id=12 + +@a = dso_local constant i32 0, align 4, !dbg !0 +@b = dso_local constant i32 0, align 4, !dbg !5 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!17, !18, !19, !20} +!llvm.ident = !{!21} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 4, type: !12, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang, some version", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "some-file.c", directory: "/some/dir/") +!4 = !{!0, !5} +!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression()) +!6 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 5, type: !7, isLocal: false, isDefinition: true) +!7 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !8) +!8 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !9) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed, annotations: !10) +!10 = !{!11} +!11 = !{!"btf:type_tag", !"tag1"} +!12 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13) +!13 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !14) +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed, annotations: !15) +!15 = !{!11, !16} +!16 = !{!"btf:type_tag", !"tag2"} +!17 = !{i32 7, !"Dwarf Version", i32 5} +!18 = !{i32 2, !"Debug Info Version", i32 3} +!19 = !{i32 1, !"wchar_size", i32 4} +!20 = !{i32 7, !"frame-pointer", i32 2} +!21 = !{!"clang, some version"} diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-multiple-tags.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-multiple-tags.ll new file mode 100644 index 0000000000000..5ed0bd2aa27ec --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-multiple-tags.ll @@ -0,0 +1,51 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; +; const volatile __tag1 __tag2 int a; +; +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -S -g -emit-llvm test.c -o test.ll + +; Check generation of type tags in chain of CVR modifiers. + +; CHECK: [1] TYPE_TAG 'tag2' type_id=10 +; CHECK: [2] TYPE_TAG 'tag2' type_id=11 +; CHECK: [3] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED +; CHECK: [4] TYPE_TAG 'tag1' type_id=3 +; CHECK: [5] TYPE_TAG 'tag2' type_id=4 +; CHECK: [6] VAR 'a' type_id=1, linkage=global +; CHECK: [7] DATASEC '.rodata' size=0 vlen=1 +; CHECK: type_id=6 offset=0 size=4 +; CHECK: [8] VOLATILE '(anon)' type_id=3 +; CHECK: [9] CONST '(anon)' type_id=8 +; CHECK: [10] TYPE_TAG 'tag1' type_id=9 +; CHECK: [11] TYPE_TAG 'tag1' type_id=8 + +@a = dso_local constant i32 0, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!11, !12, !13, !14} +!llvm.ident = !{!15} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 4, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang, some version", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "some-file.c", directory: "/some/dir/") +!4 = !{!0} +!5 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !6) +!6 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !7) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed, annotations: !8) +!8 = !{!9, !10} +!9 = !{!"btf:type_tag", !"tag1"} +!10 = !{!"btf:type_tag", !"tag2"} +!11 = !{i32 7, !"Dwarf Version", i32 5} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{i32 7, !"frame-pointer", i32 2} +!15 = !{!"clang, some version"} diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-reuse-2.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-reuse-2.ll new file mode 100644 index 0000000000000..6b3455112021f --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-reuse-2.ll @@ -0,0 +1,52 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; +; const volatile __tag1 int a; +; const volatile __tag1 int b; +; +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -S -g -emit-llvm test.c -o test.ll + +; Check that const->volatile->type_tag chain is reused for variables 'a' and 'b'. + +; CHECK: [1] TYPE_TAG 'tag1' type_id=9 +; CHECK: [2] TYPE_TAG 'tag1' type_id=8 +; CHECK: [3] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED +; CHECK: [4] TYPE_TAG 'tag1' type_id=3 +; CHECK: [5] VAR 'a' type_id=1, linkage=global +; CHECK: [6] VAR 'b' type_id=1, linkage=global +; CHECK: [7] DATASEC '.rodata' size=0 vlen=2 +; CHECK: type_id=5 offset=0 size=4 +; CHECK: type_id=6 offset=0 size=4 +; CHECK: [8] VOLATILE '(anon)' type_id=3 +; CHECK: [9] CONST '(anon)' type_id=8 + +@a = dso_local constant i32 0, align 4, !dbg !0 +@b = dso_local constant i32 0, align 4, !dbg !5 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!12, !13, !14, !15} +!llvm.ident = !{!16} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 3, type: !7, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang, some version", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "some-file.c", directory: "/some/dir/") +!4 = !{!0, !5} +!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression()) +!6 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 4, type: !7, isLocal: false, isDefinition: true) +!7 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !8) +!8 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !9) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed, annotations: !10) +!10 = !{!11} +!11 = !{!"btf:type_tag", !"tag1"} +!12 = !{i32 7, !"Dwarf Version", i32 5} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{i32 7, !"frame-pointer", i32 2} +!16 = !{!"clang, some version"} diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-reuse.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-reuse.ll new file mode 100644 index 0000000000000..787a10053bb45 --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-reuse.ll @@ -0,0 +1,55 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; +; const volatile __tag1 int a; +; volatile int b; +; +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -S -g -emit-llvm test.c -o test.ll + +; Check that volatile->int chain is reused for variables 'a' and 'b'. + +; CHECK: [1] TYPE_TAG 'tag1' type_id=10 +; CHECK: [2] TYPE_TAG 'tag1' type_id=6 +; CHECK: [3] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED +; CHECK: [4] TYPE_TAG 'tag1' type_id=3 +; CHECK: [5] VAR 'a' type_id=1, linkage=global +; CHECK: [6] VOLATILE '(anon)' type_id=3 +; CHECK: [7] VAR 'b' type_id=6, linkage=global +; CHECK: [8] DATASEC '.bss' size=0 vlen=1 +; CHECK: type_id=7 offset=0 size=4 +; CHECK: [9] DATASEC '.rodata' size=0 vlen=1 +; CHECK: type_id=5 offset=0 size=4 +; CHECK: [10] CONST '(anon)' type_id=6 + +@a = dso_local constant i32 0, align 4, !dbg !0 +@b = dso_local global i32 0, align 4, !dbg !5 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!14, !15, !16, !17} +!llvm.ident = !{!18} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 3, type: !9, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang, some version", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "some-file.c", directory: "/some/dir/") +!4 = !{!0, !5} +!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression()) +!6 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 4, type: !7, isLocal: false, isDefinition: true) +!7 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !8) +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !10) +!10 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !11) +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed, annotations: !12) +!12 = !{!13} +!13 = !{!"btf:type_tag", !"tag1"} +!14 = !{i32 7, !"Dwarf Version", i32 5} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{i32 1, !"wchar_size", i32 4} +!17 = !{i32 7, !"frame-pointer", i32 2} +!18 = !{!"clang, some version"} diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-simple.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-simple.ll new file mode 100644 index 0000000000000..55f63ebdce709 --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-cvr-simple.ll @@ -0,0 +1,44 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; +; const volatile __tag1 int a; +; +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -S -g -emit-llvm test.c -o test.ll + +; CHECK: [1] TYPE_TAG 'tag1' type_id=8 +; CHECK: [2] TYPE_TAG 'tag1' type_id=7 +; CHECK: [3] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED +; CHECK: [4] TYPE_TAG 'tag1' type_id=3 +; CHECK: [5] VAR 'a' type_id=1, linkage=global +; CHECK: [6] DATASEC '.rodata' size=0 vlen=1 +; CHECK: type_id=5 offset=0 size=4 +; CHECK: [7] VOLATILE '(anon)' type_id=3 +; CHECK: [8] CONST '(anon)' type_id=7 + +@a = dso_local constant i32 0, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!10, !11, !12, !13} +!llvm.ident = !{!14} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 3, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang, some version", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "some-file.c", directory: "/some/dir/") +!4 = !{!0} +!5 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !6) +!6 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !7) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed, annotations: !8) +!8 = !{!9} +!9 = !{!"btf:type_tag", !"tag1"} +!10 = !{i32 7, !"Dwarf Version", i32 5} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 4} +!13 = !{i32 7, !"frame-pointer", i32 2} +!14 = !{!"clang, some version"} diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-decl-tag-typedef.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-decl-tag-typedef.ll new file mode 100644 index 0000000000000..1ed034570c852 --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-decl-tag-typedef.ll @@ -0,0 +1,66 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; #define __dtag1 __attribute__((btf_decl_tag("dtag1"))) +; #define __dtag2 __attribute__((btf_decl_tag("dtag2"))) +; +; typedef int __tag1 __dtag1 foo; +; typedef foo __tag2 __dtag2 bar; +; struct buz { +; bar a; +; } g; +; +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -S -g -emit-llvm test.c -o test.ll + +; Verify that for both 'foo' and 'bar' btf_decl_tag applies to 'typedef' ID. + +; CHECK: [1] STRUCT 'buz' size=4 vlen=1 +; CHECK: 'a' type_id=2 bits_offset=0 +; CHECK: [2] TYPEDEF 'bar' type_id=5 +; CHECK: [3] DECL_TAG 'dtag2' type_id=2 component_idx=-1 +; CHECK: [4] TYPEDEF 'foo' type_id=8 +; CHECK: [5] TYPE_TAG 'tag2' type_id=4 +; CHECK: [6] DECL_TAG 'dtag1' type_id=4 component_idx=-1 +; CHECK: [7] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED +; CHECK: [8] TYPE_TAG 'tag1' type_id=7 +; CHECK: [9] VAR 'g' type_id=1, linkage=global +; CHECK: [10] DATASEC '.bss' size=0 vlen=1 +; CHECK: type_id=9 offset=0 size=4 + +%struct.buz = type { i32 } + +@g = dso_local global %struct.buz zeroinitializer, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!18, !19, !20, !21} +!llvm.ident = !{!22} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 10, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang, some version", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "some-file.c", directory: "/some/dir/") +!4 = !{!0} +!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "buz", file: !3, line: 8, size: 32, elements: !6) +!6 = !{!7} +!7 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !5, file: !3, line: 9, baseType: !8, size: 32) +!8 = !DIDerivedType(tag: DW_TAG_typedef, name: "bar", file: !3, line: 7, baseType: !9, annotations: !16) +!9 = !DIDerivedType(tag: DW_TAG_typedef, name: "foo", file: !3, line: 6, baseType: !10, annotations: !13) +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed, annotations: !11) +!11 = !{!12} +!12 = !{!"btf:type_tag", !"tag1"} +!13 = !{!14, !15} +!14 = !{!"btf:type_tag", !"tag2"} +!15 = !{!"btf_decl_tag", !"dtag1"} +!16 = !{!17} +!17 = !{!"btf_decl_tag", !"dtag2"} +!18 = !{i32 7, !"Dwarf Version", i32 5} +!19 = !{i32 2, !"Debug Info Version", i32 3} +!20 = !{i32 1, !"wchar_size", i32 4} +!21 = !{i32 7, !"frame-pointer", i32 2} +!22 = !{!"clang, some version"} diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-enum.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-enum.ll new file mode 100644 index 0000000000000..7c1b97ccfc38c --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-enum.ll @@ -0,0 +1,87 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; +; enum foo { FOO }; +; +; struct bar { +; enum foo __tag1 aa; +; enum foo __tag2 bb; +; enum foo cc; +; }; +; +; void root(struct bar *bar) {} +; +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -S -g -emit-llvm test.c -o test.ll + +; Check that enum entry is not duplicated in BTF despite duplication in DWARF +; (entries in DWARF are duplicated because of the presence of type tags). + +; CHECK: [[[#]]] STRUCT 'bar' size=12 vlen=3 +; CHECK-NEXT: 'aa' type_id=[[#tag1:]] bits_offset=0 +; CHECK-NEXT: 'bb' type_id=[[#tag2:]] bits_offset=32 +; CHECK-NEXT: 'cc' type_id=[[#foo:]] bits_offset=64 +; CHECK-NEXT: [[[#foo]]] ENUM 'foo' encoding=UNSIGNED size=4 vlen=1 +; CHECK-NEXT: 'FOO' val=0 +; CHECK-NEXT: [[[#tag1]]] TYPE_TAG 'tag1' type_id=4 +; CHECK-NEXT: [[[#tag2]]] TYPE_TAG 'tag2' type_id=4 + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local void @root(ptr noundef %bar) #0 !dbg !15 { +entry: + %bar.addr = alloca ptr, align 8 + store ptr %bar, ptr %bar.addr, align 8 + call void @llvm.dbg.declare(metadata ptr %bar.addr, metadata !31, metadata !DIExpression()), !dbg !32 + ret void, !dbg !33 +} + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9, !10, !11, !12, !13} +!llvm.ident = !{!14} + +!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang, some version", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "some-file.c", directory: "/some/dir/") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "foo", file: !1, line: 4, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FOO", value: 0) +!7 = !{i32 7, !"Dwarf Version", i32 5} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{i32 8, !"PIC Level", i32 2} +!11 = !{i32 7, !"PIE Level", i32 2} +!12 = !{i32 7, !"uwtable", i32 2} +!13 = !{i32 7, !"frame-pointer", i32 2} +!14 = !{!"clang, some version"} +!15 = distinct !DISubprogram(name: "root", scope: !1, file: !1, line: 12, type: !16, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !30) +!16 = !DISubroutineType(types: !17) +!17 = !{null, !18} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bar", file: !1, line: 6, size: 96, elements: !20) +!20 = !{!21, !25, !29} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "aa", scope: !19, file: !1, line: 7, baseType: !22, size: 32) +!22 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "foo", file: !1, line: 4, baseType: !4, size: 32, elements: !5, annotations: !23) +!23 = !{!24} +!24 = !{!"btf:type_tag", !"tag1"} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "bb", scope: !19, file: !1, line: 8, baseType: !26, size: 32, offset: 32) +!26 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "foo", file: !1, line: 4, baseType: !4, size: 32, elements: !5, annotations: !27) +!27 = !{!28} +!28 = !{!"btf:type_tag", !"tag2"} +!29 = !DIDerivedType(tag: DW_TAG_member, name: "cc", scope: !19, file: !1, line: 9, baseType: !3, size: 32, offset: 64) +!30 = !{} +!31 = !DILocalVariable(name: "bar", arg: 1, scope: !15, file: !1, line: 12, type: !18) +!32 = !DILocation(line: 12, column: 23, scope: !15) +!33 = !DILocation(line: 12, column: 29, scope: !15) diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-struct.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-struct.ll new file mode 100644 index 0000000000000..2dd7baaa6e89f --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-struct.ll @@ -0,0 +1,82 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; +; struct foo {}; +; +; struct bar { +; struct foo __tag1 aa; +; struct foo __tag2 bb; +; struct foo cc; +; }; +; +; void root(struct bar *bar) {} +; +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -S -g -emit-llvm test.c -o test.ll + +; Check that struct entry is not duplicated in BTF despite duplication in DWARF +; (entries in DWARF are duplicated because of the presence of type tags). + +; CHECK: [[[#]]] STRUCT 'bar' size=0 vlen=3 +; CHECK-NEXT: 'aa' type_id=[[#tag1:]] bits_offset=0 +; CHECK-NEXT: 'bb' type_id=[[#tag2:]] bits_offset=0 +; CHECK-NEXT: 'cc' type_id=[[#foo:]] bits_offset=0 +; CHECK-NEXT: [[[#foo]]] STRUCT 'foo' size=0 vlen=0 +; CHECK-NEXT: [[[#tag1]]] TYPE_TAG 'tag1' type_id=[[#foo]] +; CHECK-NEXT: [[[#tag2]]] TYPE_TAG 'tag2' type_id=[[#foo]] + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local void @root(ptr noundef %bar) #0 !dbg !10 { +entry: + %bar.addr = alloca ptr, align 8 + store ptr %bar, ptr %bar.addr, align 8 + call void @llvm.dbg.declare(metadata ptr %bar.addr, metadata !27, metadata !DIExpression()), !dbg !28 + ret void, !dbg !29 +} + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang, some version", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "some-file.c", directory: "/some/dir/") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 8, !"PIC Level", i32 2} +!6 = !{i32 7, !"PIE Level", i32 2} +!7 = !{i32 7, !"uwtable", i32 2} +!8 = !{i32 7, !"frame-pointer", i32 2} +!9 = !{!"clang, some version"} +!10 = distinct !DISubprogram(name: "root", scope: !1, file: !1, line: 12, type: !11, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !18) +!11 = !DISubroutineType(types: !12) +!12 = !{null, !13} +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bar", file: !1, line: 6, elements: !15) +!15 = !{!16, !21, !25} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "aa", scope: !14, file: !1, line: 7, baseType: !17) +!17 = !DICompositeType(tag: DW_TAG_structure_type, name: "foo", file: !1, line: 4, elements: !18, annotations: !19) +!18 = !{} +!19 = !{!20} +!20 = !{!"btf:type_tag", !"tag1"} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "bb", scope: !14, file: !1, line: 8, baseType: !22) +!22 = !DICompositeType(tag: DW_TAG_structure_type, name: "foo", file: !1, line: 4, elements: !18, annotations: !23) +!23 = !{!24} +!24 = !{!"btf:type_tag", !"tag2"} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "cc", scope: !14, file: !1, line: 9, baseType: !26) +!26 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo", file: !1, line: 4, elements: !18) +!27 = !DILocalVariable(name: "bar", arg: 1, scope: !10, file: !1, line: 12, type: !13) +!28 = !DILocation(line: 12, column: 23, scope: !10) +!29 = !DILocation(line: 12, column: 29, scope: !10) diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-subroutine.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-subroutine.ll new file mode 100644 index 0000000000000..c78c64fef419e --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-subroutine.ll @@ -0,0 +1,106 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; #define __tag3 __attribute__((btf_type_tag("tag3"))) +; +; struct bar { +; void (__tag1 *aa)(int, int); +; void (__tag2 *bb)(int, int); +; void (*cc)(int, int); +; int (__tag3 *dd)(int, int); +; }; +; +; void root(struct bar *bar) {} +; +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -S -g -emit-llvm test.c -o test.ll + +; Check that func_proto entry is not duplicated in BTF despite duplication in DWARF +; (entries in DWARF are duplicated because of the presence of type tags). + +; CHECK: [[[#]]] STRUCT 'bar' size=32 vlen=4 +; CHECK-NEXT: 'aa' type_id=[[#ptag1:]] bits_offset=0 +; CHECK-NEXT: 'bb' type_id=[[#ptag2:]] bits_offset=64 +; CHECK-NEXT: 'cc' type_id=[[#pfunc:]] bits_offset=128 +; CHECK-NEXT: 'dd' type_id=[[#ptag3:]] bits_offset=192 +; CHECK-NEXT: [[[#ptag1]]] PTR '(anon)' type_id=[[#tag1:]] +; CHECK-NEXT: [[[#func:]]] FUNC_PROTO '(anon)' ret_type_id=0 vlen=2 +; CHECK-NEXT: '(anon)' type_id=[[#int:]] +; CHECK-NEXT: '(anon)' type_id=[[#int]] +; CHECK-NEXT: [[[#tag1]]] TYPE_TAG 'tag1' type_id=[[#func]] +; CHECK-NEXT: [[[#int]]] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED +; CHECK-NEXT: [[[#ptag2]]] PTR '(anon)' type_id=[[#tag2:]] +; CHECK-NEXT: [[[#tag2]]] TYPE_TAG 'tag2' type_id=[[#func]] +; CHECK-NEXT: [[[#pfunc]]] PTR '(anon)' type_id=[[#func]] +; CHECK-NEXT: [[[#ptag3]]] PTR '(anon)' type_id=[[#tag3:]] +; CHECK-NEXT: [[[#func2:]]] FUNC_PROTO '(anon)' ret_type_id=[[#int]] vlen=2 +; CHECK-NEXT: '(anon)' type_id=[[#int]] +; CHECK-NEXT: '(anon)' type_id=[[#int]] +; CHECK-NEXT: [[[#tag3]]] TYPE_TAG 'tag3' type_id=[[#func2]] + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local void @root(ptr noundef %bar) #0 !dbg !10 { +entry: + %bar.addr = alloca ptr, align 8 + store ptr %bar, ptr %bar.addr, align 8 + tail call void @llvm.dbg.declare(metadata ptr %bar.addr, metadata !38, metadata !DIExpression()), !dbg !39 + ret void, !dbg !40 +} + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang some version", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "some-file.c", directory: "/some/dir") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 8, !"PIC Level", i32 2} +!6 = !{i32 7, !"PIE Level", i32 2} +!7 = !{i32 7, !"uwtable", i32 2} +!8 = !{i32 7, !"frame-pointer", i32 2} +!9 = !{!"clang some version"} +!10 = distinct !DISubprogram(name: "root", scope: !1, file: !1, line: 12, type: !11, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !37) +!11 = !DISubroutineType(types: !12) +!12 = !{null, !13} +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bar", file: !1, line: 5, size: 256, elements: !15) +!15 = !{!16, !23, !28, !31} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "aa", scope: !14, file: !1, line: 6, baseType: !17, size: 64) +!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64) +!18 = !DISubroutineType(types: !19, annotations: !21) +!19 = !{null, !20, !20} +!20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!21 = !{!22} +!22 = !{!"btf:type_tag", !"tag1"} +!23 = !DIDerivedType(tag: DW_TAG_member, name: "bb", scope: !14, file: !1, line: 7, baseType: !24, size: 64, offset: 64) +!24 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !25, size: 64) +!25 = !DISubroutineType(types: !19, annotations: !26) +!26 = !{!27} +!27 = !{!"btf:type_tag", !"tag2"} +!28 = !DIDerivedType(tag: DW_TAG_member, name: "cc", scope: !14, file: !1, line: 8, baseType: !29, size: 64, offset: 128) +!29 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !30, size: 64) +!30 = !DISubroutineType(types: !19) +!31 = !DIDerivedType(tag: DW_TAG_member, name: "dd", scope: !14, file: !1, line: 9, baseType: !32, size: 64, offset: 192) +!32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64) +!33 = !DISubroutineType(types: !34, annotations: !35) +!34 = !{!20, !20, !20} +!35 = !{!36} +!36 = !{!"btf:type_tag", !"tag3"} +!37 = !{} +!38 = !DILocalVariable(name: "bar", arg: 1, scope: !10, file: !1, line: 12, type: !13) +!39 = !DILocation(line: 12, column: 23, scope: !10) +!40 = !DILocation(line: 12, column: 29, scope: !10) diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-typedef.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-typedef.ll new file mode 100644 index 0000000000000..d1c34d6e4cccd --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-typedef.ll @@ -0,0 +1,84 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; +; typedef int foo; +; +; struct bar { +; foo __tag1 aa; +; foo __tag2 bb; +; foo cc; +; }; +; +; void root(struct bar *bar) {} +; +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -S -g -emit-llvm test.c -o test.ll + +; Check that typedef entry is not duplicated in BTF despite duplication in DWARF +; (entries in DWARF are duplicated because of the presence of type tags). + +; CHECK: [[[#]]] STRUCT 'bar' size=12 vlen=3 +; CHECK-NEXT: 'aa' type_id=[[#tag1:]] bits_offset=0 +; CHECK-NEXT: 'bb' type_id=[[#tag2:]] bits_offset=32 +; CHECK-NEXT: 'cc' type_id=[[#foo:]] bits_offset=64 +; CHECK-NEXT: [[[#foo]]] TYPEDEF 'foo' type_id=6 +; CHECK-NEXT: [[[#tag1]]] TYPE_TAG 'tag1' type_id=[[#foo]] +; CHECK-NEXT: [[[#]]] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED +; CHECK-NEXT: [[[#tag2]]] TYPE_TAG 'tag2' type_id=[[#foo]] + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local void @root(ptr noundef %bar) #0 !dbg !10 { +entry: + %bar.addr = alloca ptr, align 8 + store ptr %bar, ptr %bar.addr, align 8 + call void @llvm.dbg.declare(metadata ptr %bar.addr, metadata !28, metadata !DIExpression()), !dbg !29 + ret void, !dbg !30 +} + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang, some version", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "some-file.c", directory: "/some/dir/") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 8, !"PIC Level", i32 2} +!6 = !{i32 7, !"PIE Level", i32 2} +!7 = !{i32 7, !"uwtable", i32 2} +!8 = !{i32 7, !"frame-pointer", i32 2} +!9 = !{!"clang, some version"} +!10 = distinct !DISubprogram(name: "root", scope: !1, file: !1, line: 12, type: !11, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !27) +!11 = !DISubroutineType(types: !12) +!12 = !{null, !13} +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bar", file: !1, line: 6, size: 96, elements: !15) +!15 = !{!16, !21, !25} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "aa", scope: !14, file: !1, line: 7, baseType: !17, size: 32) +!17 = !DIDerivedType(tag: DW_TAG_typedef, name: "foo", file: !1, line: 4, baseType: !18, annotations: !19) +!18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!19 = !{!20} +!20 = !{!"btf:type_tag", !"tag1"} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "bb", scope: !14, file: !1, line: 8, baseType: !22, size: 32, offset: 32) +!22 = !DIDerivedType(tag: DW_TAG_typedef, name: "foo", file: !1, line: 4, baseType: !18, annotations: !23) +!23 = !{!24} +!24 = !{!"btf:type_tag", !"tag2"} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "cc", scope: !14, file: !1, line: 9, baseType: !26, size: 32, offset: 64) +!26 = !DIDerivedType(tag: DW_TAG_typedef, name: "foo", file: !1, line: 4, baseType: !18) +!27 = !{} +!28 = !DILocalVariable(name: "bar", arg: 1, scope: !10, file: !1, line: 12, type: !13) +!29 = !DILocation(line: 12, column: 23, scope: !10) +!30 = !DILocation(line: 12, column: 29, scope: !10) diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-union.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-union.ll new file mode 100644 index 0000000000000..e02dfd8273688 --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-dedup-union.ll @@ -0,0 +1,82 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; +; union foo {}; +; +; struct bar { +; union foo __tag1 aa; +; union foo __tag2 bb; +; union foo cc; +; }; +; +; void root(struct bar *bar) {} +; +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -S -g -emit-llvm test.c -o test.ll + +; Check that union entry is not duplicated in BTF despite duplication in DWARF +; (entries in DWARF are duplicated because of the presence of type tags). + +; CHECK: [[[#]]] STRUCT 'bar' size=0 vlen=3 +; CHECK-NEXT: 'aa' type_id=[[#tag1:]] bits_offset=0 +; CHECK-NEXT: 'bb' type_id=[[#tag2:]] bits_offset=0 +; CHECK-NEXT: 'cc' type_id=[[#foo:]] bits_offset=0 +; CHECK-NEXT: [[[#foo]]] UNION 'foo' size=0 vlen=0 +; CHECK-NEXT: [[[#tag1]]] TYPE_TAG 'tag1' type_id=[[#foo]] +; CHECK-NEXT: [[[#tag2]]] TYPE_TAG 'tag2' type_id=[[#foo]] + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local void @root(ptr noundef %bar) #0 !dbg !10 { +entry: + %bar.addr = alloca ptr, align 8 + store ptr %bar, ptr %bar.addr, align 8 + call void @llvm.dbg.declare(metadata ptr %bar.addr, metadata !27, metadata !DIExpression()), !dbg !28 + ret void, !dbg !29 +} + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang, some version", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "some-file.c", directory: "/some/dir/") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 8, !"PIC Level", i32 2} +!6 = !{i32 7, !"PIE Level", i32 2} +!7 = !{i32 7, !"uwtable", i32 2} +!8 = !{i32 7, !"frame-pointer", i32 2} +!9 = !{!"clang, some version"} +!10 = distinct !DISubprogram(name: "root", scope: !1, file: !1, line: 12, type: !11, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !18) +!11 = !DISubroutineType(types: !12) +!12 = !{null, !13} +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bar", file: !1, line: 6, elements: !15) +!15 = !{!16, !21, !25} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "aa", scope: !14, file: !1, line: 7, baseType: !17) +!17 = !DICompositeType(tag: DW_TAG_union_type, name: "foo", file: !1, line: 4, elements: !18, annotations: !19) +!18 = !{} +!19 = !{!20} +!20 = !{!"btf:type_tag", !"tag1"} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "bb", scope: !14, file: !1, line: 8, baseType: !22) +!22 = !DICompositeType(tag: DW_TAG_union_type, name: "foo", file: !1, line: 4, elements: !18, annotations: !23) +!23 = !{!24} +!24 = !{!"btf:type_tag", !"tag2"} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "cc", scope: !14, file: !1, line: 9, baseType: !26) +!26 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "foo", file: !1, line: 4, elements: !18) +!27 = !DILocalVariable(name: "bar", arg: 1, scope: !10, file: !1, line: 12, type: !13) +!28 = !DILocation(line: 12, column: 23, scope: !10) +!29 = !DILocation(line: 12, column: 29, scope: !10) diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-field-relo.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-field-relo.ll new file mode 100644 index 0000000000000..af697fa272290 --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-field-relo.ll @@ -0,0 +1,103 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s | llvm-objdump -dr --no-show-raw-insn - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s | llvm-objdump -dr --no-show-raw-insn - | FileCheck %s +; +; Source: +; +; #define __pai __attribute__((preserve_access_index)); +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; +; struct alpha { +; int zulu; +; } __pai; +; +; struct bravo { +; struct alpha __tag1 *yankee; +; } __pai; +; +; int func(struct bravo *xray) { +; return xray->yankee->zulu; +; } +; +; Compilation command: +; +; cat test.c | clang -mllvm -btf-type-tag-v2 -x c -target bpf -O2 -g -emit-llvm -S - -o - +; +; The relocation entry for zulu should point to STRUCT 'alpha', +; not TYPE_TAG 'tag1' -> STRUCT 'alpha'. + +@"llvm.alpha:0:0$0:0" = external global i64, !llvm.preserve.access.index !0 #0 +@"llvm.bravo:0:0$0:0" = external global i64, !llvm.preserve.access.index !8 #0 + +; Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none) +define dso_local i32 @func(ptr noundef readonly %xray) local_unnamed_addr #1 !dbg !20 { +entry: + tail call void @llvm.dbg.value(metadata ptr %xray, metadata !25, metadata !DIExpression()), !dbg !26 + %0 = load i64, ptr @"llvm.bravo:0:0$0:0", align 8 + %1 = getelementptr i8, ptr %xray, i64 %0 + %2 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 1, ptr %1) + %3 = load ptr, ptr %2, align 8, !dbg !27, !tbaa !28 + %4 = load i64, ptr @"llvm.alpha:0:0$0:0", align 8 + %5 = getelementptr i8, ptr %3, i64 %4 + %6 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 0, ptr %5) + %7 = load i32, ptr %6, align 4, !dbg !33, !tbaa !34 + ret i32 %7, !dbg !37 +} + +; CHECK: r[[#]] = *(u64 *)(r[[#]] + 0x0) +; CHECK-NEXT: CO-RE [[[#]]] struct bravo::yankee (0:0) +; CHECK-NEXT: r[[#]] = *(u32 *)(r[[#]] + 0x0) +; CHECK-NEXT: CO-RE [[[#]]] struct alpha::zulu (0:0) + +; Function Attrs: nofree nosync nounwind memory(none) +declare ptr @llvm.bpf.passthrough.p0.p0(i32, ptr) #2 + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { "btf_ama" } +attributes #1 = { nofree nosync nounwind memory(read, inaccessiblemem: none) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #2 = { nofree nosync nounwind memory(none) } +attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } + +!llvm.dbg.cu = !{!12} +!llvm.module.flags = !{!14, !15, !16, !17, !18} +!llvm.ident = !{!19} + +!0 = !DICompositeType(tag: DW_TAG_structure_type, name: "alpha", file: !1, line: 4, size: 32, elements: !2, annotations: !6) +!1 = !DIFile(filename: "some-file.c", directory: "/some/dir") +!2 = !{!3} +!3 = !DIDerivedType(tag: DW_TAG_member, name: "zulu", scope: !4, file: !1, line: 5, baseType: !5, size: 32) +!4 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "alpha", file: !1, line: 4, size: 32, elements: !2) +!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!6 = !{!7} +!7 = !{!"btf:type_tag", !"tag1"} +!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bravo", file: !1, line: 8, size: 64, elements: !9) +!9 = !{!10} +!10 = !DIDerivedType(tag: DW_TAG_member, name: "yankee", scope: !8, file: !1, line: 9, baseType: !11, size: 64) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !0, size: 64) +!12 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang some version", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !13, splitDebugInlining: false, nameTableKind: None) +!13 = !{!0} +!14 = !{i32 7, !"Dwarf Version", i32 5} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{i32 1, !"wchar_size", i32 4} +!17 = !{i32 7, !"frame-pointer", i32 2} +!18 = !{i32 7, !"debug-info-assignment-tracking", i1 true} +!19 = !{!"clang, some version"} +!20 = distinct !DISubprogram(name: "func", scope: !1, file: !1, line: 12, type: !21, scopeLine: 12, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !12, retainedNodes: !24) +!21 = !DISubroutineType(types: !22) +!22 = !{!5, !23} +!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64) +!24 = !{!25} +!25 = !DILocalVariable(name: "xray", arg: 1, scope: !20, file: !1, line: 12, type: !23) +!26 = !DILocation(line: 0, scope: !20) +!27 = !DILocation(line: 13, column: 16, scope: !20) +!28 = !{!29, !30, i64 0} +!29 = !{!"bravo", !30, i64 0} +!30 = !{!"any pointer", !31, i64 0} +!31 = !{!"omnipotent char", !32, i64 0} +!32 = !{!"Simple C/C++ TBAA"} +!33 = !DILocation(line: 13, column: 24, scope: !20) +!34 = !{!35, !36, i64 0} +!35 = !{!"alpha", !36, i64 0} +!36 = !{!"int", !31, i64 0} +!37 = !DILocation(line: 13, column: 3, scope: !20) diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-fixup-fwd-v2.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-fixup-fwd-v2.ll new file mode 100644 index 0000000000000..bfca93f9c4407 --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-fixup-fwd-v2.ll @@ -0,0 +1,102 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; +; struct foo; +; struct map_value { +; struct foo __tag2 __tag1 *ptr; +; }; +; void func(struct map_value *); +; void test(void) +; { +; struct map_value v = {}; +; func(&v); +; } +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -target bpf -O2 -g -S -emit-llvm test.c + +; Check generation of type tags attached to forward declaration. + +; CHECK: [1] FUNC_PROTO '(anon)' ret_type_id=0 vlen=0 +; CHECK: [2] FUNC 'test' type_id=1 linkage=global +; CHECK: [3] FUNC_PROTO '(anon)' ret_type_id=0 vlen=1 +; CHECK: '(anon)' type_id=4 +; CHECK: [4] PTR '(anon)' type_id=5 +; CHECK: [5] STRUCT 'map_value' size=8 vlen=1 +; CHECK: 'ptr' type_id=6 bits_offset=0 +; CHECK: [6] PTR '(anon)' type_id=9 +; CHECK: [7] FWD 'foo' fwd_kind=struct +; CHECK: [8] TYPE_TAG 'tag2' type_id=7 +; CHECK: [9] TYPE_TAG 'tag1' type_id=8 +; CHECK: [10] FUNC 'func' type_id=3 linkage=extern + +%struct.map_value = type { ptr } + +; Function Attrs: nounwind +define dso_local void @test() local_unnamed_addr #0 !dbg !7 { +entry: + %v = alloca %struct.map_value, align 8 + call void @llvm.lifetime.start.p0(i64 8, ptr nonnull %v) #4, !dbg !23 + call void @llvm.dbg.declare(metadata ptr %v, metadata !11, metadata !DIExpression()), !dbg !24 + store i64 0, ptr %v, align 8, !dbg !24 + call void @func(ptr noundef nonnull %v) #4, !dbg !25 + call void @llvm.lifetime.end.p0(i64 8, ptr nonnull %v) #4, !dbg !26 + ret void, !dbg !26 +} + +; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #1 + +; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare void @llvm.dbg.declare(metadata, metadata, metadata) #2 + +declare !dbg !27 dso_local void @func(ptr noundef) local_unnamed_addr #3 + +; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #1 + +attributes #0 = { nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +attributes #2 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) } +attributes #3 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang, some", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "some-file.c", directory: "/some/dir/") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"frame-pointer", i32 2} +!6 = !{!"clang, some version"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !8, scopeLine: 10, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10) +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!10 = !{!11} +!11 = !DILocalVariable(name: "v", scope: !7, file: !1, line: 11, type: !12) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "map_value", file: !1, line: 5, size: 64, elements: !13) +!13 = !{!14} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "ptr", scope: !12, file: !1, line: 6, baseType: !15, size: 64) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "foo", file: !1, line: 4, flags: DIFlagFwdDecl, annotations: !17) +!17 = !{!18, !19} +!18 = !{!"btf:type_tag", !"tag2"} +!19 = !{!"btf:type_tag", !"tag1"} +!23 = !DILocation(line: 11, column: 9, scope: !7) +!24 = !DILocation(line: 11, column: 26, scope: !7) +!25 = !DILocation(line: 12, column: 9, scope: !7) +!26 = !DILocation(line: 13, column: 1, scope: !7) +!27 = !DISubprogram(name: "func", scope: !1, file: !1, line: 8, type: !28, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !31) +!28 = !DISubroutineType(types: !29) +!29 = !{null, !30} +!30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!31 = !{!32} +!32 = !DILocalVariable(arg: 1, scope: !27, file: !1, line: 8, type: !30) diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-fixup-resolved-v2.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-fixup-resolved-v2.ll new file mode 100644 index 0000000000000..e70c43e28315d --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-fixup-resolved-v2.ll @@ -0,0 +1,112 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; +; struct foo { +; int i; +; }; +; struct map_value { +; struct foo __tag2 __tag1 *ptr; +; }; +; void func(struct map_value *, struct foo *); +; void test(void) +; { +; struct map_value v = {}; +; func(&v, v.ptr); +; } +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -target bpf -O2 -g -S -emit-llvm test.c + +; CHECK: [1] FUNC_PROTO '(anon)' ret_type_id=0 vlen=0 +; CHECK: [2] FUNC 'test' type_id=1 linkage=global +; CHECK: [3] FUNC_PROTO '(anon)' ret_type_id=0 vlen=2 +; CHECK: '(anon)' type_id=4 +; CHECK: '(anon)' type_id=7 +; CHECK: [4] PTR '(anon)' type_id=5 +; CHECK: [5] STRUCT 'map_value' size=8 vlen=1 +; CHECK: 'ptr' type_id=6 bits_offset=0 +; CHECK: [6] PTR '(anon)' type_id=12 +; CHECK: [7] PTR '(anon)' type_id=8 +; CHECK: [8] STRUCT 'foo' size=4 vlen=1 +; CHECK: 'i' type_id=9 bits_offset=0 +; CHECK: [9] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED +; CHECK: [10] FUNC 'func' type_id=3 linkage=extern +; CHECK: [11] TYPE_TAG 'tag2' type_id=8 +; CHECK: [12] TYPE_TAG 'tag1' type_id=11 + +%struct.map_value = type { ptr } + +; Function Attrs: nounwind +define dso_local void @test() local_unnamed_addr #0 !dbg !7 { +entry: + %v = alloca %struct.map_value, align 8 + call void @llvm.lifetime.start.p0(i64 8, ptr nonnull %v) #4, !dbg !27 + call void @llvm.dbg.declare(metadata ptr %v, metadata !11, metadata !DIExpression()), !dbg !28 + store i64 0, ptr %v, align 8, !dbg !28 + call void @func(ptr noundef nonnull %v, ptr noundef null) #4, !dbg !29 + call void @llvm.lifetime.end.p0(i64 8, ptr nonnull %v) #4, !dbg !30 + ret void, !dbg !30 +} + +; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #1 + +; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare void @llvm.dbg.declare(metadata, metadata, metadata) #2 + +declare !dbg !31 dso_local void @func(ptr noundef, ptr noundef) local_unnamed_addr #3 + +; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #1 + +attributes #0 = { nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +attributes #2 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) } +attributes #3 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang, some version", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "some-file.c", directory: "/some/dir/") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"frame-pointer", i32 2} +!6 = !{!"clang, some version"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 11, type: !8, scopeLine: 12, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10) +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!10 = !{!11} +!11 = !DILocalVariable(name: "v", scope: !7, file: !1, line: 13, type: !12) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "map_value", file: !1, line: 7, size: 64, elements: !13) +!13 = !{!14} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "ptr", scope: !12, file: !1, line: 8, baseType: !15, size: 64) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "foo", file: !1, line: 4, size: 32, elements: !17, annotations: !21) +!17 = !{!18} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 5, baseType: !20, size: 32) +!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo", file: !1, line: 4, size: 32, elements: !17) +!20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!21 = !{!22, !23} +!22 = !{!"btf:type_tag", !"tag2"} +!23 = !{!"btf:type_tag", !"tag1"} +!27 = !DILocation(line: 13, column: 9, scope: !7) +!28 = !DILocation(line: 13, column: 26, scope: !7) +!29 = !DILocation(line: 14, column: 9, scope: !7) +!30 = !DILocation(line: 15, column: 1, scope: !7) +!31 = !DISubprogram(name: "func", scope: !1, file: !1, line: 10, type: !32, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !36) +!32 = !DISubroutineType(types: !33) +!33 = !{null, !34, !35} +!34 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!35 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!36 = !{!37, !38} +!37 = !DILocalVariable(arg: 1, scope: !31, file: !1, line: 10, type: !34) +!38 = !DILocalVariable(arg: 2, scope: !31, file: !1, line: 10, type: !35) diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-skip-var.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-skip-var.ll new file mode 100644 index 0000000000000..d38fcfac02f96 --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-skip-var.ll @@ -0,0 +1,49 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; int __tag1 *aa; +; int __tag1 bb; +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -S -g -emit-llvm test.c -o test.ll +; +; BTF VAR entry for `b` should be stripped of type tag. + +; CHECK: [1] PTR '(anon)' type_id=3 +; CHECK: [2] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED +; CHECK: [3] TYPE_TAG 'tag1' type_id=2 +; CHECK: [4] VAR 'aa' type_id=1, linkage=global +; CHECK: [5] VAR 'bb' type_id=2, linkage=global +; CHECK: [6] DATASEC '.bss' size=0 vlen=2 +; CHECK: type_id=4 offset=0 size=8 +; CHECK: type_id=5 offset=0 size=4 + +@aa = dso_local global ptr null, align 8, !dbg !0 +@bb = dso_local global i32 0, align 4, !dbg !5 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!11, !12, !13, !14, !15, !16, !17} +!llvm.ident = !{!18} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "aa", scope: !2, file: !3, line: 2, type: !10, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang, some version", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "some-file.c", directory: "/some/dir") +!4 = !{!0, !5} +!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression()) +!6 = distinct !DIGlobalVariable(name: "bb", scope: !2, file: !3, line: 3, type: !7, isLocal: false, isDefinition: true) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed, annotations: !8) +!8 = !{!9} +!9 = !{!"btf:type_tag", !"tag1"} +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!11 = !{i32 7, !"Dwarf Version", i32 5} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{i32 8, !"PIC Level", i32 2} +!15 = !{i32 7, !"PIE Level", i32 2} +!16 = !{i32 7, !"uwtable", i32 2} +!17 = !{i32 7, !"frame-pointer", i32 2} +!18 = !{!"clang, some version"} diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-var-v2.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-var-v2.ll new file mode 100644 index 0000000000000..482fc5c0acbeb --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-var-v2.ll @@ -0,0 +1,46 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; int __tag1 * __tag1 __tag2 *g; +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -target bpf -O2 -g -S -emit-llvm test.c + +; CHECK: [1] PTR '(anon)' type_id=4 +; CHECK: [2] PTR '(anon)' type_id=6 +; CHECK: [3] TYPE_TAG 'tag1' type_id=2 +; CHECK: [4] TYPE_TAG 'tag2' type_id=3 +; CHECK: [5] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED +; CHECK: [6] TYPE_TAG 'tag1' type_id=5 +; CHECK: [7] VAR 'g' type_id=1, linkage=global +; CHECK: [8] DATASEC '.bss' size=0 vlen=1 +; CHECK: type_id=7 offset=0 size=8 + +@g = dso_local local_unnamed_addr global ptr null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!12, !13, !14, !15} +!llvm.ident = !{!16} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 3, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang, some version", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "some-file.c", directory: "/some/dir") +!4 = !{!0} +!5 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64) +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64, annotations: !10) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed, annotations: !8) +!8 = !{!9} +!9 = !{!"btf:type_tag", !"tag1"} +!10 = !{!9, !11} +!11 = !{!"btf:type_tag", !"tag2"} + +!12 = !{i32 7, !"Dwarf Version", i32 5} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{i32 7, !"frame-pointer", i32 2} +!16 = !{!"clang, some version"} diff --git a/llvm/test/CodeGen/BPF/BTF/type-tag-void.ll b/llvm/test/CodeGen/BPF/BTF/type-tag-void.ll new file mode 100644 index 0000000000000..2081fa217d7c5 --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/type-tag-void.ll @@ -0,0 +1,43 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s \ +; RUN: | llvm-objcopy --dump-section .BTF=- - | %python %S/print_btf.py - | FileCheck %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; void __tag1 *foo; +; Compilation flag: +; clang -mllvm -btf-type-tag-v2 -S -g -emit-llvm test.c -o test.ll + +; Check that btf:type_tag attached to DW_TAG_unspecified_type is +; converted to type tag referencing 0. + +; CHECK: [1] PTR '(anon)' type_id=2 +; CHECK: [2] TYPE_TAG 'tag1' type_id=0 +; CHECK: [3] VAR 'foo' type_id=1, linkage=global +; CHECK: [4] DATASEC '.bss' size=0 vlen=1 +; CHECK: type_id=3 offset=0 size=8 + +@foo = dso_local global ptr null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!9, !10, !11, !12, !13, !14, !15} +!llvm.ident = !{!16} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "foo", scope: !2, file: !3, line: 2, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang, some version", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "some-file.c", directory: "/some/dir") +!4 = !{!0} +!5 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64) +!6 = !DIBasicType(tag: DW_TAG_unspecified_type, name: "void", annotations: !7) +!7 = !{!8} +!8 = !{!"btf:type_tag", !"tag1"} +!9 = !{i32 7, !"Dwarf Version", i32 5} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{i32 8, !"PIC Level", i32 2} +!13 = !{i32 7, !"PIE Level", i32 2} +!14 = !{i32 7, !"uwtable", i32 2} +!15 = !{i32 7, !"frame-pointer", i32 2} +!16 = !{!"clang, some version"} diff --git a/llvm/test/DebugInfo/attr-btf_type_tag.ll b/llvm/test/DebugInfo/attr-btf_type_tag.ll index 47a2aa59106d1..329b95cb5d63b 100644 --- a/llvm/test/DebugInfo/attr-btf_type_tag.ll +++ b/llvm/test/DebugInfo/attr-btf_type_tag.ll @@ -4,59 +4,121 @@ ; Source: ; #define __tag1 __attribute__((btf_type_tag("tag1"))) ; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; #define __tag3 __attribute__((btf_type_tag("tag3"))) +; #define __tag4 __attribute__((btf_type_tag("tag4"))) +; +; int __tag1 a; +; int * __tag2 b; +; void __tag3 *c; +; void (__tag4 *d)(void); +; ; -; int * __tag1 * __tag2 *g; ; Compilation flag: ; clang -target x86_64 -g -S -emit-llvm t.c +; +; Note: only "btf:type_tag" annotations are checked for brevity. -@g = dso_local global ptr null, align 8, !dbg !0 +@a = dso_local global i32 0, align 4, !dbg !0 +@b = dso_local global ptr null, align 8, !dbg !5 +@c = dso_local global ptr null, align 8, !dbg !11 +@d = dso_local global ptr null, align 8, !dbg !19 !llvm.dbg.cu = !{!2} -!llvm.module.flags = !{!13, !14, !15, !16, !17} -!llvm.ident = !{!18} +!llvm.module.flags = !{!31, !32, !33, !34, !35} +!llvm.ident = !{!36} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) -!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !5, isLocal: false, isDefinition: true) -!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 14.0.0 (https://github.com/llvm/llvm-project.git 2c240a5eefae1a945dfd36cdaa0c677eca90dd82)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) -!3 = !DIFile(filename: "t.c", directory: "/home/yhs/work/tests/llvm/btf_tag_type") -!4 = !{!0} -!5 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64, annotations: !11) -!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64, annotations: !9) -!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 6, type: !28, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang version 17.0.0 (https://github.com/llvm/llvm-project.git ffde01565bce81795ba0442108742557a9a4562d)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/home/eddy/work/tmp", checksumkind: CSK_MD5, checksum: "71845c02e58f6b1a8b0162797b4d3f37") +!4 = !{!0, !5, !11, !19} +!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression()) + +; CHECK: DW_TAG_variable +; CHECK-NEXT: DW_AT_name ("a") +; CHECK-NEXT: DW_AT_type (0x[[T1:[0-9a-f]+]] "int") + +; CHECK: 0x[[T1]]: DW_TAG_base_type +; CHECK-NEXT: DW_AT_name ("int") + +; CHECK: DW_TAG_LLVM_annotation +; CHECK-NEXT: DW_AT_name ("btf:type_tag") +; CHECK-NEXT: DW_AT_const_value ("tag1") + +!6 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 7, type: !7, isLocal: false, isDefinition: true) +!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64, annotations: !9) !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !9 = !{!10} -!10 = !{!"btf_type_tag", !"tag1"} -!11 = !{!12} -!12 = !{!"btf_type_tag", !"tag2"} +!10 = !{!"btf:type_tag", !"tag2"} +!11 = !DIGlobalVariableExpression(var: !12, expr: !DIExpression()) + +; CHECK: DW_TAG_variable +; CHECK-NEXT: DW_AT_name ("b") +; CHECK-NEXT: DW_AT_type (0x[[T2:[0-9a-f]+]] "int *") + +; CHECK: 0x[[T2]]: DW_TAG_pointer_type +; CHECK-NEXT: DW_AT_type (0x[[T3:[0-9a-f]+]] "int") + +; CHECK: DW_TAG_LLVM_annotation +; CHECK-NEXT: DW_AT_name ("btf:type_tag") +; CHECK-NEXT: DW_AT_const_value ("tag2") + +; CHECK: 0x[[T3]]: DW_TAG_base_type +; CHECK-NEXT: DW_AT_name ("int") +; CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) + +!12 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 8, type: !13, isLocal: false, isDefinition: true) +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64, annotations: !17) +!14 = !DIBasicType(tag: DW_TAG_unspecified_type, name: "void", annotations: !15) +!15 = !{!16} +!16 = !{!"btf:type_tag", !"tag3"} +!17 = !{!18} +!18 = !{!"btf_type_tag", !"tag3"} + +; CHECK: DW_TAG_variable +; CHECK-NEXT: DW_AT_name ("c") +; CHECK-NEXT: DW_AT_type (0x[[T4:[0-9a-f]+]] "void *") -; CHECK: DW_TAG_variable -; CHECK-NEXT: DW_AT_name ("g") -; CHECK-NEXT: DW_AT_type (0x[[T1:[0-9a-f]+]] "int ***") +; CHECK: 0x[[T4]]: DW_TAG_pointer_type +; CHECK-NEXT: DW_AT_type (0x[[T5:[0-9a-f]+]] "void") -; CHECK: 0x[[T1]]: DW_TAG_pointer_type -; CHECK-NEXT: DW_AT_type (0x[[T2:[0-9a-f]+]] "int **") +; CHECK: 0x[[T5]]: DW_TAG_unspecified_type +; CHECK-NEXT: DW_AT_name ("void") -; CHECK: DW_TAG_LLVM_annotation -; CHECK-NEXT: DW_AT_name ("btf_type_tag") -; CHECK-NEXT: DW_AT_const_value ("tag2") +; CHECK: DW_TAG_LLVM_annotation +; CHECK-NEXT: DW_AT_name ("btf:type_tag") +; CHECK-NEXT: DW_AT_const_value ("tag3") -; CHECK: NULL +!19 = !DIGlobalVariableExpression(var: !20, expr: !DIExpression()) +!20 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 9, type: !21, isLocal: false, isDefinition: true) +!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64, annotations: !26) +!22 = !DISubroutineType(types: !23, annotations: !24) +!23 = !{null} +!24 = !{!25} +!25 = !{!"btf:type_tag", !"tag4"} +!26 = !{!27} +!27 = !{!"btf_type_tag", !"tag4"} +!28 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed, annotations: !29) +!29 = !{!30} +!30 = !{!"btf:type_tag", !"tag1"} -; CHECK: 0x[[T2]]: DW_TAG_pointer_type -; CHECK-NEXT: DW_AT_type (0x[[T3:[0-9a-f]+]] "int *") +; CHECK: DW_TAG_variable +; CHECK-NEXT: DW_AT_name ("d") +; CHECK-NEXT: DW_AT_type (0x[[T6:[0-9a-f]+]] "void (*)(") -; CHECK: DW_TAG_LLVM_annotation -; CHECK-NEXT: DW_AT_name ("btf_type_tag") -; CHECK-NEXT: DW_AT_const_value ("tag1") +; CHECK: 0x[[T6]]: DW_TAG_pointer_type +; CHECK-NEXT: DW_AT_type (0x[[T7:[0-9a-f]+]] "void (") -; CHECK: NULL +; CHECK: 0x[[T7]]: DW_TAG_subroutine_type +; CHECK-NEXT: DW_AT_prototyped (true) -; CHECK: 0x[[T3]]: DW_TAG_pointer_type -; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int") +; CHECK: DW_TAG_LLVM_annotation +; CHECK-NEXT: DW_AT_name ("btf:type_tag") +; CHECK-NEXT: DW_AT_const_value ("tag4") -!13 = !{i32 7, !"Dwarf Version", i32 4} -!14 = !{i32 2, !"Debug Info Version", i32 3} -!15 = !{i32 1, !"wchar_size", i32 4} -!16 = !{i32 7, !"uwtable", i32 1} -!17 = !{i32 7, !"frame-pointer", i32 2} -!18 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git 2c240a5eefae1a945dfd36cdaa0c677eca90dd82)"} +!31 = !{i32 7, !"Dwarf Version", i32 5} +!32 = !{i32 2, !"Debug Info Version", i32 3} +!33 = !{i32 1, !"wchar_size", i32 4} +!34 = !{i32 7, !"uwtable", i32 2} +!35 = !{i32 7, !"frame-pointer", i32 2} +!36 = !{!"clang version 17.0.0 (https://github.com/llvm/llvm-project.git ffde01565bce81795ba0442108742557a9a4562d)"}