}
}
+/// Generate btf_type_tag chains.
+int BTFDebug::genBTFTypeTags(const DIDerivedType *DTy, int BaseTypeId) {
+ SmallVector<const MDString *, 4> MDStrs;
+ DINodeArray Annots = DTy->getAnnotations();
+ if (Annots) {
+ // For type with "int __tag1 __tag2 *p", the MDStrs will have
+ // content: [__tag1, __tag2].
+ for (const Metadata *Annotations : Annots->operands()) {
+ const MDNode *MD = cast<MDNode>(Annotations);
+ const MDString *Name = cast<MDString>(MD->getOperand(0));
+ if (!Name->getString().equals("btf_type_tag"))
+ continue;
+ MDStrs.push_back(cast<MDString>(MD->getOperand(1)));
+ }
+ }
+
+ if (MDStrs.size() == 0)
+ return -1;
+
+ // With MDStrs [__tag1, __tag2], the output type chain looks like
+ // PTR -> __tag2 -> __tag1 -> BaseType
+ // In the below, we construct BTF types with the order of __tag1, __tag2
+ // and PTR.
+ unsigned TmpTypeId;
+ std::unique_ptr<BTFTypeTypeTag> TypeEntry;
+ if (BaseTypeId >= 0)
+ TypeEntry =
+ std::make_unique<BTFTypeTypeTag>(BaseTypeId, MDStrs[0]->getString());
+ else
+ TypeEntry = std::make_unique<BTFTypeTypeTag>(DTy, MDStrs[0]->getString());
+ TmpTypeId = addType(std::move(TypeEntry));
+
+ for (unsigned I = 1; I < MDStrs.size(); I++) {
+ const MDString *Value = MDStrs[I];
+ TypeEntry = std::make_unique<BTFTypeTypeTag>(TmpTypeId, Value->getString());
+ TmpTypeId = addType(std::move(TypeEntry));
+ }
+ return TmpTypeId;
+}
+
/// Handle structure/union types.
void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct,
uint32_t &TypeId) {
/// pointee type will be replaced with either a real type or
/// a forward declaration.
auto TypeEntry = std::make_unique<BTFTypeDerived>(DTy, Tag, true);
- auto &Fixup = FixupDerivedTypes[CTy->getName()];
- Fixup.first = CTag == dwarf::DW_TAG_union_type;
- Fixup.second.push_back(TypeEntry.get());
+ auto &Fixup = FixupDerivedTypes[CTy];
+ Fixup.push_back(std::make_pair(DTy, TypeEntry.get()));
TypeId = addType(std::move(TypeEntry), DTy);
return;
}
}
if (Tag == dwarf::DW_TAG_pointer_type) {
- SmallVector<const MDString *, 4> MDStrs;
- DINodeArray Annots = DTy->getAnnotations();
- if (Annots) {
- // For type with "int __tag1 __tag2 *p", the MDStrs will have
- // content: [__tag1, __tag2].
- for (const Metadata *Annotations : Annots->operands()) {
- const MDNode *MD = cast<MDNode>(Annotations);
- const MDString *Name = cast<MDString>(MD->getOperand(0));
- if (!Name->getString().equals("btf_type_tag"))
- continue;
- MDStrs.push_back(cast<MDString>(MD->getOperand(1)));
- }
- }
-
- if (MDStrs.size() > 0) {
- // With MDStrs [__tag1, __tag2], the output type chain looks like
- // PTR -> __tag2 -> __tag1 -> BaseType
- // In the below, we construct BTF types with the order of __tag1, __tag2
- // and PTR.
- auto TypeEntry =
- std::make_unique<BTFTypeTypeTag>(DTy, MDStrs[0]->getString());
- unsigned TmpTypeId = addType(std::move(TypeEntry));
- for (unsigned I = 1; I < MDStrs.size(); I++) {
- const MDString *Value = MDStrs[I];
- TypeEntry =
- std::make_unique<BTFTypeTypeTag>(TmpTypeId, Value->getString());
- TmpTypeId = addType(std::move(TypeEntry));
- }
+ int TmpTypeId = genBTFTypeTags(DTy, -1);
+ if (TmpTypeId >= 0) {
auto TypeDEntry =
std::make_unique<BTFTypeDerived>(TmpTypeId, Tag, DTy->getName());
TypeId = addType(std::move(TypeDEntry), DTy);
// Fixups
for (auto &Fixup : FixupDerivedTypes) {
- StringRef TypeName = Fixup.first;
- bool IsUnion = Fixup.second.first;
+ const DICompositeType *CTy = Fixup.first;
+ StringRef TypeName = CTy->getName();
+ bool IsUnion = CTy->getTag() == dwarf::DW_TAG_union_type;
// Search through struct types
uint32_t StructTypeId = 0;
StructTypeId = addType(std::move(FwdTypeEntry));
}
- for (auto &DType : Fixup.second.second) {
- DType->setPointeeType(StructTypeId);
+ for (auto &TypeInfo : Fixup.second) {
+ const DIDerivedType *DTy = TypeInfo.first;
+ BTFTypeDerived *BDType = TypeInfo.second;
+
+ int TmpTypeId = genBTFTypeTags(DTy, StructTypeId);
+ if (TmpTypeId >= 0)
+ BDType->setPointeeType(TmpTypeId);
+ else
+ BDType->setPointeeType(StructTypeId);
}
}
std::map<std::string, std::unique_ptr<BTFKindDataSec>> DataSecEntries;
std::vector<BTFTypeStruct *> StructTypes;
std::map<const GlobalVariable *, std::pair<int64_t, uint32_t>> PatchImms;
- std::map<StringRef, std::pair<bool, std::vector<BTFTypeDerived *>>>
+ std::map<const DICompositeType *,
+ std::vector<std::pair<const DIDerivedType *, BTFTypeDerived *>>>
FixupDerivedTypes;
std::set<const Function *>ProtoFunctions;
void processDeclAnnotations(DINodeArray Annotations, uint32_t BaseTypeId,
int ComponentId);
+ /// Generate BTF type_tag's. If BaseTypeId is nonnegative, the last
+ /// BTF type_tag in the chain points to BaseTypeId. Otherwise, it points to
+ /// the base type of DTy. Return the type id of the first BTF type_tag
+ /// in the chain. If no type_tag's are generated, a negative value
+ /// is returned.
+ int genBTFTypeTags(const DIDerivedType *DTy, int BaseTypeId);
+
/// Generate one field relocation record.
void generatePatchImmReloc(const MCSymbol *ORSym, uint32_t RootId,
const GlobalVariable *, bool IsAma);
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+;
+; Source:
+; #define __tag1 __attribute__((btf_type_tag("tag1")))
+; #define __tag2 __attribute__((btf_type_tag("tag2")))
+;
+; struct foo;
+; struct map_value {
+; struct foo __tag2 __tag1 *ptr;
+; };
+; void func(struct map_value *);
+; void test(void)
+; {
+; struct map_value v = {};
+; func(&v);
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.map_value = type { %struct.foo* }
+%struct.foo = type opaque
+
+; Function Attrs: nounwind
+define dso_local void @test() local_unnamed_addr #0 !dbg !7 {
+entry:
+ %v = alloca %struct.map_value, align 8
+ %0 = bitcast %struct.map_value* %v to i8*, !dbg !20
+ call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %0) #4, !dbg !20
+ call void @llvm.dbg.declare(metadata %struct.map_value* %v, metadata !11, metadata !DIExpression()), !dbg !21
+ %1 = bitcast %struct.map_value* %v to i64*, !dbg !21
+ store i64 0, i64* %1, align 8, !dbg !21
+ call void @func(%struct.map_value* noundef nonnull %v) #4, !dbg !22
+ call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %0) #4, !dbg !23
+ ret void, !dbg !23
+}
+
+; CHECK: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
+; CHECK-NEXT: .long 218103808 # 0xd000000
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 1 # BTF_KIND_FUNC(id = 2)
+; CHECK-NEXT: .long 201326593 # 0xc000001
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 3)
+; CHECK-NEXT: .long 218103809 # 0xd000001
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 4)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long 62 # BTF_KIND_STRUCT(id = 5)
+; CHECK-NEXT: .long 67108865 # 0x4000001
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 72
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 76 # BTF_KIND_TYPE_TAG(id = 6)
+; CHECK-NEXT: .long 301989888 # 0x12000000
+; CHECK-NEXT: .long 9
+; CHECK-NEXT: .long 81 # BTF_KIND_TYPE_TAG(id = 7)
+; CHECK-NEXT: .long 301989888 # 0x12000000
+; CHECK-NEXT: .long 6
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 8)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 86 # BTF_KIND_FWD(id = 9)
+; CHECK-NEXT: .long 117440512 # 0x7000000
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 90 # BTF_KIND_FUNC(id = 10)
+; CHECK-NEXT: .long 201326594 # 0xc000002
+; CHECK-NEXT: .long 3
+
+; CHECK: .ascii "test" # string offset=1
+; CHECK: .ascii "map_value" # string offset=62
+; CHECK: .ascii "ptr" # string offset=72
+; CHECK: .ascii "tag2" # string offset=76
+; CHECK: .ascii "tag1" # string offset=81
+; CHECK: .ascii "foo" # string offset=86
+; CHECK: .ascii "func" # string offset=90
+
+; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
+declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: mustprogress nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #2
+
+declare !dbg !24 dso_local void @func(%struct.map_value* noundef) local_unnamed_addr #3
+
+; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
+declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
+
+attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+attributes #1 = { argmemonly mustprogress nofree nosync nounwind willreturn }
+attributes #2 = { mustprogress nofree nosync nounwind readnone speculatable willreturn }
+attributes #3 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 15.0.0 (https://github.com/llvm/llvm-project.git 25e8505f515bc9ef6c13527ffc4a902bae3a9071)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_tag_type", checksumkind: CSK_MD5, checksum: "7735a89e98603fee29d352a8e9db5acb")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 7, !"frame-pointer", i32 2}
+!6 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git 25e8505f515bc9ef6c13527ffc4a902bae3a9071)"}
+!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !8, scopeLine: 10, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10)
+!8 = !DISubroutineType(types: !9)
+!9 = !{null}
+!10 = !{!11}
+!11 = !DILocalVariable(name: "v", scope: !7, file: !1, line: 11, type: !12)
+!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "map_value", file: !1, line: 5, size: 64, elements: !13)
+!13 = !{!14}
+!14 = !DIDerivedType(tag: DW_TAG_member, name: "ptr", scope: !12, file: !1, line: 6, baseType: !15, size: 64)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64, annotations: !17)
+!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "foo", file: !1, line: 4, flags: DIFlagFwdDecl)
+!17 = !{!18, !19}
+!18 = !{!"btf_type_tag", !"tag2"}
+!19 = !{!"btf_type_tag", !"tag1"}
+!20 = !DILocation(line: 11, column: 9, scope: !7)
+!21 = !DILocation(line: 11, column: 26, scope: !7)
+!22 = !DILocation(line: 12, column: 9, scope: !7)
+!23 = !DILocation(line: 13, column: 1, scope: !7)
+!24 = !DISubprogram(name: "func", scope: !1, file: !1, line: 8, type: !25, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !28)
+!25 = !DISubroutineType(types: !26)
+!26 = !{null, !27}
+!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64)
+!28 = !{}
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+;
+; Source:
+; #define __tag1 __attribute__((btf_type_tag("tag1")))
+; #define __tag2 __attribute__((btf_type_tag("tag2")))
+;
+; struct foo {
+; int i;
+; };
+; struct map_value {
+; struct foo __tag2 __tag1 *ptr;
+; };
+; void func(struct map_value *, struct foo *);
+; void test(void)
+; {
+; struct map_value v = {};
+; func(&v, v.ptr);
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.map_value = type { %struct.foo* }
+%struct.foo = type { i32 }
+
+; Function Attrs: nounwind
+define dso_local void @test() local_unnamed_addr #0 !dbg !7 {
+entry:
+ %v = alloca %struct.map_value, align 8
+ %0 = bitcast %struct.map_value* %v to i8*, !dbg !23
+ call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %0) #4, !dbg !23
+ call void @llvm.dbg.declare(metadata %struct.map_value* %v, metadata !11, metadata !DIExpression()), !dbg !24
+ %1 = bitcast %struct.map_value* %v to i64*, !dbg !24
+ store i64 0, i64* %1, align 8, !dbg !24
+ call void @func(%struct.map_value* noundef nonnull %v, %struct.foo* noundef null) #4, !dbg !25
+ call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %0) #4, !dbg !26
+ ret void, !dbg !26
+}
+
+; CHECK: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
+; CHECK-NEXT: .long 218103808 # 0xd000000
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 1 # BTF_KIND_FUNC(id = 2)
+; CHECK-NEXT: .long 201326593 # 0xc000001
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 3)
+; CHECK-NEXT: .long 218103810 # 0xd000002
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 4)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long 63 # BTF_KIND_STRUCT(id = 5)
+; CHECK-NEXT: .long 67108865 # 0x4000001
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 73
+; CHECK-NEXT: .long 6
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 6)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 12
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 7)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 77 # BTF_KIND_STRUCT(id = 8)
+; CHECK-NEXT: .long 67108865 # 0x4000001
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 81
+; CHECK-NEXT: .long 9
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 83 # BTF_KIND_INT(id = 9)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 16777248 # 0x1000020
+; CHECK-NEXT: .long 87 # BTF_KIND_FUNC(id = 10)
+; CHECK-NEXT: .long 201326594 # 0xc000002
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 92 # BTF_KIND_TYPE_TAG(id = 11)
+; CHECK-NEXT: .long 301989888 # 0x12000000
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 97 # BTF_KIND_TYPE_TAG(id = 12)
+; CHECK-NEXT: .long 301989888 # 0x12000000
+; CHECK-NEXT: .long 11
+
+; CHECK: .ascii "test" # string offset=1
+; CHECK: .ascii "map_value" # string offset=63
+; CHECK: .ascii "ptr" # string offset=73
+; CHECK: .ascii "foo" # string offset=77
+; CHECK: .byte 105 # string offset=81
+; CHECK: .ascii "int" # string offset=83
+; CHECK: .ascii "func" # string offset=87
+; CHECK: .ascii "tag2" # string offset=92
+; CHECK: .ascii "tag1" # string offset=97
+
+; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
+declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: mustprogress nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #2
+
+declare !dbg !27 dso_local void @func(%struct.map_value* noundef, %struct.foo* noundef) local_unnamed_addr #3
+
+; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
+declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
+
+attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+attributes #1 = { argmemonly mustprogress nofree nosync nounwind willreturn }
+attributes #2 = { mustprogress nofree nosync nounwind readnone speculatable willreturn }
+attributes #3 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 15.0.0 (https://github.com/llvm/llvm-project.git 25e8505f515bc9ef6c13527ffc4a902bae3a9071)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp//home/yhs/work/tests/llvm/btf_tag_type", checksumkind: CSK_MD5, checksum: "8b3b8281c3b4240403467e0c9461251d")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 7, !"frame-pointer", i32 2}
+!6 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git 25e8505f515bc9ef6c13527ffc4a902bae3a9071)"}
+!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 11, type: !8, scopeLine: 12, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10)
+!8 = !DISubroutineType(types: !9)
+!9 = !{null}
+!10 = !{!11}
+!11 = !DILocalVariable(name: "v", scope: !7, file: !1, line: 13, type: !12)
+!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "map_value", file: !1, line: 7, size: 64, elements: !13)
+!13 = !{!14}
+!14 = !DIDerivedType(tag: DW_TAG_member, name: "ptr", scope: !12, file: !1, line: 8, baseType: !15, size: 64)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64, annotations: !20)
+!16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo", file: !1, line: 4, size: 32, elements: !17)
+!17 = !{!18}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !16, file: !1, line: 5, baseType: !19, size: 32)
+!19 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!20 = !{!21, !22}
+!21 = !{!"btf_type_tag", !"tag2"}
+!22 = !{!"btf_type_tag", !"tag1"}
+!23 = !DILocation(line: 13, column: 9, scope: !7)
+!24 = !DILocation(line: 13, column: 26, scope: !7)
+!25 = !DILocation(line: 14, column: 9, scope: !7)
+!26 = !DILocation(line: 15, column: 1, scope: !7)
+!27 = !DISubprogram(name: "func", scope: !1, file: !1, line: 10, type: !28, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !32)
+!28 = !DISubroutineType(types: !29)
+!29 = !{null, !30, !31}
+!30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64)
+!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!32 = !{}