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 @@ -1845,6 +1845,13 @@ let LangOpts = [COnly]; } +def BTFTypeTag : TypeAttr { + let Spellings = [Clang<"btf_type_tag">]; + let Args = [StringArgument<"BTFTypeTag">]; + let Documentation = [BTFTypeTagDocs]; + let LangOpts = [COnly]; +} + def WebAssemblyExportName : InheritableAttr, TargetSpecificAttr { let Spellings = [Clang<"export_name">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2023,6 +2023,18 @@ }]; } +def BTFTypeTagDocs : Documentation { + let Category = DocCatType; + let Content = [{ +Clang supports the ``__attribute__((btf_type_tag("ARGUMENT")))`` attribute for +all targets. If -g is specified, for variable declaration type, function return +type, function argument type, or typedef underlying type, if these types +are pointer types, the ``ARGUMENT`` info will be preserved in IR and be emitted +to dwarf. FOR BPF trgets, the ``ARGUMENT`` info will be eimitted to .BTF ELF +section too. + }]; +} + def MipsInterruptDocs : Documentation { let Category = DocCatFunction; let Heading = "interrupt (MIPS)"; 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 @@ -1746,6 +1746,9 @@ case attr::ArmMveStrictPolymorphism: OS << "__clang_arm_mve_strict_polymorphism"; break; + case attr::BTFTypeTag: + OS << "btf_type_tag"; + break; } OS << "))"; } diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -178,16 +178,19 @@ llvm::DIType *CreateType(const ComplexType *Ty); llvm::DIType *CreateType(const AutoType *Ty); llvm::DIType *CreateType(const ExtIntType *Ty); - llvm::DIType *CreateQualifiedType(QualType Ty, llvm::DIFile *Fg); + llvm::DIType *CreateQualifiedType(QualType Ty, llvm::DIFile *Fg, + TypeLoc TL = TypeLoc()); llvm::DIType *CreateQualifiedType(const FunctionProtoType *Ty, llvm::DIFile *Fg); llvm::DIType *CreateType(const TypedefType *Ty, llvm::DIFile *Fg); llvm::DIType *CreateType(const TemplateSpecializationType *Ty, llvm::DIFile *Fg); llvm::DIType *CreateType(const ObjCObjectPointerType *Ty, llvm::DIFile *F); - llvm::DIType *CreateType(const PointerType *Ty, llvm::DIFile *F); + llvm::DIType *CreateType(const PointerType *Ty, llvm::DIFile *F, + TypeLoc TL = TypeLoc()); llvm::DIType *CreateType(const BlockPointerType *Ty, llvm::DIFile *F); - llvm::DIType *CreateType(const FunctionType *Ty, llvm::DIFile *F); + llvm::DIType *CreateType(const FunctionType *Ty, llvm::DIFile *F, + TypeLoc TL = TypeLoc()); /// Get structure or union type. llvm::DIType *CreateType(const RecordType *Tyg); llvm::DIType *CreateTypeDefinition(const RecordType *Ty); @@ -242,7 +245,8 @@ /// \return namespace descriptor for the given namespace decl. llvm::DINamespace *getOrCreateNamespace(const NamespaceDecl *N); llvm::DIType *CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty, - QualType PointeeTy, llvm::DIFile *F); + QualType PointeeTy, llvm::DIFile *F, + TypeLoc TL = TypeLoc()); llvm::DIType *getOrCreateStructPtrType(StringRef Name, llvm::DIType *&Cache); /// A helper function to create a subprogram for a single member @@ -308,7 +312,8 @@ uint64_t offsetInBits, uint32_t AlignInBits, llvm::DIFile *tunit, llvm::DIScope *scope, const RecordDecl *RD = nullptr, - llvm::DINodeArray Annotations = nullptr); + llvm::DINodeArray Annotations = nullptr, + TypeLoc TL = TypeLoc()); llvm::DIType *createFieldType(StringRef name, QualType type, SourceLocation loc, AccessSpecifier AS, @@ -628,7 +633,8 @@ Optional Source); /// Get the type from the cache or create a new type if necessary. - llvm::DIType *getOrCreateType(QualType Ty, llvm::DIFile *Fg); + llvm::DIType *getOrCreateType(QualType Ty, llvm::DIFile *Fg, + TypeLoc TL = TypeLoc()); /// Get a reference to a clang module. If \p CreateSkeletonCU is true, /// this also creates a split dwarf skeleton compile unit. @@ -643,7 +649,8 @@ llvm::DICompositeType *getOrCreateLimitedType(const RecordType *Ty); /// Create type metadata for a source language type. - llvm::DIType *CreateTypeNode(QualType Ty, llvm::DIFile *Fg); + llvm::DIType *CreateTypeNode(QualType Ty, llvm::DIFile *Fg, + TypeLoc TL = TypeLoc()); /// Create new member and increase Offset by FType's size. llvm::DIType *CreateMemberType(llvm::DIFile *Unit, QualType FType, 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 @@ -928,8 +928,29 @@ return (llvm::dwarf::Tag)0; } -llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty, - llvm::DIFile *Unit) { +// Strip MacroQualifiedTypeLoc and AttributedTypeLoc +// as their corresponding types will be ignored +// during code generation. Stripping them allows +// to maintain proper TypeLoc for a given type +// during code generation. +static TypeLoc StripMacroAttributed(TypeLoc TL) { + if (TL.isNull()) + return TL; + + while (true) { + if (auto MTL = TL.getAs()) { + TL = MTL.getInnerLoc(); + } else if (auto ATL = TL.getAs()) { + TL = ATL.getModifiedLoc(); + } else { + break; + } + } + return TL; +} + +llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile *Unit, + TypeLoc TL) { QualifierCollector Qc; const Type *T = Qc.strip(Ty); @@ -943,7 +964,15 @@ return getOrCreateType(QualType(T, 0), Unit); } - auto *FromTy = getOrCreateType(Qc.apply(CGM.getContext(), T), Unit); + QualType NextTy = Qc.apply(CGM.getContext(), T); + TypeLoc NextTL; + if (NextTy.hasQualifiers()) + NextTL = TL; + else if (!TL.isNull()) { + if (auto QTL = TL.getAs()) + NextTL = StripMacroAttributed(QTL.getNextTypeLoc()); + } + auto *FromTy = getOrCreateType(NextTy, Unit, NextTL); // No need to fill in the Name, Line, Size, Alignment, Offset in case of // CVR derived types. @@ -987,10 +1016,10 @@ Ty->getPointeeType(), Unit); } -llvm::DIType *CGDebugInfo::CreateType(const PointerType *Ty, - llvm::DIFile *Unit) { +llvm::DIType *CGDebugInfo::CreateType(const PointerType *Ty, llvm::DIFile *Unit, + TypeLoc TL) { return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, - Ty->getPointeeType(), Unit); + Ty->getPointeeType(), Unit, TL); } /// \return whether a C++ mangling exists for the type defined by TD. @@ -1131,7 +1160,8 @@ llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty, QualType PointeeTy, - llvm::DIFile *Unit) { + llvm::DIFile *Unit, + TypeLoc TL) { // Bit size, align and offset of the type. // Size is always the size of a pointer. We can't use getTypeSize here // because that does not return the correct value for references. @@ -1141,13 +1171,52 @@ Optional DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(AddressSpace); + llvm::DINodeArray Annotations = nullptr; + TypeLoc NextTL; + if (!TL.isNull()) { + SmallVector Annots; + NextTL = TL.getNextTypeLoc(); + if (!NextTL.isNull()) { + // Traverse all MacroQualifiedTypeLoc, QualifiedTypeLoc and + // AttributedTypeLoc type locations so we can collect + // BTFTypeTag attributes for this pointer. + while (true) { + if (auto MTL = NextTL.getAs()) { + NextTL = MTL.getInnerLoc(); + } else if (auto QTL = NextTL.getAs()) { + NextTL = QTL.getNextTypeLoc(); + } else if (auto ATL = NextTL.getAs()) { + if (const auto *A = ATL.getAttrAs()) { + StringRef BTFTypeTag = A->getBTFTypeTag(); + if (!BTFTypeTag.empty()) { + 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)); + } + } + NextTL = ATL.getModifiedLoc(); + } else { + break; + } + } + } + + NextTL = StripMacroAttributed(TL.getNextTypeLoc()); + 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); + return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit, NextTL), + Size, Align, DWARFAddressSpace, + StringRef(), Annotations); } llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name, @@ -1264,8 +1333,11 @@ llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile *Unit) { + TypeLoc TL; + if (auto TSI = Ty->getDecl()->getTypeSourceInfo()) + TL = TSI->getTypeLoc(); llvm::DIType *Underlying = - getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit); + getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit, TL); if (Ty->getDecl()->hasAttr()) return Underlying; @@ -1339,7 +1411,7 @@ } llvm::DIType *CGDebugInfo::CreateType(const FunctionType *Ty, - llvm::DIFile *Unit) { + llvm::DIFile *Unit, TypeLoc TL) { const auto *FPT = dyn_cast(Ty); if (FPT) { if (llvm::DIType *QTy = CreateQualifiedType(FPT, Unit)) @@ -1351,17 +1423,41 @@ SmallVector EltTys; // Add the result type at least. - EltTys.push_back(getOrCreateType(Ty->getReturnType(), Unit)); + TypeLoc RetTL; + if (!TL.isNull()) { + if (auto FTL = TL.getAs()) + RetTL = FTL.getReturnLoc(); + } + EltTys.push_back(getOrCreateType(Ty->getReturnType(), Unit, RetTL)); llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; // Set up remainder of arguments if there is a prototype. // otherwise emit it as a variadic function. - if (!FPT) + if (!FPT) { EltTys.push_back(DBuilder.createUnspecifiedParameter()); - else { + } else { Flags = getRefFlags(FPT); - for (const QualType &ParamType : FPT->param_types()) - EltTys.push_back(getOrCreateType(ParamType, Unit)); + bool DoneWithTL = false; + if (!TL.isNull()) { + if (auto FTL = TL.getAs()) { + DoneWithTL = true; + int Idx = 0; + for (const QualType &ParamType : FPT->param_types()) { + TypeLoc ParamTL; + if (auto Param = FTL.getParam(Idx)) { + if (auto TSI = Param->getTypeSourceInfo()) + ParamTL = TSI->getTypeLoc(); + } + EltTys.push_back(getOrCreateType(ParamType, Unit, ParamTL)); + Idx++; + } + } + } + + if (!DoneWithTL) { + for (const QualType &ParamType : FPT->param_types()) + EltTys.push_back(getOrCreateType(ParamType, Unit)); + } if (FPT->isVariadic()) EltTys.push_back(DBuilder.createUnspecifiedParameter()); } @@ -1432,11 +1528,13 @@ Flags, DebugType, Annotations); } -llvm::DIType *CGDebugInfo::createFieldType( - StringRef name, QualType type, SourceLocation loc, AccessSpecifier AS, - uint64_t offsetInBits, uint32_t AlignInBits, llvm::DIFile *tunit, - llvm::DIScope *scope, const RecordDecl *RD, llvm::DINodeArray Annotations) { - llvm::DIType *debugType = getOrCreateType(type, tunit); +llvm::DIType * +CGDebugInfo::createFieldType(StringRef name, QualType type, SourceLocation loc, + AccessSpecifier AS, uint64_t offsetInBits, + uint32_t AlignInBits, llvm::DIFile *tunit, + llvm::DIScope *scope, const RecordDecl *RD, + llvm::DINodeArray Annotations, TypeLoc TL) { + llvm::DIType *debugType = getOrCreateType(type, tunit, TL); // Get the location for the field. llvm::DIFile *file = getOrCreateFile(loc); @@ -1544,9 +1642,12 @@ } else { auto Align = getDeclAlignIfRequired(field, CGM.getContext()); llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(field); - FieldType = - createFieldType(name, type, field->getLocation(), field->getAccess(), - OffsetInBits, Align, tunit, RecordTy, RD, Annotations); + TypeLoc TL; + if (auto TSI = field->getTypeSourceInfo()) + TL = TSI->getTypeLoc(); + FieldType = createFieldType(name, type, field->getLocation(), + field->getAccess(), OffsetInBits, Align, tunit, + RecordTy, RD, Annotations, TL); } elements.push_back(FieldType); @@ -3304,7 +3405,8 @@ RetainedTypes.push_back(CGM.getContext().getRecordType(&D).getAsOpaquePtr()); } -llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) { +llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit, + TypeLoc TL) { if (Ty.isNull()) return nullptr; @@ -3321,7 +3423,7 @@ if (auto *T = getTypeOrNull(Ty)) return T; - llvm::DIType *Res = CreateTypeNode(Ty, Unit); + llvm::DIType *Res = CreateTypeNode(Ty, Unit, TL); void *TyPtr = Ty.getAsOpaquePtr(); // And update the type cache. @@ -3365,10 +3467,11 @@ return nullptr; } -llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { +llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit, + TypeLoc TL) { // Handle qualifiers, which recursively handles what they refer to. if (Ty.hasLocalQualifiers()) - return CreateQualifiedType(Ty, Unit); + return CreateQualifiedType(Ty, Unit, TL); // Work out details of type. switch (Ty->getTypeClass()) { @@ -3397,7 +3500,7 @@ case Type::Complex: return CreateType(cast(Ty)); case Type::Pointer: - return CreateType(cast(Ty), Unit); + return CreateType(cast(Ty), Unit, TL); case Type::BlockPointer: return CreateType(cast(Ty), Unit); case Type::Typedef: @@ -3408,7 +3511,7 @@ return CreateEnumType(cast(Ty)); case Type::FunctionProto: case Type::FunctionNoProto: - return CreateType(cast(Ty), Unit); + return CreateType(cast(Ty), Unit, TL); case Type::ConstantArray: case Type::VariableArray: case Type::IncompleteArray: @@ -3953,7 +4056,12 @@ getDwarfCC(CC)); } - return cast(getOrCreateType(FnType, F)); + TypeLoc TL; + if (const auto *FD = dyn_cast(D)) { + if (auto TSI = FD->getTypeSourceInfo()) + TL = TSI->getTypeLoc(); + } + return cast(getOrCreateType(FnType, F, TL)); } QualType @@ -4355,8 +4463,12 @@ uint64_t XOffset = 0; if (VD->hasAttr()) Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset).WrappedType; - else - Ty = getOrCreateType(VD->getType(), Unit); + else { + TypeLoc TL; + if (auto TSI = VD->getTypeSourceInfo()) + TL = TSI->getTypeLoc(); + Ty = getOrCreateType(VD->getType(), Unit, TL); + } // If there is no debug info for this type then do not emit debug info // for this variable. @@ -5080,10 +5192,14 @@ } AppendAddressSpaceXDeref(AddressSpace, Expr); + TypeLoc TL; + if (auto TSI = D->getTypeSourceInfo()) + TL = TSI->getTypeLoc(); + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D); GVE = DBuilder.createGlobalVariableExpression( - DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit), - Var->hasLocalLinkage(), true, + DContext, DeclName, LinkageName, Unit, LineNo, + getOrCreateType(T, Unit, TL), Var->hasLocalLinkage(), true, Expr.empty() ? nullptr : DBuilder.createExpression(Expr), getOrCreateStaticDataMemberDeclarationOrNull(D), TemplateParameters, Align, Annotations); 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 @@ -5900,6 +5900,9 @@ void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { Visit(TL.getUnqualifiedLoc()); } + // Allow to fill pointee's type locations, e.g., + // int __attr * __attr * __attr *p; + void VisitPointerTypeLoc(PointerTypeLoc TL) { Visit(TL.getNextTypeLoc()); } void VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeLoc()); } @@ -6500,6 +6503,34 @@ 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.getAttributedType( + ::new (Ctx) BTFTypeTagAttr(Ctx, Attr, BTFTypeTag), Type, Type); + 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 +8158,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/test/CodeGen/attr-btf_type_tag-func.c b/clang/test/CodeGen/attr-btf_type_tag-func.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/attr-btf_type_tag-func.c @@ -0,0 +1,20 @@ +// 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"))) +#define __tag4 __attribute__((btf_type_tag("tag4"))) + +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]]) 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/CodeGen/attr-btf_type_tag-var.c b/clang/test/CodeGen/attr-btf_type_tag-var.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/attr-btf_type_tag-var.c @@ -0,0 +1,31 @@ +// 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"))) +#define __tag4 __attribute__((btf_type_tag("tag4"))) +#define __tag5 __attribute__((btf_type_tag("tag5"))) +#define __tag6 __attribute__((btf_type_tag("tag6"))) + +const int __tag1 __tag2 volatile * const __tag3 __tag4 volatile * __tag5 __tag6 const volatile * g; + +// 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"} 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,25 @@ +// RUN: %clang_cc1 -x c -triple x86_64-pc-linux-gnu -dwarf-version=4 -fsyntax-only -verify %s + +#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"))) +#define __tag5 __attribute__((btf_type_tag("tag5"))) +#define __tag6 __attribute__((btf_type_tag("tag6"))) + +int __attribute__((btf_type_tag("tag1", "tag2"))) *invalid1; // expected-error {{'btf_type_tag' attribute takes one argument}} +int __attribute__((btf_type_tag(2))) *invalid2; // expected-error {{'btf_type_tag' attribute requires a string}} + +int * __tag1 __tag2 * __tag3 __tag4 * __tag5 __tag6 *g; + +typedef void __fn_t(int); +typedef __fn_t __tag1 __tag2 * __tag3 __tag4 *__fn2_t; +struct t { + int __tag1 * __tag2 * __tag3 *a; + int __tag1 __tag2 __tag3 *b; + __fn2_t c; + long d; +}; +int __tag4 * __tag5 * __tag6 *foo1(struct t __tag1 * __tag2 * __tag3 *a1) { + return (int __tag4 * __tag5 * __tag6 *)a1[0][0]->d; +} 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,12 @@ /// \param AlignInBits Alignment. (optional) /// \param DWARFAddressSpace DWARF address space. (optional) /// \param Name Pointer type name. (optional) - DIDerivedType *createPointerType(DIType *PointeeTy, uint64_t SizeInBits, - uint32_t AlignInBits = 0, - Optional DWARFAddressSpace = - None, - StringRef Name = ""); + /// \param Annotations Member annotations. + DIDerivedType * + createPointerType(DIType *PointeeTy, uint64_t SizeInBits, + uint32_t AlignInBits = 0, + Optional DWARFAddressSpace = None, + 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/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -287,17 +287,16 @@ 0, 0, None, DINode::FlagZero); } -DIDerivedType *DIBuilder::createPointerType( - DIType *PointeeTy, - uint64_t SizeInBits, - uint32_t AlignInBits, - Optional DWARFAddressSpace, - StringRef Name) { +DIDerivedType * +DIBuilder::createPointerType(DIType *PointeeTy, uint64_t SizeInBits, + uint32_t AlignInBits, + Optional DWARFAddressSpace, + 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); + AlignInBits, 0, DWARFAddressSpace, DINode::FlagZero, + nullptr, Annotations); } DIDerivedType *DIBuilder::createMemberPointerType(DIType *PointeeTy, diff --git a/llvm/test/Bitcode/attr-btf_type_tag.ll b/llvm/test/Bitcode/attr-btf_type_tag.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Bitcode/attr-btf_type_tag.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* null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!9, !10, !11, !12, !13} +!llvm.ident = !{!14} + +!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_C99, file: !3, producer: "clang version 14.0.0 (https://github.com/llvm/llvm-project.git 248122328bfefe82608a2e110af3a3ff04279ddf)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_tag_type") +!4 = !{!0} +!5 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64, annotations: !7) +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{!8} +!8 = !{!"btf_type_tag", !"tag1"} + +; CHECK: distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 2, type: !5 +; CHECK: !5 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64, annotations: !7) +; CHECK-NEXT: !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +; CHECK-NEXT: !7 = !{!8} +; CHECK-NEXT: !8 = !{!"btf_type_tag", !"tag1"} + +!9 = !{i32 7, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{i32 7, !"uwtable", i32 1} +!13 = !{i32 7, !"frame-pointer", i32 2} +!14 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git 248122328bfefe82608a2e110af3a3ff04279ddf)"} 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)"}