diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1558,6 +1558,11 @@ QualType modifiedType, QualType equivalentType); + QualType getAttributedBTFType(attr::Kind attrKind, + QualType modifiedType, + QualType equivalentType, + StringRef BTFTypeTag); + QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced, QualType Replacement) const; QualType getSubstTemplateTypeParmPackType( diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -4675,6 +4675,7 @@ QualType ModifiedType; QualType EquivalentType; +protected: AttributedType(QualType canon, attr::Kind attrKind, QualType modified, QualType equivalent) : Type(Attributed, canon, equivalent->getDependence()), @@ -4762,6 +4763,33 @@ } }; +class AttributedBTFType : public AttributedType { +private: + std::string BTFTypeTag; + +public: + AttributedBTFType(QualType canon, attr::Kind attrKind, QualType modified, + QualType equivalent, StringRef BTFTypeTag) + : AttributedType(canon, attrKind, modified, equivalent) { + this->BTFTypeTag = BTFTypeTag.str(); + } + +public: + StringRef getBTFTypeTag() const { return StringRef(BTFTypeTag); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getAttrKind(), getModifiedType(), getEquivalentType(), + StringRef(BTFTypeTag)); + } + + static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind, + QualType modified, QualType equivalent, + StringRef BTFTypeTag) { + AttributedType::Profile(ID, attrKind, modified, equivalent); + ID.AddString(BTFTypeTag); + } +}; + class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1843,6 +1843,13 @@ let LangOpts = [COnly]; } +def BTFTypeTag : TypeAttr { + let Spellings = [Clang<"btf_type_tag">]; + let Args = [StringArgument<"BTFTypeTag">]; + let Documentation = [Undocumented]; + let LangOpts = [COnly]; +} + def WebAssemblyExportName : InheritableAttr, TargetSpecificAttr { let Spellings = [Clang<"export_name">]; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4641,6 +4641,27 @@ return QualType(type, 0); } +QualType ASTContext::getAttributedBTFType(attr::Kind attrKind, + QualType modifiedType, + QualType equivalentType, + StringRef BTFTypeTag) { + llvm::FoldingSetNodeID id; + AttributedBTFType::Profile(id, attrKind, modifiedType, equivalentType, BTFTypeTag); + + void *insertPos = nullptr; + AttributedType *type = AttributedTypes.FindNodeOrInsertPos(id, insertPos); + if (type) return QualType(type, 0); + + QualType canon = getCanonicalType(equivalentType); + type = new (*this, TypeAlignment) + AttributedBTFType(canon, attrKind, modifiedType, equivalentType, BTFTypeTag); + + Types.push_back(type); + AttributedTypes.InsertNode(type, insertPos); + + return QualType(type, 0); +} + /// Retrieve a substitution-result type. QualType ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1753,6 +1753,9 @@ case attr::ArmMveStrictPolymorphism: OS << "__clang_arm_mve_strict_polymorphism"; break; + case attr::BTFTypeTag: + OS << "btf_type_tag(\"" << cast(T)->getBTFTypeTag() << "\")"; + break; } OS << "))"; } diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1157,13 +1157,38 @@ Optional DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(AddressSpace); + // Find all AttributedBTFTypes for this pointer. + SmallVector Annots; + QualType BaseTy = PointeeTy; + while (true) { + if (auto *MT = dyn_cast(BaseTy.getTypePtr())) { + BaseTy = MT->getUnderlyingType(); + } else if (auto *AT = dyn_cast(BaseTy.getTypePtr())) { + StringRef BTFTypeTag = AT->getBTFTypeTag(); + if (BTFTypeTag[0]) { + llvm::Metadata *Ops[2] = { + llvm::MDString::get(CGM.getLLVMContext(), StringRef("btf_tag")), + llvm::MDString::get(CGM.getLLVMContext(), BTFTypeTag)}; + Annots.insert(Annots.begin(), llvm::MDNode::get(CGM.getLLVMContext(), Ops)); + } + BaseTy = AT->getModifiedType(); + } else { + break; + } + } + + llvm::DINodeArray Annotations = nullptr; + if (Annots.size() > 0) + Annotations = DBuilder.getOrCreateArray(Annots); + 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); + Align, DWARFAddressSpace, StringRef(), + Annotations); } llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name, diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -265,6 +265,17 @@ return T; } + QualType getAttributedBTFType(Attr *A, QualType ModifiedType, + QualType EquivType, + StringRef BTFTypeTag) { + QualType T = + sema.Context.getAttributedBTFType(A->getKind(), ModifiedType, EquivType, + BTFTypeTag); + AttrsForTypes.push_back({cast(T.getTypePtr()), A}); + AttrsForTypesSorted = false; + return T; + } + /// Completely replace the \c auto in \p TypeWithAuto by /// \p Replacement. Also replace \p TypeWithAuto in \c TypeAttrPair if /// necessary. @@ -6500,6 +6511,36 @@ return BuildAddressSpaceAttr(T, ASIdx, AddrSpace, AttrLoc); } +static void HandleBTFTypeTagAttribute(QualType &Type, + const ParsedAttr &Attr, + TypeProcessingState &State) { + Sema &S = State.getSema(); + + // Check the number of attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << Attr + << 1; + Attr.setInvalid(); + return; + } + + // Ensure the argument is a string. + auto *StrLiteral = dyn_cast(Attr.getArgAsExpr(0)); + if (!StrLiteral) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr + << AANT_ArgumentString; + Attr.setInvalid(); + return; + } + + ASTContext &Ctx = S.Context; + StringRef BTFTypeTag = StrLiteral->getString(); + Type = State.getAttributedBTFType( + ::new (Ctx) BTFTypeTagAttr(Ctx, Attr, BTFTypeTag), Type, Type, + BTFTypeTag); + return; +} + /// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. @@ -8133,6 +8174,10 @@ // build won't break. attr.setUsedAsTypeAttr(); break; + case ParsedAttr::AT_BTFTypeTag: + HandleBTFTypeTagAttribute(type, attr, state); + attr.setUsedAsTypeAttr(); + break; case ParsedAttr::AT_MayAlias: // FIXME: This attribute needs to actually be handled, but if we ignore // it it breaks large amounts of Linux software. diff --git a/clang/test/CodeGen/attr-btf_type_tag-conv-var.c b/clang/test/CodeGen/attr-btf_type_tag-conv-var.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/attr-btf_type_tag-conv-var.c @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -triple %itanium_abi_triple -debug-info-kind=limited -S -emit-llvm -o - %s | FileCheck %s + +#define __tag1 __attribute__((btf_type_tag("tag1"))) +#define __tag2 __attribute__((btf_type_tag("tag2"))) +#define __tag3 __attribute__((btf_type_tag("tag3"))) + +struct t { + long c; +}; +struct t * __tag1 * __tag2 *g; +int __tag3 *foo(struct t *a1) { + return (int __tag3 *)a1->c; +} + +// CHECK: distinct !DIGlobalVariable(name: "g", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L10:[0-9]+]] +// CHECK: distinct !DICompileUnit(language: DW_LANG_C99 +// CHECK-SAME: retainedTypes: ![[L4:[0-9]+]] +// CHECK: ![[L4]] = !{![[L5:[0-9]+]]} +// CHECK: ![[L5]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L6:[0-9]+]], size: [[#]], annotations: ![[L7:[0-9]+]]) +// CHECK: ![[L6]] = !DIBasicType(name: "int", size: [[#]], encoding: DW_ATE_signed) +// CHECK: ![[L7]] = !{![[L8:[0-9]+]]} +// CHECK: ![[L8]] = !{!"btf_tag", !"tag3"} +// CHECK: ![[L10]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L11:[0-9]+]], size: [[#]], annotations: ![[L19:[0-9]+]]) +// CHECK: ![[L11]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L12:[0-9]+]], size: [[#]], annotations: ![[L17:[0-9]+]]) +// CHECK: ![[L12]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L13:[0-9]+]], size: [[#]]) +// CHECK: ![[L13]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t" +// CHECK: ![[L17]] = !{![[L18:[0-9]+]]} +// CHECK: ![[L18]] = !{!"btf_tag", !"tag1"} +// CHECK: ![[L19]] = !{![[L20:[0-9]+]]} +// CHECK: ![[L20]] = !{!"btf_tag", !"tag2"} +// CHECK: distinct !DISubprogram(name: "foo", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L28:[0-9]+]] +// CHECK: ![[L28]] = !DISubroutineType(types: ![[L29:[0-9]+]]) +// CHECK: ![[L29]] = !{![[L5]], ![[L12]]} diff --git a/clang/test/CodeGen/attr-btf_type_tag-typedef-field.c b/clang/test/CodeGen/attr-btf_type_tag-typedef-field.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/attr-btf_type_tag-typedef-field.c @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple %itanium_abi_triple -debug-info-kind=limited -S -emit-llvm -o - %s | FileCheck %s + +#define __tag1 __attribute__((btf_type_tag("tag1"))) +#define __tag2 __attribute__((btf_type_tag("tag2"))) + +typedef void __fn_t(int); +typedef __fn_t __tag1 __tag2 *__fn2_t; +struct t { + int __tag1 * __tag2 *a; + __fn2_t b; + long c; +}; +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_tag", !"tag1"} +// CHECK: ![[L22]] = !{![[L23:[0-9]+]]} +// CHECK: ![[L23]] = !{!"btf_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 int", size: [[#]], encoding: DW_ATE_signed) diff --git a/clang/test/Sema/attr-btf_type_tag.c b/clang/test/Sema/attr-btf_type_tag.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/attr-btf_type_tag.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -x c -triple x86_64-pc-linux-gnu -dwarf-version=4 -fsyntax-only -verify %s + +// expected-no-diagnostics + +#define __tag1 __attribute__((btf_type_tag("tag1"))) +#define __tag2 __attribute__((btf_type_tag("tag2"))) + +int * __tag1 * __tag2 *g; + +typedef void __fn_t(int); +typedef __fn_t __tag1 __tag2 *__fn2_t; +struct t { + int __tag1 * __tag2 *a; + __fn2_t b; + long c; +}; +int __tag1 *foo1(struct t __tag1 * __tag2 *a1) { + return (int __tag1 *)a1[0]->c; +} +int * foo2(struct t * __tag1 a1) { + return (int *)a1->c; +} diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -219,11 +219,13 @@ /// \param AlignInBits Alignment. (optional) /// \param DWARFAddressSpace DWARF address space. (optional) /// \param Name Pointer type name. (optional) + /// \param Annotations Member annotations. DIDerivedType *createPointerType(DIType *PointeeTy, uint64_t SizeInBits, uint32_t AlignInBits = 0, Optional DWARFAddressSpace = None, - StringRef Name = ""); + StringRef Name = "", + DINodeArray Annotations = nullptr); /// Create debugging information entry for a pointer to member. /// \param PointeeTy Type pointed to by this pointer. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -754,6 +754,8 @@ if (!Name.empty()) addString(Buffer, dwarf::DW_AT_name, Name); + addAnnotation(Buffer, DTy->getAnnotations()); + // If alignment is specified for a typedef , create and insert DW_AT_alignment // attribute in DW_TAG_typedef DIE. if (Tag == dwarf::DW_TAG_typedef && DD->getDwarfVersion() >= 5) { diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -292,12 +292,13 @@ uint64_t SizeInBits, uint32_t AlignInBits, Optional DWARFAddressSpace, - StringRef Name) { + StringRef Name, + DINodeArray Annotations) { // FIXME: Why is there a name here? return DIDerivedType::get(VMContext, dwarf::DW_TAG_pointer_type, Name, nullptr, 0, nullptr, PointeeTy, SizeInBits, AlignInBits, 0, DWARFAddressSpace, - DINode::FlagZero); + DINode::FlagZero, nullptr, Annotations); } DIDerivedType *DIBuilder::createMemberPointerType(DIType *PointeeTy, diff --git a/llvm/test/DebugInfo/attr-btf_type_tag.ll b/llvm/test/DebugInfo/attr-btf_type_tag.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/attr-btf_type_tag.ll @@ -0,0 +1,62 @@ +; REQUIRES: x86-registered-target +; RUN: llc -filetype=obj -o %t %s +; RUN: llvm-dwarfdump -debug-info %t | FileCheck %s +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; +; int * __tag1 * __tag2 *g; +; Compilation flag: +; clang -target x86_64 -g -S -emit-llvm t.c + +@g = dso_local global i32*** null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!13, !14, !15, !16, !17} +!llvm.ident = !{!18} + +!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) +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !{!10} +!10 = !{!"btf_tag", !"tag1"} +!11 = !{!12} +!12 = !{!"btf_tag", !"tag2"} + +; CHECK: DW_TAG_variable +; CHECK-NEXT: DW_AT_name ("g") +; CHECK-NEXT: DW_AT_type (0x[[T1:[0-9]+]] "int ***") + +; CHECK: 0x[[T1]]: DW_TAG_pointer_type +; CHECK-NEXT: DW_AT_type (0x[[T2:[0-9]+]] "int **") + +; CHECK: DW_TAG_LLVM_annotation +; CHECK-NEXT: DW_AT_name ("btf_tag") +; CHECK-NEXT: DW_AT_const_value ("tag2") + +; CHECK: NULL + +; CHECK: 0x[[T2]]: DW_TAG_pointer_type +; CHECK-NEXT: DW_AT_type (0x[[T3:[0-9]+]] "int *") + +; CHECK: DW_TAG_LLVM_annotation +; CHECK-NEXT: DW_AT_name ("btf_tag") +; CHECK-NEXT: DW_AT_const_value ("tag1") + +; CHECK: NULL + +; CHECK: 0x[[T3]]: DW_TAG_pointer_type +; CHECK-NEXT: DW_AT_type (0x[[#]] "int") + +!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)"}