Skip to content

Commit

Permalink
[DebugInfo][BPF] Add 'btf:type_tag' annotation in DWARF
Browse files Browse the repository at this point in the history
This commit is a follow-up for BPF mailing list discussion at [1].
It changes the way `__attribute__((btf_type_tag("...")))`s are
represented in DWARF.

Prior to this commit type tags could only be attached to pointers.
Such attachments associated the tags with a pointee type.
E.g. for the following C code:

    int __attribute__((btf_type_tag("tag1"))) *g;

Generated DWARF looked as follows:

    0x0000001e:   DW_TAG_variable
                    DW_AT_name      ("g")
                    DW_AT_type      (0x00000029 "int *")

    0x00000029:   DW_TAG_pointer_type
                    DW_AT_type      (0x00000032 "int")

    0x0000002e:     DW_TAG_LLVM_annotation
                      DW_AT_name    ("btf_type_tag")
                      DW_AT_const_value     ("tag1")

    0x00000032:   DW_TAG_base_type
                    DW_AT_name      ("int")

The goal of this commit is to allow attachment of type tags to the
tagged types instead. E.g. for the same example DWARF should look as
follows:

    0x0000001e:   DW_TAG_variable
                    DW_AT_name      ("g")
                    DW_AT_type      (0x00000029 "int *")

    0x00000029:   DW_TAG_pointer_type
                    DW_AT_type      (0x00000032 "int")

    0x00000032:   DW_TAG_base_type
                    DW_AT_name      ("int")

    0x00000036:     DW_TAG_LLVM_annotation
                      DW_AT_name    ("btf:type_tag")
                      DW_AT_const_value     ("tag1")

A new tag name, `btf:type_tag`, is used so that DWARF consumers
could distinguish between old and new attachment semantics.

In order to preserve backwards compatibility both `btf_type_tag` and
`btf:type_tag` are generated. `btf_type_tag` might be deprecated in
the future.

The commit includes the following changes:
- Changes in debug info generation:
  - New method `DIBuilder::createAnnotationsPlaceholder()` is added,
    it creates a temporary `DIDerivedType` that plays as annotations
    placeholder while debug info metadata is being constructed;
  - New overload for `CGDebugInfo::CreateType` method is added:

      llvm::DIType *CGDebugInfo::CreateType(const BTFTagAttributedType *Ty,
                                            llvm::DIFile *Unit);

    This overload collects BTF type tags in `Ty`, creates annotations
    placeholder pointing to the base type of `Ty`, registers the
    placeholder in the `CGDebugInfo::AnnotationsPlaceholder` vector.
  - `CGDebugInfo::finalize()` is updated to do the following for each
    annotation placeholder:
    - clone underlying base type;
    - attach annotations the clone using `replaceAnnotations()` call;
    - replace all placeholder usages by a clone.
  Such scheme allows to deal with type cycles.

- Changes in AST construction:
  - `ASTContext::getBTFTagAttributedType()` is updated to ensure that
    `BTFTagAttributedType` always wraps `QualType` w/o local
    constant/volatile/restricted qualifiers. This simplifies debug info
    generation.

[1] https://lore.kernel.org/bpf/87r0w9jjoq.fsf@oracle.com/

Depends on D143966

Differential Revision: https://reviews.llvm.org/D143967
  • Loading branch information
eddyz87 committed Aug 1, 2023
1 parent 3dad877 commit 5ad452a
Show file tree
Hide file tree
Showing 14 changed files with 385 additions and 92 deletions.
192 changes: 167 additions & 25 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,158 @@ CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty,
return RetTy;
}

static QualType collectBTFTypeTagAnnotations(
llvm::LLVMContext &Context, llvm::DIBuilder &DBuilder,
llvm::SmallVectorImpl<llvm::Metadata *> &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<BTFTagAttributedType>(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 llvm::DIType *cloneAndAddAnnotations(llvm::DIBuilder &DBuilder,
SmallVector<llvm::Metadata *, 4> Annotations,
llvm::DIType *WrappedDI) {
auto AddAnnotations = [&](auto *Type) {
if (llvm::DINodeArray OldAnnotations = Type->getAnnotations())
for (const llvm::Metadata *O : OldAnnotations->operands())
Annotations.push_back(const_cast<llvm::Metadata *>(O));
auto Clone = Type->clone();
Clone->replaceAnnotations(DBuilder.getOrCreateArray(Annotations));
return llvm::MDNode::replaceWithPermanent(std::move(Clone));
};

if (auto *Ty = dyn_cast<llvm::DIBasicType>(WrappedDI))
return AddAnnotations(Ty);
if (auto *Ty = dyn_cast<llvm::DICompositeType>(WrappedDI))
return AddAnnotations(Ty);
if (auto *Ty = dyn_cast<llvm::DIDerivedType>(WrappedDI))
return AddAnnotations(Ty);
if (auto *Ty = dyn_cast<llvm::DISubroutineType>(WrappedDI))
return AddAnnotations(Ty);

return WrappedDI;
}

static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C);

llvm::DIType *CGDebugInfo::CreateType(const BTFTagAttributedType *Ty,
llvm::DIFile *Unit) {
SmallVector<llvm::Metadata *, 4> Annotations;
QualType WrappedTy = collectBTFTypeTagAnnotations(
CGM.getLLVMContext(), DBuilder, Annotations, Ty, "btf:type_tag");
if (Annotations.size() == 0)
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);

// We are going to invoke CreateTypeNode(WrappedTy, ...), to avoid
// infinite cycle in the case like below add ourselves to the
// TypeCache. The Placeholder node is temporary and would be
// replaced at the end of this function. Example:
//
// #define __tag1 __attribute__((btf_type_tag("tag1")))
// struct st {
// struct st __tag1 *self;
// } g;
//
auto *Placeholder = DBuilder.createAnnotationsPlaceholder();
TypeCache[Ty].reset(Placeholder);
// Invoke CreateTypeNode(WrappedTy, ...) in order to clone the
// result and attach annotations to it at the end of this function.
// Can't call getOrCreateType() because that might return existing
// temporary node created by getOrCreateLimitedType(). Clone of that
// temporary node will not be finalized with correct members.
WrappedTy = UnwrapTypeForDebugInfo(WrappedTy, CGM.getContext());
llvm::DIType *WrappedDI = CreateTypeNode(WrappedTy, Unit);
if (WrappedDI == nullptr)
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<llvm::DIDerivedType>(WrappedDI)) {
if (!retreiveCVR(DTy, Qc))
break;
WrappedDI = DTy->getBaseType();
}

