[llvm] fff2721 - [BPF] Fix CO-RE bugs with bitfields

Yonghong Song via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 4 20:09:00 PST 2019


Author: Yonghong Song
Date: 2019-11-04T20:08:05-08:00
New Revision: fff2721286e1c051c2b1c91210ddc3e6a9b179e1

URL: https://github.com/llvm/llvm-project/commit/fff2721286e1c051c2b1c91210ddc3e6a9b179e1
DIFF: https://github.com/llvm/llvm-project/commit/fff2721286e1c051c2b1c91210ddc3e6a9b179e1.diff

LOG: [BPF] Fix CO-RE bugs with bitfields

bitfield handling is not robust with current implementation.
I have seen two issues as described below.

Issue 1:
  struct s {
    long long f1;
    char f2;
    char b1:1;
  } *p;
  The current approach will generate an access bit size
  56 (from b1 to the end of structure) which will be
  rejected as it is not power of 2.

Issue 2:
  struct s {
    char f1;
    char b1:3;
    char b2:5;
    char b3:6:
    char b4:2;
    char f2;
  };
  The LLVM will group 4 bitfields together with 2 bytes. But
  loading 2 bytes is not correct as it violates alignment
  requirement. Note that sometimes, LLVM breaks a large
  bitfield groups into multiple groups, but not in this case.

To resolve the above two issues, this patch takes a
different approach. The alignment for the structure is used
to construct the offset of the bitfield access. The bitfield
incurred memory access is an aligned memory access with alignment/size
equal to the alignment of the structure.
This also simplified the code.

This may not be the optimal memory access in terms of memory access
width. But this should be okay since extracting the bitfield value
will have the same amount of work regardless of what kind of
memory access width.

Differential Revision: https://reviews.llvm.org/D69837

Added: 
    llvm/test/CodeGen/BPF/CORE/field-reloc-bitfield-1.ll
    llvm/test/CodeGen/BPF/CORE/field-reloc-bitfield-2.ll

Modified: 
    llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
index 405a07a04dad..41ba89f502a7 100644
--- a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
+++ b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
@@ -130,6 +130,8 @@ class BPFAbstractMemberAccess final : public ModulePass {
     BPFPreserveFieldInfoAI = 4,
   };
 
+  const DataLayout *DL;
+
   std::map<std::string, GlobalVariable *> GEPGlobals;
   // A map to link preserve_*_access_index instrinsic calls.
   std::map<CallInst *, std::pair<CallInst *, CallInfo>> AIChain;
@@ -154,11 +156,11 @@ class BPFAbstractMemberAccess final : public ModulePass {
   void replaceWithGEP(std::vector<CallInst *> &CallList,
                       uint32_t NumOfZerosIndex, uint32_t DIIndex);
   bool HasPreserveFieldInfoCall(CallInfoStack &CallStack);
-  void GetStorageBitRange(DICompositeType *CTy, DIDerivedType *MemberTy,
-                          uint32_t AccessIndex, uint32_t &StartBitOffset,
-                          uint32_t &EndBitOffset);
+  void GetStorageBitRange(DIDerivedType *MemberTy, uint32_t RecordAlignment,
+                          uint32_t &StartBitOffset, uint32_t &EndBitOffset);
   uint32_t GetFieldInfo(uint32_t InfoKind, DICompositeType *CTy,
-                        uint32_t AccessIndex, uint32_t PatchImm);
+                        uint32_t AccessIndex, uint32_t PatchImm,
+                        uint32_t RecordAlignment);
 
   Value *computeBaseAndAccessKey(CallInst *Call, CallInfo &CInfo,
                                  std::string &AccessKey, MDNode *&BaseMeta);
@@ -182,6 +184,7 @@ bool BPFAbstractMemberAccess::runOnModule(Module &M) {
   if (M.debug_compile_units().empty())
     return false;
 
+  DL = &M.getDataLayout();
   return doTransformation(M);
 }
 
@@ -509,40 +512,29 @@ uint64_t BPFAbstractMemberAccess::getConstant(const Value *IndexValue) {
 }
 
 /// Get the start and the end of storage offset for \p MemberTy.
