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 @@ -263,6 +263,7 @@ DeducedTemplateSpecializationTypes; mutable llvm::FoldingSet AtomicTypes; llvm::FoldingSet AttributedTypes; + llvm::FoldingSet AttributedBTFTypes; mutable llvm::FoldingSet PipeTypes; mutable llvm::FoldingSet ExtIntTypes; mutable llvm::FoldingSet DependentExtIntTypes; @@ -1558,6 +1559,9 @@ 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/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -131,6 +131,7 @@ def SourceLocation : PropertyType; def StmtRef : RefPropertyType<"Stmt"> { let ConstWhenWriting = 1; } def ExprRef : SubclassPropertyType<"Expr", StmtRef>; +def String : PropertyType<"std::string">; def TemplateArgument : PropertyType; def TemplateArgumentKind : EnumPropertyType<"TemplateArgument::ArgKind">; def TemplateName : DefaultValuePropertyType; diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1029,6 +1029,9 @@ DEF_TRAVERSE_TYPE(AttributedType, { TRY_TO(TraverseType(T->getModifiedType())); }) +DEF_TRAVERSE_TYPE(AttributedBTFType, + { TRY_TO(TraverseType(T->getModifiedType())); }) + DEF_TRAVERSE_TYPE(ParenType, { TRY_TO(TraverseType(T->getInnerType())); }) DEF_TRAVERSE_TYPE(MacroQualifiedType, @@ -1314,6 +1317,9 @@ DEF_TRAVERSE_TYPELOC(AttributedType, { TRY_TO(TraverseTypeLoc(TL.getModifiedLoc())); }) +DEF_TRAVERSE_TYPELOC(AttributedBTFType, + { TRY_TO(TraverseTypeLoc(TL.getModifiedLoc())); }) + DEF_TRAVERSE_TYPELOC(ElaboratedType, { if (TL.getQualifierLoc()) { TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); 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 @@ -4682,6 +4682,13 @@ AttributedTypeBits.AttrKind = attrKind; } +protected: + AttributedType(TypeClass tc, QualType canon, attr::Kind attrKind, + QualType modified, QualType equivalent) + : Type(tc, canon, equivalent->getDependence()), ModifiedType(modified), + EquivalentType(equivalent) { + AttributedTypeBits.AttrKind = attrKind; + } public: Kind getAttrKind() const { return static_cast(AttributedTypeBits.AttrKind); @@ -4758,7 +4765,38 @@ } static bool classof(const Type *T) { - return T->getTypeClass() == Attributed; + return T->getTypeClass() == Attributed || + T->getTypeClass() == AttributedBTF; + } +}; + +class AttributedBTFType : public AttributedType { +private: + StringRef BTFTypeTag; + +public: + AttributedBTFType(QualType canon, attr::Kind attrKind, QualType modified, + QualType equivalent, StringRef BTFTypeTag) + : AttributedType(AttributedBTF, canon, attrKind, modified, equivalent) { + this->BTFTypeTag = BTFTypeTag; + } + + StringRef getBTFTypeTag() const { return BTFTypeTag; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getAttrKind(), getModifiedType(), getEquivalentType(), + BTFTypeTag); + } + + static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind, + QualType modified, QualType equivalent, + StringRef BTFTypeTag) { + AttributedType::Profile(ID, attrKind, modified, equivalent); + ID.AddString(BTFTypeTag); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == AttributedBTF; } }; diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -891,6 +891,10 @@ } }; +class AttributedBTFTypeLoc + : public InheritingConcreteTypeLoc {}; + struct ObjCObjectTypeLocInfo { SourceLocation TypeArgsLAngleLoc; SourceLocation TypeArgsRAngleLoc; diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -606,6 +606,15 @@ }]>; } +let Class = AttributedBTFType in { + def : Property<"tag", String> { + let Read = [{ node->getBTFTypeTag().str() }]; + } + def : Creator<[{ + return ctx.getAttributedBTFType(attribute, modifiedType, equivalentType, tag); + }]>; +} + let Class = DependentAddressSpaceType in { def : Property<"pointeeType", QualType> { let Read = [{ node->getPointeeType() }]; 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 @@ -1844,6 +1844,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/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td --- a/clang/include/clang/Basic/TypeNodes.td +++ b/clang/include/clang/Basic/TypeNodes.td @@ -90,6 +90,7 @@ def EnumType : TypeNode, LeafType; def ElaboratedType : TypeNode, NeverCanonical; def AttributedType : TypeNode, NeverCanonical; +def AttributedBTFType : TypeNode, NeverCanonical; def TemplateTypeParmType : TypeNode, AlwaysDependent, LeafType; def SubstTemplateTypeParmType : TypeNode, NeverCanonical; def SubstTemplateTypeParmPackType : TypeNode, AlwaysDependent; diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h --- a/clang/include/clang/Serialization/ASTRecordWriter.h +++ b/clang/include/clang/Serialization/ASTRecordWriter.h @@ -283,6 +283,8 @@ return Writer->AddString(Str, *Record); } + void writeString(StringRef Str) { return AddString(Str); } + /// Emit a path. void AddPath(StringRef Path) { return Writer->AddPath(Path, *Record); diff --git a/clang/include/clang/Serialization/TypeBitCodes.def b/clang/include/clang/Serialization/TypeBitCodes.def --- a/clang/include/clang/Serialization/TypeBitCodes.def +++ b/clang/include/clang/Serialization/TypeBitCodes.def @@ -62,5 +62,6 @@ TYPE_BIT_CODE(DependentExtInt, DEPENDENT_EXT_INT, 51) TYPE_BIT_CODE(ConstantMatrix, CONSTANT_MATRIX, 52) TYPE_BIT_CODE(DependentSizedMatrix, DEPENDENT_SIZE_MATRIX, 53) +TYPE_BIT_CODE(AttributedBTF, ATTRIBUTED_BTF, 54) #undef TYPE_BIT_CODE 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 @@ -2363,6 +2363,7 @@ return getTypeInfo(cast(T)->getNamedType().getTypePtr()); case Type::Attributed: + case Type::AttributedBTF: return getTypeInfo( cast(T)->getEquivalentType().getTypePtr()); @@ -4632,6 +4633,28 @@ 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; + AttributedBTFType *type = + AttributedBTFTypes.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); + AttributedBTFTypes.InsertNode(type, insertPos); + return QualType(type, 0); +} + /// Retrieve a substitution-result type. QualType ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -922,6 +922,7 @@ break; case Type::Attributed: + case Type::AttributedBTF: if (!IsStructurallyEquivalent(Context, cast(T1)->getModifiedType(), cast(T2)->getModifiedType())) diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2253,6 +2253,7 @@ case Type::FunctionNoProto: case Type::Paren: case Type::Attributed: + case Type::AttributedBTF: case Type::Auto: case Type::DeducedTemplateSpecialization: case Type::PackExpansion: diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -673,6 +673,10 @@ return Visit(T.getModifiedLoc()); } + TypeLoc VisitAttributedBTFTypeLoc(AttributedBTFTypeLoc T) { + return Visit(T.getModifiedLoc()); + } + TypeLoc VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc T) { return Visit(T.getInnerLoc()); } 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 @@ -234,6 +234,7 @@ case Type::Pipe: case Type::ExtInt: case Type::DependentExtInt: + case Type::AttributedBTF: CanPrefixQualifiers = true; break; @@ -1704,6 +1705,7 @@ case attr::UPtr: case attr::AddressSpace: case attr::CmseNSCall: + case attr::BTFTypeTag: llvm_unreachable("This attribute should have been handled already"); case attr::NSReturnsRetained: @@ -1756,6 +1758,14 @@ OS << "))"; } +void TypePrinter::printAttributedBTFBefore(const AttributedBTFType *T, + raw_ostream &OS) { + OS << " __attribute__((btf_type_tag(\"" << T->getBTFTypeTag() << "\")))"; +} + +void TypePrinter::printAttributedBTFAfter(const AttributedBTFType *T, + raw_ostream &OS) {} + void TypePrinter::printObjCInterfaceBefore(const ObjCInterfaceType *T, raw_ostream &OS) { OS << T->getDecl()->getName(); 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 @@ -1141,13 +1141,40 @@ 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_type_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, @@ -3242,6 +3269,7 @@ T = cast(T)->getUnderlyingType(); break; case Type::Attributed: + case Type::AttributedBTF: T = cast(T)->getEquivalentType(); break; case Type::Elaborated: @@ -3433,6 +3461,7 @@ case Type::Auto: case Type::Attributed: + case Type::AttributedBTF: case Type::Adjusted: case Type::Decayed: case Type::DeducedTemplateSpecialization: diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2258,6 +2258,7 @@ case Type::TypeOf: case Type::UnaryTransform: case Type::Attributed: + case Type::AttributedBTF: case Type::SubstTemplateTypeParm: case Type::MacroQualified: // Keep walking after single level desugaring. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4433,6 +4433,7 @@ case Type::TypeOf: case Type::UnaryTransform: case Type::Attributed: + case Type::AttributedBTF: case Type::SubstTemplateTypeParm: case Type::MacroQualified: // Keep walking after single level desugaring. 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,15 @@ 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. @@ -5876,6 +5885,11 @@ TL.setAttr(State.takeAttrForAttributedType(TL.getTypePtr())); } +static void fillAttributedBTFTypeLoc(AttributedBTFTypeLoc TL, + TypeProcessingState &State) { + TL.setAttr(State.takeAttrForAttributedType(TL.getTypePtr())); +} + namespace { class TypeSpecLocFiller : public TypeLocVisitor { Sema &SemaRef; @@ -5892,6 +5906,10 @@ Visit(TL.getModifiedLoc()); fillAttributedTypeLoc(TL, State); } + void VisitAttributedBTFTypeLoc(AttributedBTFTypeLoc TL) { + Visit(TL.getModifiedLoc()); + fillAttributedBTFTypeLoc(TL, State); + } void VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) { Visit(TL.getInnerLoc()); TL.setExpansionLoc( @@ -6108,6 +6126,9 @@ void VisitAttributedTypeLoc(AttributedTypeLoc TL) { fillAttributedTypeLoc(TL, State); } + void VisitAttributedBTFTypeLoc(AttributedBTFTypeLoc TL) { + fillAttributedBTFTypeLoc(TL, State); + } void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { // nothing } @@ -6500,6 +6521,35 @@ 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. @@ -8127,6 +8177,11 @@ case ParsedAttr::IgnoredAttribute: 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/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -6800,6 +6800,41 @@ return result; } +template +QualType +TreeTransform::TransformAttributedBTFType(TypeLocBuilder &TLB, + AttributedBTFTypeLoc TL) { + const AttributedBTFType *oldType = TL.getTypePtr(); + QualType modifiedType = getDerived().TransformType(TLB, TL.getModifiedLoc()); + if (modifiedType.isNull()) + return QualType(); + + // oldAttr can be null if we started with a QualType rather than a TypeLoc. + const Attr *oldAttr = TL.getAttr(); + const Attr *newAttr = oldAttr ? getDerived().TransformAttr(oldAttr) : nullptr; + if (oldAttr && !newAttr) + return QualType(); + + QualType result = TL.getType(); + + // Handle similar to TransformAttributedType(). + if (getDerived().AlwaysRebuild() || + modifiedType != oldType->getModifiedType()) { + QualType equivalentType = + getDerived().TransformType(oldType->getEquivalentType()); + if (equivalentType.isNull()) + return QualType(); + + result = SemaRef.Context.getAttributedBTFType(TL.getAttrKind(), + modifiedType, equivalentType, + oldType->getBTFTypeTag()); + } + + AttributedBTFTypeLoc newTL = TLB.push(result); + newTL.setAttr(newAttr); + return result; +} + template QualType TreeTransform::TransformParenType(TypeLocBuilder &TLB, diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6670,6 +6670,10 @@ TL.setAttr(ReadAttr()); } +void TypeLocReader::VisitAttributedBTFTypeLoc(AttributedBTFTypeLoc TL) { + TL.setAttr(ReadAttr()); +} + void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -413,6 +413,10 @@ Record.AddAttr(TL.getAttr()); } +void TypeLocWriter::VisitAttributedBTFTypeLoc(AttributedBTFTypeLoc TL) { + Record.AddAttr(TL.getAttr()); +} + void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { Record.AddSourceLocation(TL.getNameLoc()); } 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_type_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_type_tag", !"tag1"} +// CHECK: ![[L19]] = !{![[L20:[0-9]+]]} +// CHECK: ![[L20]] = !{!"btf_type_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_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) 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/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1670,6 +1670,10 @@ return Visit(TL.getModifiedLoc()); } +bool CursorVisitor::VisitAttributedBTFTypeLoc(AttributedBTFTypeLoc TL) { + return Visit(TL.getModifiedLoc()); +} + bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType) { if (!SkipResultType && Visit(TL.getReturnLoc())) 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_type_tag", !"tag1"} +!11 = !{!12} +!12 = !{!"btf_type_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_type_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_type_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)"}