WrappedDI = cloneAndAddAnnotations(DBuilder, Annotations, WrappedDI);
DBuilder.replaceTemporary(llvm::TempDIType(Placeholder), WrappedDI);
return applyQualifiers(DBuilder, WrappedDI, Qc);
}

llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag,
const Type *Ty,
QualType PointeeTy,
Expand All @@ -1191,32 +1343,23 @@ llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag,
CGM.getTarget().getDWARFAddressSpace(
CGM.getTypes().getTargetAddressSpace(PointeeTy));

SmallVector<llvm::Metadata *, 4> Annots;
auto *BTFAttrTy = dyn_cast<BTFTagAttributedType>(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<BTFTagAttributedType>(BTFAttrTy->getWrappedType());
}

llvm::DINodeArray Annotations = nullptr;
if (Annots.size() > 0)
Annotations = DBuilder.getOrCreateArray(Annots);
if (auto *BTFAttrTy =
dyn_cast<BTFTagAttributedType>(PointeeTy.getTypePtr())) {
SmallVector<llvm::Metadata *, 4> 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,
Expand Down Expand Up @@ -2659,7 +2802,7 @@ void CGDebugInfo::completeRequiredType(const RecordDecl *RD) {
llvm::DIType *CGDebugInfo::CreateType(const RecordType *Ty) {
RecordDecl *RD = Ty->getDecl();
llvm::DIType *T = cast_or_null<llvm::DIType>(getTypeOrNull(QualType(Ty, 0)));
if (T || shouldOmitDefinition(DebugKind, DebugTypeExtRefs, RD,
if (/*T || */shouldOmitDefinition(DebugKind, DebugTypeExtRefs, RD,
CGM.getLangOpts())) {
if (!T)
T = getOrCreateRecordFwdDecl(Ty, getDeclContextDescriptor(RD));
Expand Down Expand Up @@ -3432,9 +3575,6 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
case Type::Attributed:
T = cast<AttributedType>(T)->getEquivalentType();
break;
case Type::BTFTagAttributed:
T = cast<BTFTagAttributedType>(T)->getWrappedType();
break;
case Type::Elaborated:
T = cast<ElaboratedType>(T)->getNamedType();
break;
Expand Down Expand Up @@ -3626,9 +3766,11 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
case Type::TemplateSpecialization:
return CreateType(cast<TemplateSpecializationType>(Ty), Unit);

case Type::BTFTagAttributed:
return CreateType(cast<BTFTagAttributedType>(Ty), Unit);

case Type::Auto:
case Type::Attributed:
case Type::BTFTagAttributed:
case Type::Adjusted:
case Type::Decayed:
case Type::DeducedTemplateSpecialization:
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGDebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,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);
Expand Down
18 changes: 18 additions & 0 deletions clang/test/CodeGen/attr-btf_type_tag-circular.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// 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")))

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: [[#]], annotations: ![[L6:[0-9]+]])
// 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"}
// CHECK: ![[L6]] = !{![[L9:[0-9]+]]}
// CHECK: ![[L9]] = !{!"btf_type_tag", !"tag1"}
43 changes: 43 additions & 0 deletions clang/test/CodeGen/attr-btf_type_tag-const.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// RUN: %clang_cc1 \
// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \
// RUN: -S -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]+]], {{.*}}, annotations: ![[L07:[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"}
// CHECK: ![[L07]] = !{![[L11:[0-9]+]]}
// CHECK: ![[L11]] = !{!"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"}
12 changes: 7 additions & 5 deletions clang/test/CodeGen/attr-btf_type_tag-func-ptr.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ 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: ![[L2:[0-9]+]], size: [[#]], annotations: ![[L3:[0-9]+]])
// CHECK: ![[L2]] = !DISubroutineType(types: ![[#]], annotations: ![[L4:[0-9]+]])
// CHECK: ![[L4]] = !{![[L5:[0-9]+]]}
// CHECK: ![[L5]] = !{!"btf:type_tag", !"rcu"}
// CHECK: ![[L3]] = !{![[L6:[0-9]+]]}
// CHECK: ![[L6]] = !{!"btf_type_tag", !"rcu"}
25 changes: 14 additions & 11 deletions clang/test/CodeGen/attr-btf_type_tag-func.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@

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, annotations: ![[L08:[0-9]+]])
// CHECK: ![[L08]] = !{![[L09:[0-9]+]]}
// CHECK: ![[L09]] = !{!"btf:type_tag", !"tag1"}
// CHECK: ![[L07]] = !{![[L10:[0-9]+]], ![[L11:[0-9]+]]}
// CHECK: ![[L10]] = !{!"btf:type_tag", !"tag2"}
// 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]])
21 changes: 21 additions & 0 deletions clang/test/CodeGen/attr-btf_type_tag-restrict.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// RUN: %clang_cc1 \
// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \
// RUN: -S -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"}
Loading

0 comments on commit 5ad452a

Please sign in to comment.