[llvm] 4948927 - [BPF] support btf_tag attribute in .BTF section
Yonghong Song via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 28 21:03:49 PDT 2021
Author: Yonghong Song
Date: 2021-08-28T21:02:27-07:00
New Revision: 4948927058e5a8e808e44583c33e472d0d8a315d
URL: https://github.com/llvm/llvm-project/commit/4948927058e5a8e808e44583c33e472d0d8a315d
DIFF: https://github.com/llvm/llvm-project/commit/4948927058e5a8e808e44583c33e472d0d8a315d.diff
LOG: [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
Added:
llvm/test/CodeGen/BPF/BTF/tag-1.ll
llvm/test/CodeGen/BPF/BTF/tag-2.ll
Modified:
llvm/lib/Target/BPF/BTF.def
llvm/lib/Target/BPF/BTF.h
llvm/lib/Target/BPF/BTFDebug.cpp
llvm/lib/Target/BPF/BTFDebug.h
Removed:
################################################################################
diff --git a/llvm/lib/Target/BPF/BTF.def b/llvm/lib/Target/BPF/BTF.def
index 66cf2c90ead4..8a152cf8ea88 100644
--- a/llvm/lib/Target/BPF/BTF.def
+++ b/llvm/lib/Target/BPF/BTF.def
@@ -31,5 +31,6 @@ HANDLE_BTF_KIND(13, FUNC_PROTO)
HANDLE_BTF_KIND(14, VAR)
HANDLE_BTF_KIND(15, DATASEC)
HANDLE_BTF_KIND(16, FLOAT)
+HANDLE_BTF_KIND(17, TAG)
#undef HANDLE_BTF_KIND
diff --git a/llvm/lib/Target/BPF/BTF.h b/llvm/lib/Target/BPF/BTF.h
index ad3dcc14c38a..cf29547b4249 100644
--- a/llvm/lib/Target/BPF/BTF.h
+++ b/llvm/lib/Target/BPF/BTF.h
@@ -106,14 +106,14 @@ struct CommonType {
/// Bits 24-27: kind (e.g. int, ptr, array...etc)
/// Bits 28-30: unused
/// Bit 31: kind_flag, currently used by
- /// struct, union and fwd
+ /// struct, union, fwd and tag
uint32_t Info;
/// "Size" is used by INT, ENUM, STRUCT and UNION.
/// "Size" tells the size of the type it is describing.
///
/// "Type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
- /// FUNC, FUNC_PROTO and VAR.
+ /// FUNC, FUNC_PROTO, VAR and TAG.
/// "Type" is a type_id referring to another type.
union {
uint32_t Size;
diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp
index c1f8ea99b959..c13e2dcf8c6f 100644
--- a/llvm/lib/Target/BPF/BTFDebug.cpp
+++ b/llvm/lib/Target/BPF/BTFDebug.cpp
@@ -386,6 +386,27 @@ void BTFTypeFloat::completeType(BTFDebug &BDebug) {
BTFType.NameOff = BDebug.addString(Name);
}
+BTFTypeTag::BTFTypeTag(uint32_t BaseTypeId, int ComponentId, StringRef Tag)
+ : Tag(Tag) {
+ Kind = BTF::BTF_KIND_TAG;
+ BTFType.Info = ((ComponentId < 0) << 31) | (Kind << 24);
+ BTFType.Type = BaseTypeId;
+ Info = ComponentId < 0 ? 0 : ComponentId;
+}
+
+void BTFTypeTag::completeType(BTFDebug &BDebug) {
+ if (IsCompleted)
+ return;
+ IsCompleted = true;
+
+ BTFType.NameOff = BDebug.addString(Tag);
+}
+
+void BTFTypeTag::emitType(MCStreamer &OS) {
+ BTFTypeBase::emitType(OS);
+ OS.emitInt32(Info);
+}
+
uint32_t BTFStringTable::addString(StringRef S) {
// Check whether the string already exists.
for (auto &OffsetM : OffsetToIdMap) {
@@ -475,6 +496,24 @@ void BTFDebug::visitSubroutineType(
}
}
+void BTFDebug::processAnnotations(DINodeArray Annotations, uint32_t BaseTypeId,
+ int ComponentId) {
+ if (!Annotations)
+ return;
+
+ for (const Metadata *Annotation : Annotations->operands()) {
+ const MDNode *MD = cast<MDNode>(Annotation);
+ const MDString *Name = cast<MDString>(MD->getOperand(0));
+ if (!Name->getString().equals("btf_tag"))
+ continue;
+
+ const MDString *Value = cast<MDString>(MD->getOperand(1));
+ auto TypeEntry = std::make_unique<BTFTypeTag>(BaseTypeId, ComponentId,
+ Value->getString());
+ addType(std::move(TypeEntry));
+ }
+}
+
/// Handle structure/union types.
void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct,
uint32_t &TypeId) {
@@ -498,9 +537,17 @@ void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct,
StructTypes.push_back(TypeEntry.get());
TypeId = addType(std::move(TypeEntry), CTy);
+ // Check struct/union annotations
+ processAnnotations(CTy->getAnnotations(), TypeId, -1);
+
// Visit all struct members.
- for (const auto *Element : Elements)
- visitTypeEntry(cast<DIDerivedType>(Element));
+ int FieldNo = 0;
+ for (const auto *Element : Elements) {
+ const auto Elem = cast<DIDerivedType>(Element);
+ visitTypeEntry(Elem);
+ processAnnotations(Elem->getAnnotations(), TypeId, FieldNo);
+ FieldNo++;
+ }
}
void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) {
@@ -964,6 +1011,17 @@ void BTFDebug::beginFunctionImpl(const MachineFunction *MF) {
std::make_unique<BTFTypeFunc>(SP->getName(), ProtoTypeId, Scope);
uint32_t FuncTypeId = addType(std::move(FuncTypeEntry));
+ // Process argument annotations.
+ for (const DINode *DN : SP->getRetainedNodes()) {
+ if (const auto *DV = dyn_cast<DILocalVariable>(DN)) {
+ uint32_t Arg = DV->getArg();
+ if (Arg)
+ processAnnotations(DV->getAnnotations(), FuncTypeId, Arg - 1);
+ }
+ }
+
+ processAnnotations(SP->getAnnotations(), FuncTypeId, -1);
+
for (const auto &TypeEntry : TypeEntries)
TypeEntry->completeType(*this);
@@ -1176,11 +1234,13 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) {
continue;
uint32_t GVTypeId = 0;
+ DIGlobalVariable *DIGlobal = nullptr;
for (auto *GVE : GVs) {
+ DIGlobal = GVE->getVariable();
if (SecName.startswith(".maps"))
- visitMapDefType(GVE->getVariable()->getType(), GVTypeId);
+ visitMapDefType(DIGlobal->getType(), GVTypeId);
else
- visitTypeEntry(GVE->getVariable()->getType(), GVTypeId, false, false);
+ visitTypeEntry(DIGlobal->getType(), GVTypeId, false, false);
break;
}
@@ -1212,6 +1272,8 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) {
std::make_unique<BTFKindVar>(Global.getName(), GVTypeId, GVarInfo);
uint32_t VarId = addType(std::move(VarEntry));
+ processAnnotations(DIGlobal->getAnnotations(), VarId, -1);
+
// An empty SecName means an extern variable without section attribute.
if (SecName.empty())
continue;
@@ -1306,6 +1368,9 @@ void BTFDebug::processFuncPrototypes(const Function *F) {
auto FuncTypeEntry =
std::make_unique<BTFTypeFunc>(SP->getName(), ProtoTypeId, Scope);
uint32_t FuncId = addType(std::move(FuncTypeEntry));
+
+ processAnnotations(SP->getAnnotations(), FuncId, -1);
+
if (F->hasSection()) {
StringRef SecName = F->getSection();
diff --git a/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h
index 2fdcf8500b7f..c0e672c71989 100644
--- a/llvm/lib/Target/BPF/BTFDebug.h
+++ b/llvm/lib/Target/BPF/BTFDebug.h
@@ -204,6 +204,18 @@ class BTFTypeFloat : public BTFTypeBase {
void completeType(BTFDebug &BDebug) override;
};
+/// Handle tags.
+class BTFTypeTag : public BTFTypeBase {
+ uint32_t Info;
+ StringRef Tag;
+
+public:
+ BTFTypeTag(uint32_t BaseTypeId, int ComponentId, StringRef Tag);
+ uint32_t getSize() override { return BTFTypeBase::getSize() + 4; }
+ void completeType(BTFDebug &BDebug) override;
+ void emitType(MCStreamer &OS) override;
+};
+
/// String table.
class BTFStringTable {
/// String table size in bytes.
@@ -313,6 +325,10 @@ class BTFDebug : public DebugHandlerBase {
/// Generate types for function prototypes.
void processFuncPrototypes(const Function *);
+ /// Generate types for annotations.
+ void processAnnotations(DINodeArray Annotations, uint32_t BaseTypeId,
+ int ComponentId);
+
/// Generate one field relocation record.
void generatePatchImmReloc(const MCSymbol *ORSym, uint32_t RootId,
const GlobalVariable *, bool IsAma);
diff --git a/llvm/test/CodeGen/BPF/BTF/tag-1.ll b/llvm/test/CodeGen/BPF/BTF/tag-1.ll
new file mode 100644
index 000000000000..dd31ecf0c98c
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/BTF/tag-1.ll
@@ -0,0 +1,91 @@
+; 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 code:
+; #define __tag1 __attribute__((btf_tag("tag1")))
+; #define __tag2 __attribute__((btf_tag("tag2")))
+; struct t1 {
+; int a1;
+; int a2 __tag1 __tag2;
+; } __tag1 __tag2;
+; struct t1 g1 __tag1 __tag2;
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm t.c
+
+%struct.t1 = type { i32, i32 }
+
+ at g1 = dso_local local_unnamed_addr global %struct.t1 zeroinitializer, align 4, !dbg !0
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!14, !15, !16, !17}
+!llvm.ident = !{!18}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "g1", scope: !2, file: !3, line: 7, type: !6, isLocal: false, isDefinition: true, annotations: !11)
+!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)
+!3 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_tag")
+!4 = !{}
+!5 = !{!0}
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !3, line: 3, size: 64, elements: !7, annotations: !11)
+!7 = !{!8, !10}
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !6, file: !3, line: 4, baseType: !9, size: 32)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !6, file: !3, line: 5, baseType: !9, size: 32, offset: 32, annotations: !11)
+!11 = !{!12, !13}
+!12 = !{!"btf_tag", !"tag1"}
+!13 = !{!"btf_tag", !"tag2"}
+!14 = !{i32 7, !"Dwarf Version", i32 4}
+!15 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !{i32 1, !"wchar_size", i32 4}
+!17 = !{i32 7, !"frame-pointer", i32 2}
+!18 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git 825661b8e31d0b29d78178df1e518949dfec9f9a)"}
+
+; CHECK: .long 1 # BTF_KIND_STRUCT(id = 1)
+; CHECK-NEXT: .long 67108866 # 0x4000002
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 0 # 0x0
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 32 # 0x20
+; CHECK-NEXT: .long 10 # BTF_KIND_TAG(id = 2)
+; CHECK-NEXT: .long 2432696320 # 0x91000000
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 15 # BTF_KIND_TAG(id = 3)
+; CHECK-NEXT: .long 2432696320 # 0x91000000
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 20 # BTF_KIND_INT(id = 4)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 16777248 # 0x1000020
+; CHECK-NEXT: .long 10 # BTF_KIND_TAG(id = 5)
+; CHECK-NEXT: .long 285212672 # 0x11000000
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 15 # BTF_KIND_TAG(id = 6)
+; CHECK-NEXT: .long 285212672 # 0x11000000
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 24 # BTF_KIND_VAR(id = 7)
+; CHECK-NEXT: .long 234881024 # 0xe000000
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 10 # BTF_KIND_TAG(id = 8)
+; CHECK-NEXT: .long 2432696320 # 0x91000000
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 15 # BTF_KIND_TAG(id = 9)
+; CHECK-NEXT: .long 2432696320 # 0x91000000
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 0
+
+; CHECK: .ascii "t1" # string offset=1
+; CHECK: .ascii "a1" # string offset=4
+; CHECK: .ascii "a2" # string offset=7
+; CHECK: .ascii "tag1" # string offset=10
+; CHECK: .ascii "tag2" # string offset=15
+; CHECK: .ascii "int" # string offset=20
+; CHECK: .ascii "g1" # string offset=24
diff --git a/llvm/test/CodeGen/BPF/BTF/tag-2.ll b/llvm/test/CodeGen/BPF/BTF/tag-2.ll
new file mode 100644
index 000000000000..9be1db672aaf
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/BTF/tag-2.ll
@@ -0,0 +1,125 @@
+; 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 code:
+; #define __tag1 __attribute__((btf_tag("tag1")))
+; #define __tag2 __attribute__((btf_tag("tag2")))
+; extern int bar(int a1, int a2) __tag1 __tag2;
+; int __tag1 foo(int arg1, int *arg2 __tag1) {
+; ; return arg1 + *arg2 + bar(arg1, arg1 + 1);
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm t.c
+
+; Function Attrs: nounwind
+define dso_local i32 @foo(i32 %arg1, i32* nocapture readonly %arg2) local_unnamed_addr #0 !dbg !8 {
+entry:
+ call void @llvm.dbg.value(metadata i32 %arg1, metadata !14, metadata !DIExpression()), !dbg !18
+ call void @llvm.dbg.value(metadata i32* %arg2, metadata !15, metadata !DIExpression()), !dbg !18
+ %0 = load i32, i32* %arg2, align 4, !dbg !19, !tbaa !20
+ %add = add nsw i32 %0, %arg1, !dbg !24
+ %add1 = add nsw i32 %arg1, 1, !dbg !25
+ %call = tail call i32 @bar(i32 %arg1, i32 %add1) #3, !dbg !26
+ %add2 = add nsw i32 %add, %call, !dbg !27
+ ret i32 %add2, !dbg !28
+}
+
+declare !dbg !29 dso_local i32 @bar(i32, i32) local_unnamed_addr #1
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+attributes #2 = { nofree nosync nounwind readnone speculatable willreturn }
+attributes #3 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!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)
+!1 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_tag")
+!2 = !{}
+!3 = !{i32 7, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{i32 7, !"frame-pointer", i32 2}
+!7 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git 4be11596b26383c6666f471f07463a3f79e11964)"}
+!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)
+!9 = !DISubroutineType(types: !10)
+!10 = !{!11, !11, !12}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64)
+!13 = !{!14, !15}
+!14 = !DILocalVariable(name: "arg1", arg: 1, scope: !8, file: !1, line: 4, type: !11)
+!15 = !DILocalVariable(name: "arg2", arg: 2, scope: !8, file: !1, line: 4, type: !12, annotations: !16)
+!16 = !{!17}
+!17 = !{!"btf_tag", !"tag1"}
+!18 = !DILocation(line: 0, scope: !8)
+!19 = !DILocation(line: 5, column: 17, scope: !8)
+!20 = !{!21, !21, i64 0}
+!21 = !{!"int", !22, i64 0}
+!22 = !{!"omnipotent char", !23, i64 0}
+!23 = !{!"Simple C/C++ TBAA"}
+!24 = !DILocation(line: 5, column: 15, scope: !8)
+!25 = !DILocation(line: 5, column: 40, scope: !8)
+!26 = !DILocation(line: 5, column: 25, scope: !8)
+!27 = !DILocation(line: 5, column: 23, scope: !8)
+!28 = !DILocation(line: 5, column: 3, scope: !8)
+!29 = !DISubprogram(name: "bar", scope: !1, file: !1, line: 3, type: !30, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2, annotations: !32)
+!30 = !DISubroutineType(types: !31)
+!31 = !{!11, !11, !11}
+!32 = !{!17, !33}
+!33 = !{!"btf_tag", !"tag2"}
+
+; CHECK: .long 1 # BTF_KIND_INT(id = 1)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 16777248 # 0x1000020
+; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 2)
+; CHECK-NEXT: .long 33554432 # 0x2000000
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 3)
+; CHECK-NEXT: .long 218103810 # 0xd000002
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 5
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 10
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 15 # BTF_KIND_FUNC(id = 4)
+; CHECK-NEXT: .long 201326593 # 0xc000001
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 19 # BTF_KIND_TAG(id = 5)
+; CHECK-NEXT: .long 285212672 # 0x11000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 19 # BTF_KIND_TAG(id = 6)
+; CHECK-NEXT: .long 2432696320 # 0x91000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 7)
+; CHECK-NEXT: .long 218103810 # 0xd000002
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long 72 # BTF_KIND_FUNC(id = 8)
+; CHECK-NEXT: .long 201326594 # 0xc000002
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 19 # BTF_KIND_TAG(id = 9)
+; CHECK-NEXT: .long 2432696320 # 0x91000000
+; CHECK-NEXT: .long 8
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 76 # BTF_KIND_TAG(id = 10)
+; CHECK-NEXT: .long 2432696320 # 0x91000000
+; CHECK-NEXT: .long 8
+
+; CHECK: .ascii "int" # string offset=1
+; CHECK: .ascii "arg1" # string offset=5
+; CHECK: .ascii "arg2" # string offset=10
+; CHECK: .ascii "foo" # string offset=15
+; CHECK: .ascii "tag1" # string offset=19
+; CHECK: .ascii "bar" # string offset=72
+; CHECK: .ascii "tag2" # string offset=76
More information about the llvm-commits
mailing list