-/// The storage bits are corresponding to the LLVM internal types,
-/// and the storage bits for the member determines what load width
-/// to use in order to extract the bitfield value.
-void BPFAbstractMemberAccess::GetStorageBitRange(DICompositeType *CTy,
-                                                 DIDerivedType *MemberTy,
-                                                 uint32_t AccessIndex,
+void BPFAbstractMemberAccess::GetStorageBitRange(DIDerivedType *MemberTy,
+                                                 uint32_t RecordAlignment,
                                                  uint32_t &StartBitOffset,
                                                  uint32_t &EndBitOffset) {
-  auto SOff = dyn_cast<ConstantInt>(MemberTy->getStorageOffsetInBits());
-  assert(SOff);
-  StartBitOffset = SOff->getZExtValue();
-
-  EndBitOffset = CTy->getSizeInBits();
-  uint32_t Index = AccessIndex + 1;
-  for (; Index < CTy->getElements().size(); ++Index) {
-    auto Member = cast<DIDerivedType>(CTy->getElements()[Index]);
-    if (!Member->isBitField()) {
-      EndBitOffset = Member->getOffsetInBits();
-      break;
-    }
-    SOff = dyn_cast<ConstantInt>(Member->getStorageOffsetInBits());
-    assert(SOff);
-    unsigned BitOffset = SOff->getZExtValue();
-    if (BitOffset != StartBitOffset) {
-      EndBitOffset = BitOffset;
-      break;
-    }
-  }
+  uint32_t MemberBitSize = MemberTy->getSizeInBits();
+  uint32_t MemberBitOffset = MemberTy->getOffsetInBits();
+  uint32_t AlignBits = RecordAlignment * 8;
+  if (RecordAlignment > 8 || MemberBitSize > AlignBits)
+    report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info, "
+                       "requiring too big alignment");
+
+  StartBitOffset = MemberBitOffset & ~(AlignBits - 1);
+  if ((StartBitOffset + AlignBits) < (MemberBitOffset + MemberBitSize))
+    report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info, "
+                       "cross alignment boundary");
+  EndBitOffset = StartBitOffset + AlignBits;
 }
 
 uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind,
                                                DICompositeType *CTy,
                                                uint32_t AccessIndex,
-                                               uint32_t PatchImm) {
+                                               uint32_t PatchImm,
+                                               uint32_t RecordAlignment) {
   if (InfoKind == BPFCoreSharedInfo::FIELD_EXISTENCE)
       return 1;
 
@@ -557,9 +549,10 @@ uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind,
       if (!MemberTy->isBitField()) {
         PatchImm += MemberTy->getOffsetInBits() >> 3;
       } else {
-        auto SOffset = dyn_cast<ConstantInt>(MemberTy->getStorageOffsetInBits());
-        assert(SOffset);
-        PatchImm += SOffset->getZExtValue() >> 3;
+        unsigned SBitOffset, NextSBitOffset;
+        GetStorageBitRange(MemberTy, RecordAlignment, SBitOffset,
+                           NextSBitOffset);
+        PatchImm += SBitOffset >> 3;
       }
     }
     return PatchImm;
@@ -576,7 +569,7 @@ uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind,
         return SizeInBits >> 3;
 
       unsigned SBitOffset, NextSBitOffset;
-      GetStorageBitRange(CTy, MemberTy, AccessIndex, SBitOffset, NextSBitOffset);
+      GetStorageBitRange(MemberTy, RecordAlignment, SBitOffset, NextSBitOffset);
       SizeInBits = NextSBitOffset - SBitOffset;
       if (SizeInBits & (SizeInBits - 1))
         report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info");
@@ -636,7 +629,7 @@ uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind,
     }
 
     unsigned SBitOffset, NextSBitOffset;
-    GetStorageBitRange(CTy, MemberTy, AccessIndex, SBitOffset, NextSBitOffset);
+    GetStorageBitRange(MemberTy, RecordAlignment, SBitOffset, NextSBitOffset);
     if (NextSBitOffset - SBitOffset > 64)
       report_fatal_error("too big field size for llvm.bpf.preserve.field.info");
 
