Skip to content

Commit 4948927

Browse files
committed
[BPF] support btf_tag attribute in .BTF section
A new kind BTF_KIND_TAG is added to .BTF to encode btf_tag attributes. The format looks like CommonType.name : attribute string CommonType.type : attached to a struct/union/func/var. CommonType.info : encoding BTF_KIND_TAG kflag == 1 to indicate the attribute is for CommonType.type, or kflag == 0 for struct/union member or func argument. one uint32_t : to encode which member/argument starting from 0. If one particular type or member/argument has more than one attribute, multiple BTF_KIND_TAG will be generated. Differential Revision: https://reviews.llvm.org/D106622
1 parent ca5f05d commit 4948927

File tree

6 files changed

+304
-6
lines changed

6 files changed

+304
-6
lines changed

llvm/lib/Target/BPF/BTF.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,6 @@ HANDLE_BTF_KIND(13, FUNC_PROTO)
3131
HANDLE_BTF_KIND(14, VAR)
3232
HANDLE_BTF_KIND(15, DATASEC)
3333
HANDLE_BTF_KIND(16, FLOAT)
34+
HANDLE_BTF_KIND(17, TAG)
3435

3536
#undef HANDLE_BTF_KIND

llvm/lib/Target/BPF/BTF.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,14 @@ struct CommonType {
106106
/// Bits 24-27: kind (e.g. int, ptr, array...etc)
107107
/// Bits 28-30: unused
108108
/// Bit 31: kind_flag, currently used by
109-
/// struct, union and fwd
109+
/// struct, union, fwd and tag
110110
uint32_t Info;
111111

112112
/// "Size" is used by INT, ENUM, STRUCT and UNION.
113113
/// "Size" tells the size of the type it is describing.
114114
///
115115
/// "Type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
116-
/// FUNC, FUNC_PROTO and VAR.
116+
/// FUNC, FUNC_PROTO, VAR and TAG.
117117
/// "Type" is a type_id referring to another type.
118118
union {
119119
uint32_t Size;

llvm/lib/Target/BPF/BTFDebug.cpp

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,27 @@ void BTFTypeFloat::completeType(BTFDebug &BDebug) {
386386
BTFType.NameOff = BDebug.addString(Name);
387387
}
388388

389+
BTFTypeTag::BTFTypeTag(uint32_t BaseTypeId, int ComponentId, StringRef Tag)
390+
: Tag(Tag) {
391+
Kind = BTF::BTF_KIND_TAG;
392+
BTFType.Info = ((ComponentId < 0) << 31) | (Kind << 24);
393+
BTFType.Type = BaseTypeId;
394+
Info = ComponentId < 0 ? 0 : ComponentId;
395+
}
396+
397+
void BTFTypeTag::completeType(BTFDebug &BDebug) {
398+
if (IsCompleted)
399+
return;
400+
IsCompleted = true;
401+
402+
BTFType.NameOff = BDebug.addString(Tag);
403+
}
404+
405+
void BTFTypeTag::emitType(MCStreamer &OS) {
406+
BTFTypeBase::emitType(OS);
407+
OS.emitInt32(Info);
408+
}
409+
389410
uint32_t BTFStringTable::addString(StringRef S) {
390411
// Check whether the string already exists.
391412
for (auto &OffsetM : OffsetToIdMap) {
@@ -475,6 +496,24 @@ void BTFDebug::visitSubroutineType(
475496
}
476497
}
477498

499+
void BTFDebug::processAnnotations(DINodeArray Annotations, uint32_t BaseTypeId,
500+
int ComponentId) {
501+
if (!Annotations)
502+
return;
503+
504+
for (const Metadata *Annotation : Annotations->operands()) {
505+
const MDNode *MD = cast<MDNode>(Annotation);
506+
const MDString *Name = cast<MDString>(MD->getOperand(0));
507+
if (!Name->getString().equals("btf_tag"))
508+
continue;
509+
510+
const MDString *Value = cast<MDString>(MD->getOperand(1));
511+
auto TypeEntry = std::make_unique<BTFTypeTag>(BaseTypeId, ComponentId,
512+
Value->getString());
513+
addType(std::move(TypeEntry));
514+
}
515+
}
516+
478517
/// Handle structure/union types.
479518
void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct,
480519
uint32_t &TypeId) {
@@ -498,9 +537,17 @@ void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct,
498537
StructTypes.push_back(TypeEntry.get());
499538
TypeId = addType(std::move(TypeEntry), CTy);
500539

540+
// Check struct/union annotations
541+
processAnnotations(CTy->getAnnotations(), TypeId, -1);
542+
501543
// Visit all struct members.
502-
for (const auto *Element : Elements)
503-
visitTypeEntry(cast<DIDerivedType>(Element));
544+
int FieldNo = 0;
545+
for (const auto *Element : Elements) {
546+
const auto Elem = cast<DIDerivedType>(Element);
547+
visitTypeEntry(Elem);
548+
processAnnotations(Elem->getAnnotations(), TypeId, FieldNo);
549+
FieldNo++;
550+
}
504551
}
505552

506553
void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) {
@@ -964,6 +1011,17 @@ void BTFDebug::beginFunctionImpl(const MachineFunction *MF) {
9641011
std::make_unique<BTFTypeFunc>(SP->getName(), ProtoTypeId, Scope);
9651012
uint32_t FuncTypeId = addType(std::move(FuncTypeEntry));
9661013

1014+
// Process argument annotations.
1015+
for (const DINode *DN : SP->getRetainedNodes()) {
1016+
if (const auto *DV = dyn_cast<DILocalVariable>(DN)) {
1017+
uint32_t Arg = DV->getArg();
1018+
if (Arg)
1019+
processAnnotations(DV->getAnnotations(), FuncTypeId, Arg - 1);
1020+
}
1021+
}
1022+
1023+
processAnnotations(SP->getAnnotations(), FuncTypeId, -1);
1024+
9671025
for (const auto &TypeEntry : TypeEntries)
9681026
TypeEntry->completeType(*this);
9691027

@@ -1176,11 +1234,13 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) {
11761234
continue;
11771235

11781236
uint32_t GVTypeId = 0;
1237+
DIGlobalVariable *DIGlobal = nullptr;
11791238
for (auto *GVE : GVs) {
1239+
DIGlobal = GVE->getVariable();
11801240
if (SecName.startswith(".maps"))
1181-
visitMapDefType(GVE->getVariable()->getType(), GVTypeId);
1241+
visitMapDefType(DIGlobal->getType(), GVTypeId);
11821242
else
1183-
visitTypeEntry(GVE->getVariable()->getType(), GVTypeId, false, false);
1243+
visitTypeEntry(DIGlobal->getType(), GVTypeId, false, false);
11841244
break;
11851245
}
11861246

@@ -1212,6 +1272,8 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) {
12121272
std::make_unique<BTFKindVar>(Global.getName(), GVTypeId, GVarInfo);
12131273
uint32_t VarId = addType(std::move(VarEntry));
12141274

1275+
processAnnotations(DIGlobal->getAnnotations(), VarId, -1);
1276+
12151277
// An empty SecName means an extern variable without section attribute.
12161278
if (SecName.empty())
12171279
continue;
@@ -1306,6 +1368,9 @@ void BTFDebug::processFuncPrototypes(const Function *F) {
13061368
auto FuncTypeEntry =
13071369
std::make_unique<BTFTypeFunc>(SP->getName(), ProtoTypeId, Scope);
13081370
uint32_t FuncId = addType(std::move(FuncTypeEntry));
1371+
1372+
processAnnotations(SP->getAnnotations(), FuncId, -1);
1373+
13091374
if (F->hasSection()) {
13101375
StringRef SecName = F->getSection();
13111376

llvm/lib/Target/BPF/BTFDebug.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,18 @@ class BTFTypeFloat : public BTFTypeBase {
204204
void completeType(BTFDebug &BDebug) override;
205205
};
206206

207+
/// Handle tags.
208+
class BTFTypeTag : public BTFTypeBase {
209+
uint32_t Info;
210+
StringRef Tag;
211+
212+
public:
213+
BTFTypeTag(uint32_t BaseTypeId, int ComponentId, StringRef Tag);
214+
uint32_t getSize() override { return BTFTypeBase::getSize() + 4; }
215+
void completeType(BTFDebug &BDebug) override;
216+
void emitType(MCStreamer &OS) override;
217+
};
218+
207219
/// String table.
208220
class BTFStringTable {
209221
/// String table size in bytes.
@@ -313,6 +325,10 @@ class BTFDebug : public DebugHandlerBase {
313325
/// Generate types for function prototypes.
314326
void processFuncPrototypes(const Function *);
315327

328+
/// Generate types for annotations.
329+
void processAnnotations(DINodeArray Annotations, uint32_t BaseTypeId,
330+
int ComponentId);
331+
316332
/// Generate one field relocation record.
317333
void generatePatchImmReloc(const MCSymbol *ORSym, uint32_t RootId,
318334
const GlobalVariable *, bool IsAma);

llvm/test/CodeGen/BPF/BTF/tag-1.ll

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
2+
; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
3+
4+
; Source code:
5+
; #define __tag1 __attribute__((btf_tag("tag1")))
6+
; #define __tag2 __attribute__((btf_tag("tag2")))
7+
; struct t1 {
8+
; int a1;
9+
; int a2 __tag1 __tag2;
10+
; } __tag1 __tag2;
11+
; struct t1 g1 __tag1 __tag2;
12+
; Compilation flag:
13+
; clang -target bpf -O2 -g -S -emit-llvm t.c
14+
15+
%struct.t1 = type { i32, i32 }
16+
17+
@g1 = dso_local local_unnamed_addr global %struct.t1 zeroinitializer, align 4, !dbg !0
18+
19+
!llvm.dbg.cu = !{!2}
20+
!llvm.module.flags = !{!14, !15, !16, !17}
21+
!llvm.ident = !{!18}
22+
23+
!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
24+
!1 = distinct !DIGlobalVariable(name: "g1", scope: !2, file: !3, line: 7, type: !6, isLocal: false, isDefinition: true, annotations: !11)
25+
!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 13.0.0 (https://github.com/llvm/llvm-project.git 825661b8e31d0b29d78178df1e518949dfec9f9a)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None)
26+
!3 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_tag")
27+
!4 = !{}
28+
!5 = !{!0}
29+
!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !3, line: 3, size: 64, elements: !7, annotations: !11)
30+
!7 = !{!8, !10}
31+
!8 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !6, file: !3, line: 4, baseType: !9, size: 32)
32+
!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
33+
!10 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !6, file: !3, line: 5, baseType: !9, size: 32, offset: 32, annotations: !11)
34+
!11 = !{!12, !13}
35+
!12 = !{!"btf_tag", !"tag1"}
36+
!13 = !{!"btf_tag", !"tag2"}
37+
!14 = !{i32 7, !"Dwarf Version", i32 4}
38+
!15 = !{i32 2, !"Debug Info Version", i32 3}
39+
!16 = !{i32 1, !"wchar_size", i32 4}
40+
!17 = !{i32 7, !"frame-pointer", i32 2}
41+
!18 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git 825661b8e31d0b29d78178df1e518949dfec9f9a)"}
42+
43+
; CHECK: .long 1 # BTF_KIND_STRUCT(id = 1)
44+
; CHECK-NEXT: .long 67108866 # 0x4000002
45+
; CHECK-NEXT: .long 8
46+
; CHECK-NEXT: .long 4
47+
; CHECK-NEXT: .long 4
48+
; CHECK-NEXT: .long 0 # 0x0
49+
; CHECK-NEXT: .long 7
50+
; CHECK-NEXT: .long 4
51+
; CHECK-NEXT: .long 32 # 0x20
52+
; CHECK-NEXT: .long 10 # BTF_KIND_TAG(id = 2)
53+
; CHECK-NEXT: .long 2432696320 # 0x91000000
54+
; CHECK-NEXT: .long 1
55+
; CHECK-NEXT: .long 0
56+
; CHECK-NEXT: .long 15 # BTF_KIND_TAG(id = 3)
57+
; CHECK-NEXT: .long 2432696320 # 0x91000000
58+
; CHECK-NEXT: .long 1
59+
; CHECK-NEXT: .long 0
60+
; CHECK-NEXT: .long 20 # BTF_KIND_INT(id = 4)
61+
; CHECK-NEXT: .long 16777216 # 0x1000000
62+
; CHECK-NEXT: .long 4
63+
; CHECK-NEXT: .long 16777248 # 0x1000020
64+
; CHECK-NEXT: .long 10 # BTF_KIND_TAG(id = 5)
65+
; CHECK-NEXT: .long 285212672 # 0x11000000
66+
; CHECK-NEXT: .long 1
67+
; CHECK-NEXT: .long 1
68+
; CHECK-NEXT: .long 15 # BTF_KIND_TAG(id = 6)
69+
; CHECK-NEXT: .long 285212672 # 0x11000000
70+
; CHECK-NEXT: .long 1
71+
; CHECK-NEXT: .long 1
72+
; CHECK-NEXT: .long 24 # BTF_KIND_VAR(id = 7)
73+
; CHECK-NEXT: .long 234881024 # 0xe000000
74+
; CHECK-NEXT: .long 1
75+
; CHECK-NEXT: .long 1
76+
; CHECK-NEXT: .long 10 # BTF_KIND_TAG(id = 8)
77+
; CHECK-NEXT: .long 2432696320 # 0x91000000
78+
; CHECK-NEXT: .long 7
79+
; CHECK-NEXT: .long 0
80+
; CHECK-NEXT: .long 15 # BTF_KIND_TAG(id = 9)
81+
; CHECK-NEXT: .long 2432696320 # 0x91000000
82+
; CHECK-NEXT: .long 7
83+
; CHECK-NEXT: .long 0
84+
85+
; CHECK: .ascii "t1" # string offset=1
86+
; CHECK: .ascii "a1" # string offset=4
87+
; CHECK: .ascii "a2" # string offset=7
88+
; CHECK: .ascii "tag1" # string offset=10
89+
; CHECK: .ascii "tag2" # string offset=15
90+
; CHECK: .ascii "int" # string offset=20
91+
; CHECK: .ascii "g1" # string offset=24

llvm/test/CodeGen/BPF/BTF/tag-2.ll

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
2+
; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
3+
4+
; Source code:
5+
; #define __tag1 __attribute__((btf_tag("tag1")))
6+
; #define __tag2 __attribute__((btf_tag("tag2")))
7+
; extern int bar(int a1, int a2) __tag1 __tag2;
8+
; int __tag1 foo(int arg1, int *arg2 __tag1) {
9+
; ; return arg1 + *arg2 + bar(arg1, arg1 + 1);
10+
; }
11+
; Compilation flag:
12+
; clang -target bpf -O2 -g -S -emit-llvm t.c
13+
14+
; Function Attrs: nounwind
15+
define dso_local i32 @foo(i32 %arg1, i32* nocapture readonly %arg2) local_unnamed_addr #0 !dbg !8 {
16+
entry:
17+
call void @llvm.dbg.value(metadata i32 %arg1, metadata !14, metadata !DIExpression()), !dbg !18
18+
call void @llvm.dbg.value(metadata i32* %arg2, metadata !15, metadata !DIExpression()), !dbg !18
19+
%0 = load i32, i32* %arg2, align 4, !dbg !19, !tbaa !20
20+
%add = add nsw i32 %0, %arg1, !dbg !24
21+
%add1 = add nsw i32 %arg1, 1, !dbg !25
22+
%call = tail call i32 @bar(i32 %arg1, i32 %add1) #3, !dbg !26
23+
%add2 = add nsw i32 %add, %call, !dbg !27
24+
ret i32 %add2, !dbg !28
25+
}
26+
27+
declare !dbg !29 dso_local i32 @bar(i32, i32) local_unnamed_addr #1
28+
29+
; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
30+
declare void @llvm.dbg.value(metadata, metadata, metadata) #2
31+
32+
attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
33+
attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
34+
attributes #2 = { nofree nosync nounwind readnone speculatable willreturn }
35+
attributes #3 = { nounwind }
36+
37+
!llvm.dbg.cu = !{!0}
38+
!llvm.module.flags = !{!3, !4, !5, !6}
39+
!llvm.ident = !{!7}
40+
41+
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0 (https://github.com/llvm/llvm-project.git 4be11596b26383c6666f471f07463a3f79e11964)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
42+
!1 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_tag")
43+
!2 = !{}
44+
!3 = !{i32 7, !"Dwarf Version", i32 4}
45+
!4 = !{i32 2, !"Debug Info Version", i32 3}
46+
!5 = !{i32 1, !"wchar_size", i32 4}
47+
!6 = !{i32 7, !"frame-pointer", i32 2}
48+
!7 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git 4be11596b26383c6666f471f07463a3f79e11964)"}
49+
!8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13, annotations: !16)
50+
!9 = !DISubroutineType(types: !10)
51+
!10 = !{!11, !11, !12}
52+
!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
53+
!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64)
54+
!13 = !{!14, !15}
55+
!14 = !DILocalVariable(name: "arg1", arg: 1, scope: !8, file: !1, line: 4, type: !11)
56+
!15 = !DILocalVariable(name: "arg2", arg: 2, scope: !8, file: !1, line: 4, type: !12, annotations: !16)
57+
!16 = !{!17}
58+
!17 = !{!"btf_tag", !"tag1"}
59+
!18 = !DILocation(line: 0, scope: !8)
60+
!19 = !DILocation(line: 5, column: 17, scope: !8)
61+
!20 = !{!21, !21, i64 0}
62+
!21 = !{!"int", !22, i64 0}
63+
!22 = !{!"omnipotent char", !23, i64 0}
64+
!23 = !{!"Simple C/C++ TBAA"}
65+
!24 = !DILocation(line: 5, column: 15, scope: !8)
66+
!25 = !DILocation(line: 5, column: 40, scope: !8)
67+
!26 = !DILocation(line: 5, column: 25, scope: !8)
68+
!27 = !DILocation(line: 5, column: 23, scope: !8)
69+
!28 = !DILocation(line: 5, column: 3, scope: !8)
70+
!29 = !DISubprogram(name: "bar", scope: !1, file: !1, line: 3, type: !30, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2, annotations: !32)
71+
!30 = !DISubroutineType(types: !31)
72+
!31 = !{!11, !11, !11}
73+
!32 = !{!17, !33}
74+
!33 = !{!"btf_tag", !"tag2"}
75+
76+
; CHECK: .long 1 # BTF_KIND_INT(id = 1)
77+
; CHECK-NEXT: .long 16777216 # 0x1000000
78+
; CHECK-NEXT: .long 4
79+
; CHECK-NEXT: .long 16777248 # 0x1000020
80+
; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 2)
81+
; CHECK-NEXT: .long 33554432 # 0x2000000
82+
; CHECK-NEXT: .long 1
83+
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 3)
84+
; CHECK-NEXT: .long 218103810 # 0xd000002
85+
; CHECK-NEXT: .long 1
86+
; CHECK-NEXT: .long 5
87+
; CHECK-NEXT: .long 1
88+
; CHECK-NEXT: .long 10
89+
; CHECK-NEXT: .long 2
90+
; CHECK-NEXT: .long 15 # BTF_KIND_FUNC(id = 4)
91+
; CHECK-NEXT: .long 201326593 # 0xc000001
92+
; CHECK-NEXT: .long 3
93+
; CHECK-NEXT: .long 19 # BTF_KIND_TAG(id = 5)
94+
; CHECK-NEXT: .long 285212672 # 0x11000000
95+
; CHECK-NEXT: .long 4
96+
; CHECK-NEXT: .long 1
97+
; CHECK-NEXT: .long 19 # BTF_KIND_TAG(id = 6)
98+
; CHECK-NEXT: .long 2432696320 # 0x91000000
99+
; CHECK-NEXT: .long 4
100+
; CHECK-NEXT: .long 0
101+
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 7)
102+
; CHECK-NEXT: .long 218103810 # 0xd000002
103+
; CHECK-NEXT: .long 1
104+
; CHECK-NEXT: .long 0
105+
; CHECK-NEXT: .long 1
106+
; CHECK-NEXT: .long 0
107+
; CHECK-NEXT: .long 1
108+
; CHECK-NEXT: .long 72 # BTF_KIND_FUNC(id = 8)
109+
; CHECK-NEXT: .long 201326594 # 0xc000002
110+
; CHECK-NEXT: .long 7
111+
; CHECK-NEXT: .long 19 # BTF_KIND_TAG(id = 9)
112+
; CHECK-NEXT: .long 2432696320 # 0x91000000
113+
; CHECK-NEXT: .long 8
114+
; CHECK-NEXT: .long 0
115+
; CHECK-NEXT: .long 76 # BTF_KIND_TAG(id = 10)
116+
; CHECK-NEXT: .long 2432696320 # 0x91000000
117+
; CHECK-NEXT: .long 8
118+
119+
; CHECK: .ascii "int" # string offset=1
120+
; CHECK: .ascii "arg1" # string offset=5
121+
; CHECK: .ascii "arg2" # string offset=10
122+
; CHECK: .ascii "foo" # string offset=15
123+
; CHECK: .ascii "tag1" # string offset=19
124+
; CHECK: .ascii "bar" # string offset=72
125+
; CHECK: .ascii "tag2" # string offset=76

0 commit comments

Comments
 (0)