@@ -667,7 +660,7 @@ uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind,
     }
 
     unsigned SBitOffset, NextSBitOffset;
-    GetStorageBitRange(CTy, MemberTy, AccessIndex, SBitOffset, NextSBitOffset);
+    GetStorageBitRange(MemberTy, RecordAlignment, SBitOffset, NextSBitOffset);
     if (NextSBitOffset - SBitOffset > 64)
       report_fatal_error("too big field size for llvm.bpf.preserve.field.info");
 
@@ -822,9 +815,12 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
     AccessKey += ":" + std::to_string(AccessIndex);
 
     MDNode *MDN = CInfo.Metadata;
+    uint32_t RecordAlignment =
+        DL->getABITypeAlignment(CInfo.Base->getType()->getPointerElementType());
     // At this stage, it cannot be pointer type.
     auto *CTy = cast<DICompositeType>(stripQualifiers(cast<DIType>(MDN)));
-    PatchImm = GetFieldInfo(InfoKind, CTy, AccessIndex, PatchImm);
+    PatchImm = GetFieldInfo(InfoKind, CTy, AccessIndex, PatchImm,
+                            RecordAlignment);
   }
 
   // Access key is the type name + reloc type + patched imm + access string,

diff  --git a/llvm/test/CodeGen/BPF/CORE/field-reloc-bitfield-1.ll b/llvm/test/CodeGen/BPF/CORE/field-reloc-bitfield-1.ll
new file mode 100644
index 000000000000..4bec7f3b7f8e
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/field-reloc-bitfield-1.ll
@@ -0,0 +1,126 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EL,CHECK-ALU64 %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EB,CHECK-ALU64 %s
+; RUN: llc -march=bpfel -mattr=+alu32 -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EL,CHECK-ALU32 %s
+; RUN: llc -march=bpfeb -mattr=+alu32 -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EB,CHECK-ALU32 %s
+; Source code:
+;   struct s {
+;     unsigned long long f1;
+;     unsigned f2;
+;     unsigned f3;
+;     unsigned f4;
+;     unsigned char f5;
+;     unsigned bf1:5,
+;              bf2:1;
+;   };
+;   enum {FIELD_TYPE_OFFSET = 0, FIELD_TYPE_SIZE = 1, FIELD_TYPE_LSHIFT_U64 = 4,};
+;   int test(struct s *arg) {
+;     return __builtin_preserve_field_info(arg->bf2, FIELD_TYPE_OFFSET) +
+;            __builtin_preserve_field_info(arg->bf2, FIELD_TYPE_SIZE) +
+;            __builtin_preserve_field_info(arg->bf2, FIELD_TYPE_LSHIFT_U64);
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.s = type { i64, i32, i32, i32, i8, i8 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%struct.s* %arg) local_unnamed_addr #0 !dbg !13 {
+entry:
+  call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !30, metadata !DIExpression()), !dbg !31
+  %0 = tail call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.ss(%struct.s* %arg, i32 5, i32 6), !dbg !32, !llvm.preserve.access.index !18
+  %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %0, i64 0), !dbg !33
+  %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %0, i64 1), !dbg !34
+  %add = add i32 %2, %1, !dbg !35
+  %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %0, i64 4), !dbg !36
+  %add1 = add i32 %add, %3, !dbg !37
+  ret i32 %add1, !dbg !38
+}
+
+; CHECK:             r1 = 16
+; CHECK:             r0 = 8
+; CHECK-ALU64:       r0 += r1
+; CHECK-ALU32:       w0 += w1
+; CHECK-EL:          r1 = 18
+; CHECK-EB:          r1 = 45
+; CHECK-ALU64:       r0 += r1
+; CHECK-ALU32:       w0 += w1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_STRUCT(id = 2)
+
+; CHECK:             .byte   115                     # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=89
+; CHECK:             .ascii  "0:6"                   # string offset=95
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   89                      # Field reloc section string offset=89
+; CHECK-NEXT:        .long   3
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   95
+; CHECK-NEXT:        .long   0
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   95
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   95
+; CHECK-NEXT:        .long   4
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.ss(%struct.s*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!9, !10, !11}
+!llvm.ident = !{!12}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git bc6913e314806882e2b537b5b03996800078d2ad)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 10, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6, !7, !8}
+!6 = !DIEnumerator(name: "FIELD_TYPE_OFFSET", value: 0, isUnsigned: true)
+!7 = !DIEnumerator(name: "FIELD_TYPE_SIZE", value: 1, isUnsigned: true)
+!8 = !DIEnumerator(name: "FIELD_TYPE_LSHIFT_U64", value: 4, isUnsigned: true)
+!9 = !{i32 2, !"Dwarf Version", i32 4}
+!10 = !{i32 2, !"Debug Info Version", i32 3}
+!11 = !{i32 1, !"wchar_size", i32 4}
+!12 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git bc6913e314806882e2b537b5b03996800078d2ad)"}
+!13 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 11, type: !14, scopeLine: 11, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !29)
+!14 = !DISubroutineType(types: !15)
+!15 = !{!16, !17}
+!16 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64)
+!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 192, elements: !19)
+!19 = !{!20, !22, !23, !24, !25, !27, !28}
+!20 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !18, file: !1, line: 2, baseType: !21, size: 64)
+!21 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned)
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "f2", scope: !18, file: !1, line: 3, baseType: !4, size: 32, offset: 64)
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "f3", scope: !18, file: !1, line: 4, baseType: !4, size: 32, offset: 96)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "f4", scope: !18, file: !1, line: 5, baseType: !4, size: 32, offset: 128)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "f5", scope: !18, file: !1, line: 6, baseType: !26, size: 8, offset: 160)
+!26 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char)
+!27 = !DIDerivedType(tag: DW_TAG_member, name: "bf1", scope: !18, file: !1, line: 7, baseType: !4, size: 5, offset: 168, flags: DIFlagBitField, extraData: i64 168)
+!28 = !DIDerivedType(tag: DW_TAG_member, name: "bf2", scope: !18, file: !1, line: 8, baseType: !4, size: 1, offset: 173, flags: DIFlagBitField, extraData: i64 168)
+!29 = !{!30}
+!30 = !DILocalVariable(name: "arg", arg: 1, scope: !13, file: !1, line: 11, type: !17)
+!31 = !DILocation(line: 0, scope: !13)
+!32 = !DILocation(line: 12, column: 45, scope: !13)
+!33 = !DILocation(line: 12, column: 10, scope: !13)
+!34 = !DILocation(line: 13, column: 10, scope: !13)
+!35 = !DILocation(line: 12, column: 69, scope: !13)
+!36 = !DILocation(line: 14, column: 10, scope: !13)
+!37 = !DILocation(line: 13, column: 67, scope: !13)
+!38 = !DILocation(line: 12, column: 3, scope: !13)

diff  --git a/llvm/test/CodeGen/BPF/CORE/field-reloc-bitfield-2.ll b/llvm/test/CodeGen/BPF/CORE/field-reloc-bitfield-2.ll
new file mode 100644
index 000000000000..14ffa8c4706c
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/CORE/field-reloc-bitfield-2.ll
@@ -0,0 +1,124 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EL,CHECK-ALU64 %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EB,CHECK-ALU64 %s
+; RUN: llc -march=bpfel -mattr=+alu32 -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EL,CHECK-ALU32 %s
+; RUN: llc -march=bpfeb -mattr=+alu32 -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EB,CHECK-ALU32 %s
+; Source code:
+;   struct s {
+;     char f1;
+;     char bf1:6,
+;          bf2:2,
+;          bf3:5,
+;          bf4:3;
+;   };
+;   enum {FIELD_TYPE_OFFSET = 0, FIELD_TYPE_SIZE = 1, FIELD_TYPE_LSHIFT_U64 = 4,};
+;   int test(struct s *arg) {
+;     return __builtin_preserve_field_info(arg->bf4, FIELD_TYPE_OFFSET) +
+;            __builtin_preserve_field_info(arg->bf4, FIELD_TYPE_SIZE) +
+;            __builtin_preserve_field_info(arg->bf4, FIELD_TYPE_LSHIFT_U64);
+;   }
+; For this case, the IR type has the same starting storage offset for fields
+; bf1, bf1, bf3 and bf4 and the ABI alignment is 1 byte. So for bf4 access,
+; the starting offset has to be at the beginning of field bf3.
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.s = type <{ i8, i16 }>
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%struct.s* %arg) local_unnamed_addr #0 !dbg !13 {
+entry:
+  call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !27, metadata !DIExpression()), !dbg !28
+  %0 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s* %arg, i32 1, i32 4), !dbg !29, !llvm.preserve.access.index !18
+  %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 0), !dbg !30
+  %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 1), !dbg !31
+  %add = add i32 %2, %1, !dbg !32
+  %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 4), !dbg !33
+  %add1 = add i32 %add, %3, !dbg !34
+  ret i32 %add1, !dbg !35
+}
+
+; CHECK:             r1 = 2
+; CHECK:             r0 = 1
+; CHECK-ALU64:       r0 += r1
+; CHECK-ALU32:       w0 += w1
+; CHECK-EL:          r1 = 56
+; CHECK-EB:          r1 = 61
+; CHECK-ALU64:       r0 += r1
+; CHECK-ALU32:       w0 += w1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_STRUCT(id = 2)
+
+; CHECK:             .byte   115                     # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=40
+; CHECK:             .ascii  "0:4"                   # string offset=46
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   40                      # Field reloc section string offset=40
+; CHECK-NEXT:        .long   3
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   46
+; CHECK-NEXT:        .long   0
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   46
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   46
+; CHECK-NEXT:        .long   4
+
+; Function Attrs: nounwind readnone
+declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readnone speculatable }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!9, !10, !11}
+!llvm.ident = !{!12}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 630ca91834ecc06349cb3b4bd2982c1b85b5ad96)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 8, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6, !7, !8}
+!6 = !DIEnumerator(name: "FIELD_TYPE_OFFSET", value: 0, isUnsigned: true)
+!7 = !DIEnumerator(name: "FIELD_TYPE_SIZE", value: 1, isUnsigned: true)
+!8 = !DIEnumerator(name: "FIELD_TYPE_LSHIFT_U64", value: 4, isUnsigned: true)
+!9 = !{i32 2, !"Dwarf Version", i32 4}
+!10 = !{i32 2, !"Debug Info Version", i32 3}
+!11 = !{i32 1, !"wchar_size", i32 4}
+!12 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 630ca91834ecc06349cb3b4bd2982c1b85b5ad96)"}
+!13 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !14, scopeLine: 9, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26)
+!14 = !DISubroutineType(types: !15)
+!15 = !{!16, !17}
+!16 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64)
+!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 24, elements: !19)
+!19 = !{!20, !22, !23, !24, !25}
+!20 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !18, file: !1, line: 2, baseType: !21, size: 8)
+!21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "bf1", scope: !18, file: !1, line: 3, baseType: !21, size: 6, offset: 8, flags: DIFlagBitField, extraData: i64 8)
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "bf2", scope: !18, file: !1, line: 4, baseType: !21, size: 2, offset: 14, flags: DIFlagBitField, extraData: i64 8)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "bf3", scope: !18, file: !1, line: 5, baseType: !21, size: 5, offset: 16, flags: DIFlagBitField, extraData: i64 8)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "bf4", scope: !18, file: !1, line: 6, baseType: !21, size: 3, offset: 21, flags: DIFlagBitField, extraData: i64 8)
+!26 = !{!27}
+!27 = !DILocalVariable(name: "arg", arg: 1, scope: !13, file: !1, line: 9, type: !17)
+!28 = !DILocation(line: 0, scope: !13)
+!29 = !DILocation(line: 10, column: 45, scope: !13)
+!30 = !DILocation(line: 10, column: 10, scope: !13)
+!31 = !DILocation(line: 11, column: 10, scope: !13)
+!32 = !DILocation(line: 10, column: 69, scope: !13)
+!33 = !DILocation(line: 12, column: 10, scope: !13)
+!34 = !DILocation(line: 11, column: 67, scope: !13)
+!35 = !DILocation(line: 10, column: 3, scope: !13)


        


More information about the llvm-commits mailing list