]> granicus.if.org Git - llvm/commitdiff
[BPF] do compile-once run-everywhere relocation for bitfields
authorYonghong Song <yhs@fb.com>
Tue, 8 Oct 2019 18:23:17 +0000 (18:23 +0000)
committerYonghong Song <yhs@fb.com>
Tue, 8 Oct 2019 18:23:17 +0000 (18:23 +0000)
A bpf specific clang intrinsic is introduced:
   u32 __builtin_preserve_field_info(member_access, info_kind)
Depending on info_kind, different information will
be returned to the program. A relocation is also
recorded for this builtin so that bpf loader can
patch the instruction on the target host.
This clang intrinsic is used to get certain information
to facilitate struct/union member relocations.

The offset relocation is extended by 4 bytes to
include relocation kind.
Currently supported relocation kinds are
 enum {
    FIELD_BYTE_OFFSET = 0,
    FIELD_BYTE_SIZE,
    FIELD_EXISTENCE,
    FIELD_SIGNEDNESS,
    FIELD_LSHIFT_U64,
    FIELD_RSHIFT_U64,
 };
for __builtin_preserve_field_info. The old
access offset relocation is covered by
    FIELD_BYTE_OFFSET = 0.

An example:
struct s {
    int a;
    int b1:9;
    int b2:4;
};
enum {
    FIELD_BYTE_OFFSET = 0,
    FIELD_BYTE_SIZE,
    FIELD_EXISTENCE,
    FIELD_SIGNEDNESS,
    FIELD_LSHIFT_U64,
    FIELD_RSHIFT_U64,
};

void bpf_probe_read(void *, unsigned, const void *);
int field_read(struct s *arg) {
  unsigned long long ull = 0;
  unsigned offset = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_OFFSET);
  unsigned size = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_SIZE);
 #ifdef USE_PROBE_READ
  bpf_probe_read(&ull, size, (const void *)arg + offset);
  unsigned lshift = __builtin_preserve_field_info(arg->b2, FIELD_LSHIFT_U64);
 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
  lshift = lshift + (size << 3) - 64;
 #endif
 #else
  switch(size) {
  case 1:
    ull = *(unsigned char *)((void *)arg + offset); break;
  case 2:
    ull = *(unsigned short *)((void *)arg + offset); break;
  case 4:
    ull = *(unsigned int *)((void *)arg + offset); break;
  case 8:
    ull = *(unsigned long long *)((void *)arg + offset); break;
  }
  unsigned lshift = __builtin_preserve_field_info(arg->b2, FIELD_LSHIFT_U64);
 #endif
  ull <<= lshift;
  if (__builtin_preserve_field_info(arg->b2, FIELD_SIGNEDNESS))
    return (long long)ull >> __builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64);
  return ull >> __builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64);
}

There is a minor overhead for bpf_probe_read() on big endian.

The code and relocation generated for field_read where bpf_probe_read() is
used to access argument data on little endian mode:
        r3 = r1
        r1 = 0
        r1 = 4  <=== relocation (FIELD_BYTE_OFFSET)
        r3 += r1
        r1 = r10
        r1 += -8
        r2 = 4  <=== relocation (FIELD_BYTE_SIZE)
        call bpf_probe_read
        r2 = 51 <=== relocation (FIELD_LSHIFT_U64)
        r1 = *(u64 *)(r10 - 8)
        r1 <<= r2
        r2 = 60 <=== relocation (FIELD_RSHIFT_U64)
        r0 = r1
        r0 >>= r2
        r3 = 1  <=== relocation (FIELD_SIGNEDNESS)
        if r3 == 0 goto LBB0_2
        r1 s>>= r2
        r0 = r1
LBB0_2:
        exit

Compare to the above code between relocations FIELD_LSHIFT_U64 and
FIELD_LSHIFT_U64, the code with big endian mode has four more
instructions.
        r1 = 41   <=== relocation (FIELD_LSHIFT_U64)
        r6 += r1
        r6 += -64
        r6 <<= 32
        r6 >>= 32
        r1 = *(u64 *)(r10 - 8)
        r1 <<= r6
        r2 = 60   <=== relocation (FIELD_RSHIFT_U64)

The code and relocation generated when using direct load.
        r2 = 0
        r3 = 4
        r4 = 4
        if r4 s> 3 goto LBB0_3
        if r4 == 1 goto LBB0_5
        if r4 == 2 goto LBB0_6
        goto LBB0_9
LBB0_6:                                 # %sw.bb1
        r1 += r3
        r2 = *(u16 *)(r1 + 0)
        goto LBB0_9
LBB0_3:                                 # %entry
        if r4 == 4 goto LBB0_7
        if r4 == 8 goto LBB0_8
        goto LBB0_9
LBB0_8:                                 # %sw.bb9
        r1 += r3
        r2 = *(u64 *)(r1 + 0)
        goto LBB0_9
LBB0_5:                                 # %sw.bb
        r1 += r3
        r2 = *(u8 *)(r1 + 0)
        goto LBB0_9
LBB0_7:                                 # %sw.bb5
        r1 += r3
        r2 = *(u32 *)(r1 + 0)
LBB0_9:                                 # %sw.epilog
        r1 = 51
        r2 <<= r1
        r1 = 60
        r0 = r2
        r0 >>= r1
        r3 = 1
        if r3 == 0 goto LBB0_11
        r2 s>>= r1
        r0 = r2
LBB0_11:                                # %sw.epilog
        exit

Considering verifier is able to do limited constant
propogation following branches. The following is the
code actually traversed.
        r2 = 0
        r3 = 4   <=== relocation
        r4 = 4   <=== relocation
        if r4 s> 3 goto LBB0_3
LBB0_3:                                 # %entry
        if r4 == 4 goto LBB0_7
LBB0_7:                                 # %sw.bb5
        r1 += r3
        r2 = *(u32 *)(r1 + 0)
LBB0_9:                                 # %sw.epilog
        r1 = 51   <=== relocation
        r2 <<= r1
        r1 = 60   <=== relocation
        r0 = r2
        r0 >>= r1
        r3 = 1
        if r3 == 0 goto LBB0_11
        r2 s>>= r1
        r0 = r2
LBB0_11:                                # %sw.epilog
        exit

For native load case, the load size is calculated to be the
same as the size of load width LLVM otherwise used to load
the value which is then used to extract the bitfield value.

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@374099 91177308-0d34-0410-b5e6-96231b3b80d8

55 files changed:
include/llvm/IR/IntrinsicsBPF.td
lib/Target/BPF/BPF.h
lib/Target/BPF/BPFAbstractMemberAccess.cpp
lib/Target/BPF/BPFCORE.h
lib/Target/BPF/BPFTargetMachine.cpp
lib/Target/BPF/BTF.h
lib/Target/BPF/BTFDebug.cpp
lib/Target/BPF/BTFDebug.h
test/CodeGen/BPF/CORE/intrinsic-array.ll
test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-1.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-2.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-3.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-1.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-2.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-3.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-1.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-2.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-1.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-2.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-3.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-1.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-2.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-3.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/intrinsic-struct.ll
test/CodeGen/BPF/CORE/intrinsic-union.ll
test/CodeGen/BPF/CORE/offset-reloc-access-str.ll
test/CodeGen/BPF/CORE/offset-reloc-basic.ll
test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll
test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll
test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll
test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll
test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll
test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll
test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll
test/CodeGen/BPF/CORE/offset-reloc-end-load.ll
test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll
test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-1.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-2.ll [new file with mode: 0644]
test/CodeGen/BPF/CORE/offset-reloc-global-1.ll
test/CodeGen/BPF/CORE/offset-reloc-global-2.ll
test/CodeGen/BPF/CORE/offset-reloc-global-3.ll
test/CodeGen/BPF/CORE/offset-reloc-ignore.ll
test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll
test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll
test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll
test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll
test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll
test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll
test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll
test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll
test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll
test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll
test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll
test/CodeGen/BPF/CORE/offset-reloc-typedef.ll
test/CodeGen/BPF/CORE/offset-reloc-union.ll

index d7595a2a77007755ee9ad28f271c736400f7cc30..3618cc6a4128dad699480c7034e2521eacaa6e0b 100644 (file)
@@ -20,4 +20,7 @@ let TargetPrefix = "bpf" in {  // All intrinsics start with "llvm.bpf."
               Intrinsic<[llvm_i64_ty], [llvm_ptr_ty, llvm_i64_ty], [IntrReadMem]>;
   def int_bpf_pseudo : GCCBuiltin<"__builtin_bpf_pseudo">,
               Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty]>;
+  def int_bpf_preserve_field_info : GCCBuiltin<"__builtin_bpf_preserve_field_info">,
+              Intrinsic<[llvm_i32_ty], [llvm_anyptr_ty, llvm_i64_ty],
+              [IntrNoMem, ImmArg<1>]>;
 }
index d311fc15409460472b0d799a2a9581a134044a31..ba21503d868eec29a16a0ffcf4161dbcd57f6781 100644 (file)
@@ -15,7 +15,7 @@
 namespace llvm {
 class BPFTargetMachine;
 
-ModulePass *createBPFAbstractMemberAccess();
+ModulePass *createBPFAbstractMemberAccess(BPFTargetMachine *TM);
 
 FunctionPass *createBPFISelDag(BPFTargetMachine &TM);
 FunctionPass *createBPFMISimplifyPatchablePass();
index 5a9a34e4af3c28612d3ffc1cd63fb5b348104637..1b442815c7ed9d8028b4d051e40c6c1c3981da13 100644 (file)
 //   addr = preserve_struct_access_index(base, gep_index, di_index)
 //          !llvm.preserve.access.index <struct_ditype>
 //
+// Bitfield member access needs special attention. User cannot take the
+// address of a bitfield acceess. To facilitate kernel verifier
+// for easy bitfield code optimization, a new clang intrinsic is introduced:
+//   uint32_t __builtin_preserve_field_info(member_access, info_kind)
+// In IR, a chain with two (or more) intrinsic calls will be generated:
+//   ...
+//   addr = preserve_struct_access_index(base, 1, 1) !struct s
+//   uint32_t result = bpf_preserve_field_info(addr, info_kind)
+//
+// Suppose the info_kind is FIELD_SIGNEDNESS,
+// The above two IR intrinsics will be replaced with
+// a relocatable insn:
+//   signness = /* signness of member_access */
+// and signness can be changed by bpf loader based on the
+// types on the host.
+//
+// User can also test whether a field exists or not with
+//   uint32_t result = bpf_preserve_field_info(member_access, FIELD_EXISTENCE)
+// The field will be always available (result = 1) during initial
+// compilation, but bpf loader can patch with the correct value
+// on the target host where the member_access may or may not be available
+//
 //===----------------------------------------------------------------------===//
 
 #include "BPF.h"
@@ -88,7 +110,11 @@ class BPFAbstractMemberAccess final : public ModulePass {
 
 public:
   static char ID;
-  BPFAbstractMemberAccess() : ModulePass(ID) {}
+  TargetMachine *TM;
+  // Add optional BPFTargetMachine parameter so that BPF backend can add the phase
+  // with target machine to find out the endianness. The default constructor (without
+  // parameters) is used by the pass manager for managing purposes.
+  BPFAbstractMemberAccess(BPFTargetMachine *TM = nullptr) : ModulePass(ID), TM(TM) {}
 
   struct CallInfo {
     uint32_t Kind;
@@ -96,19 +122,21 @@ public:
     MDNode *Metadata;
     Value *Base;
   };
+  typedef std::stack<std::pair<CallInst *, CallInfo>> CallInfoStack;
 
 private:
   enum : uint32_t {
     BPFPreserveArrayAI = 1,
     BPFPreserveUnionAI = 2,
     BPFPreserveStructAI = 3,
+    BPFPreserveFieldInfoAI = 4,
   };
 
   std::map<std::string, GlobalVariable *> GEPGlobals;
   // A map to link preserve_*_access_index instrinsic calls.
   std::map<CallInst *, std::pair<CallInst *, CallInfo>> AIChain;
   // A map to hold all the base preserve_*_access_index instrinsic calls.
-  // The base call is not an input of any other preserve_*_access_index
+  // The base call is not an input of any other preserve_*
   // intrinsics.
   std::map<CallInst *, CallInfo> BaseAICalls;
 
@@ -127,6 +155,12 @@ private:
   bool removePreserveAccessIndexIntrinsic(Module &M);
   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);
+  uint32_t GetFieldInfo(uint32_t InfoKind, DICompositeType *CTy,
+                        uint32_t AccessIndex, uint32_t PatchImm);
 
   Value *computeBaseAndAccessKey(CallInst *Call, CallInfo &CInfo,
                                  std::string &AccessKey, MDNode *&BaseMeta);
@@ -139,8 +173,8 @@ char BPFAbstractMemberAccess::ID = 0;
 INITIALIZE_PASS(BPFAbstractMemberAccess, DEBUG_TYPE,
                 "abstracting struct/union member accessees", false, false)
 
-ModulePass *llvm::createBPFAbstractMemberAccess() {
-  return new BPFAbstractMemberAccess();
+ModulePass *llvm::createBPFAbstractMemberAccess(BPFTargetMachine *TM) {
+  return new BPFAbstractMemberAccess(TM);
 }
 
 bool BPFAbstractMemberAccess::runOnModule(Module &M) {
@@ -231,6 +265,16 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
     CInfo.Base = Call->getArgOperand(0);
     return true;
   }
+  if (GV->getName().startswith("llvm.bpf.preserve.field.info")) {
+    CInfo.Kind = BPFPreserveFieldInfoAI;
+    CInfo.Metadata = nullptr;
+    // Check validity of info_kind as clang did not check this.
+    uint64_t InfoKind = getConstant(Call->getArgOperand(1));
+    if (InfoKind >= BPFCoreSharedInfo::MAX_FIELD_RELOC_KIND)
+      report_fatal_error("Incorrect info_kind for llvm.bpf.preserve.field.info intrinsic");
+    CInfo.AccessIndex = InfoKind;
+    return true;
+  }
 
   return false;
 }
@@ -306,6 +350,9 @@ bool BPFAbstractMemberAccess::removePreserveAccessIndexIntrinsic(Module &M) {
 bool BPFAbstractMemberAccess::IsValidAIChain(const MDNode *ParentType,
                                              uint32_t ParentAI,
                                              const MDNode *ChildType) {
+  if (!ChildType)
+    return true; // preserve_field_info, no type comparison needed.
+
   const DIType *PType = stripQualifiers(cast<DIType>(ParentType));
   const DIType *CType = stripQualifiers(cast<DIType>(ChildType));
 
@@ -463,7 +510,187 @@ uint64_t BPFAbstractMemberAccess::getConstant(const Value *IndexValue) {
   return CV->getValue().getZExtValue();
 }
 
-/// Compute the base of the whole preserve_*_access_index chains, i.e., the base
+/// 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,
+                                                 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->getStorageOffsetInBits()) {
+      EndBitOffset = Member->getOffsetInBits();
+      break;
+    }
+    SOff = dyn_cast<ConstantInt>(Member->getStorageOffsetInBits());
+    assert(SOff);
+    unsigned BitOffset = SOff->getZExtValue();
+    if (BitOffset != StartBitOffset) {
+      EndBitOffset = BitOffset;
+      break;
+    }
+  }
+}
+
+uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind,
+                                               DICompositeType *CTy,
+                                               uint32_t AccessIndex,
+                                               uint32_t PatchImm) {
+  if (InfoKind == BPFCoreSharedInfo::FIELD_EXISTENCE)
+      return 1;
+
+  uint32_t Tag = CTy->getTag();
+  if (InfoKind == BPFCoreSharedInfo::FIELD_BYTE_OFFSET) {
+    if (Tag == dwarf::DW_TAG_array_type) {
+      auto *EltTy = stripQualifiers(CTy->getBaseType());
+      PatchImm += AccessIndex * calcArraySize(CTy, 1) *
+                  (EltTy->getSizeInBits() >> 3);
+    } else if (Tag == dwarf::DW_TAG_structure_type) {
+      auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
+      if (!MemberTy->isBitField()) {
+        PatchImm += MemberTy->getOffsetInBits() >> 3;
+      } else {
+        auto SOffset = dyn_cast<ConstantInt>(MemberTy->getStorageOffsetInBits());
+        assert(SOffset);
+        PatchImm += SOffset->getZExtValue() >> 3;
+      }
+    }
+    return PatchImm;
+  }
+
+  if (InfoKind == BPFCoreSharedInfo::FIELD_BYTE_SIZE) {
+    if (Tag == dwarf::DW_TAG_array_type) {
+      auto *EltTy = stripQualifiers(CTy->getBaseType());
+      return calcArraySize(CTy, 1) * (EltTy->getSizeInBits() >> 3);
+    } else {
+      auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
+      uint32_t SizeInBits = MemberTy->getSizeInBits();
+      if (!MemberTy->isBitField())
+        return SizeInBits >> 3;
+
+      unsigned SBitOffset, NextSBitOffset;
+      GetStorageBitRange(CTy, MemberTy, AccessIndex, SBitOffset, NextSBitOffset);
+      SizeInBits = NextSBitOffset - SBitOffset;
+      if (SizeInBits & (SizeInBits - 1))
+        report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info");
+      return SizeInBits >> 3;
+    }
+  }
+
+  if (InfoKind == BPFCoreSharedInfo::FIELD_SIGNEDNESS) {
+    const DIType *BaseTy;
+    if (Tag == dwarf::DW_TAG_array_type) {
+      // Signedness only checked when final array elements are accessed.
+      if (CTy->getElements().size() != 1)
+        report_fatal_error("Invalid array expression for llvm.bpf.preserve.field.info");
+      BaseTy = stripQualifiers(CTy->getBaseType());
+    } else {
+      auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
+      BaseTy = stripQualifiers(MemberTy->getBaseType());
+    }
+
+    // Only basic types and enum types have signedness.
+    const auto *BTy = dyn_cast<DIBasicType>(BaseTy);
+    while (!BTy) {
+      const auto *CompTy = dyn_cast<DICompositeType>(BaseTy);
+      // Report an error if the field expression does not have signedness.
+      if (!CompTy || CompTy->getTag() != dwarf::DW_TAG_enumeration_type)
+        report_fatal_error("Invalid field expression for llvm.bpf.preserve.field.info");
+      BaseTy = stripQualifiers(CompTy->getBaseType());
+      BTy = dyn_cast<DIBasicType>(BaseTy);
+    }
+    uint32_t Encoding = BTy->getEncoding();
+    return (Encoding == dwarf::DW_ATE_signed || Encoding == dwarf::DW_ATE_signed_char);
+  }
+
+  if (InfoKind == BPFCoreSharedInfo::FIELD_LSHIFT_U64) {
+    // The value is loaded into a value with FIELD_BYTE_SIZE size,
+    // and then zero or sign extended to U64.
+    // FIELD_LSHIFT_U64 and FIELD_RSHIFT_U64 are operations
+    // to extract the original value.
+    const Triple &Triple = TM->getTargetTriple();
+    DIDerivedType *MemberTy = nullptr;
+    bool IsBitField = false;
+    uint32_t SizeInBits;
+
+    if (Tag == dwarf::DW_TAG_array_type) {
+      auto *EltTy = stripQualifiers(CTy->getBaseType());
+      SizeInBits = calcArraySize(CTy, 1) * EltTy->getSizeInBits();
+    } else {
+      MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
+      SizeInBits = MemberTy->getSizeInBits();
+      IsBitField = MemberTy->isBitField();
+    }
+
+    if (!IsBitField) {
+      if (SizeInBits > 64)
+        report_fatal_error("too big field size for llvm.bpf.preserve.field.info");
+      return 64 - SizeInBits;
+    }
+
+    unsigned SBitOffset, NextSBitOffset;
+    GetStorageBitRange(CTy, MemberTy, AccessIndex, SBitOffset, NextSBitOffset);
+    if (NextSBitOffset - SBitOffset > 64)
+      report_fatal_error("too big field size for llvm.bpf.preserve.field.info");
+
+    unsigned OffsetInBits = MemberTy->getOffsetInBits();
+    if (Triple.getArch() == Triple::bpfel)
+      return SBitOffset + 64 - OffsetInBits - SizeInBits;
+    else
+      return OffsetInBits + 64 - NextSBitOffset;
+  }
+
+  if (InfoKind == BPFCoreSharedInfo::FIELD_RSHIFT_U64) {
+    DIDerivedType *MemberTy = nullptr;
+    bool IsBitField = false;
+    uint32_t SizeInBits;
+    if (Tag == dwarf::DW_TAG_array_type) {
+      auto *EltTy = stripQualifiers(CTy->getBaseType());
+      SizeInBits = calcArraySize(CTy, 1) * EltTy->getSizeInBits();
+    } else {
+      MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
+      SizeInBits = MemberTy->getSizeInBits();
+      IsBitField = MemberTy->isBitField();
+    }
+
+    if (!IsBitField) {
+      if (SizeInBits > 64)
+        report_fatal_error("too big field size for llvm.bpf.preserve.field.info");
+      return 64 - SizeInBits;
+    }
+
+    unsigned SBitOffset, NextSBitOffset;
+    GetStorageBitRange(CTy, MemberTy, AccessIndex, SBitOffset, NextSBitOffset);
+    if (NextSBitOffset - SBitOffset > 64)
+      report_fatal_error("too big field size for llvm.bpf.preserve.field.info");
+
+    return 64 - SizeInBits;
+  }
+
+  llvm_unreachable("Unknown llvm.bpf.preserve.field.info info kind");
+}
+
+bool BPFAbstractMemberAccess::HasPreserveFieldInfoCall(CallInfoStack &CallStack) {
+  // This is called in error return path, no need to maintain CallStack.
+  while (CallStack.size()) {
+    auto StackElem = CallStack.top();
+    if (StackElem.second.Kind == BPFPreserveFieldInfoAI)
+      return true;
+    CallStack.pop();
+  }
+  return false;
+}
+
+/// Compute the base of the whole preserve_* intrinsics chains, i.e., the base
 /// pointer of the first preserve_*_access_index call, and construct the access
 /// string, which will be the name of a global variable.
 Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
@@ -472,7 +699,7 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
                                                         MDNode *&TypeMeta) {
   Value *Base = nullptr;
   std::string TypeName;
-  std::stack<std::pair<CallInst *, CallInfo>> CallStack;
+  CallInfoStack CallStack;
 
   // Put the access chain into a stack with the top as the head of the chain.
   while (Call) {
@@ -492,7 +719,8 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
   //    int a[10][20]; ... __builtin_preserve_access_index(&a[2][3]) ...
   // we will skip them.
   uint32_t FirstIndex = 0;
-  uint32_t AccessOffset = 0;
+  uint32_t PatchImm = 0; // AccessOffset or the requested field info
+  uint32_t InfoKind = BPFCoreSharedInfo::FIELD_BYTE_OFFSET;
   while (CallStack.size()) {
     auto StackElem = CallStack.top();
     Call = StackElem.first;
@@ -507,10 +735,12 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
       // struct or union type
       TypeName = Ty->getName();
       TypeMeta = Ty;
-      AccessOffset += FirstIndex * Ty->getSizeInBits() >> 3;
+      PatchImm += FirstIndex * (Ty->getSizeInBits() >> 3);
       break;
     }
 
+    assert(CInfo.Kind == BPFPreserveArrayAI);
+
     // Array entries will always be consumed for accumulative initial index.
     CallStack.pop();
 
@@ -546,16 +776,22 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
 
     if (CheckElemType) {
       auto *CTy = dyn_cast<DICompositeType>(BaseTy);
-      if (!CTy)
+      if (!CTy) {
+        if (HasPreserveFieldInfoCall(CallStack))
+          report_fatal_error("Invalid field access for llvm.preserve.field.info intrinsic");
         return nullptr;
+      }
 
       unsigned CTag = CTy->getTag();
-      if (CTag != dwarf::DW_TAG_structure_type && CTag != dwarf::DW_TAG_union_type)
-        return nullptr;
-      else
+      if (CTag == dwarf::DW_TAG_structure_type || CTag == dwarf::DW_TAG_union_type) {
         TypeName = CTy->getName();
+      } else {
+        if (HasPreserveFieldInfoCall(CallStack))
+          report_fatal_error("Invalid field access for llvm.preserve.field.info intrinsic");
+        return nullptr;
+      }
       TypeMeta = CTy;
-      AccessOffset += FirstIndex * CTy->getSizeInBits() >> 3;
+      PatchImm += FirstIndex * (CTy->getSizeInBits() >> 3);
       break;
     }
   }
@@ -569,6 +805,20 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
     CInfo = StackElem.second;
     CallStack.pop();
 
+    if (CInfo.Kind == BPFPreserveFieldInfoAI)
+      break;
+
+    // If the next Call (the top of the stack) is a BPFPreserveFieldInfoAI,
+    // the action will be extracting field info.
+    if (CallStack.size()) {
+      auto StackElem2 = CallStack.top();
+      CallInfo CInfo2 = StackElem2.second;
+      if (CInfo2.Kind == BPFPreserveFieldInfoAI) {
+        InfoKind = CInfo2.AccessIndex;
+        assert(CallStack.size() == 1);
+      }
+    }
+
     // Access Index
     uint64_t AccessIndex = CInfo.AccessIndex;
     AccessKey += ":" + std::to_string(AccessIndex);
@@ -576,20 +826,13 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
     MDNode *MDN = CInfo.Metadata;
     // At this stage, it cannot be pointer type.
     auto *CTy = cast<DICompositeType>(stripQualifiers(cast<DIType>(MDN)));
-    uint32_t Tag = CTy->getTag();
-    if (Tag == dwarf::DW_TAG_structure_type) {
-      auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
-      AccessOffset += MemberTy->getOffsetInBits() >> 3;
-    } else if (Tag == dwarf::DW_TAG_array_type) {
-      auto *EltTy = stripQualifiers(CTy->getBaseType());
-      AccessOffset += AccessIndex * calcArraySize(CTy, 1) *
-                      EltTy->getSizeInBits() >> 3;
-    }
+    PatchImm = GetFieldInfo(InfoKind, CTy, AccessIndex, PatchImm);
   }
 
-  // Access key is the type name + access string, uniquely identifying
-  // one kernel memory access.
-  AccessKey = TypeName + ":" + std::to_string(AccessOffset) + "$" + AccessKey;
+  // Access key is the type name + reloc type + patched imm + access string,
+  // uniquely identifying one relocation.
+  AccessKey = TypeName + ":" + std::to_string(InfoKind) + ":" +
+              std::to_string(PatchImm) + "$" + AccessKey;
 
   return Base;
 }
@@ -605,22 +848,18 @@ bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call,
   if (!Base)
     return false;
 
-  // Do the transformation
-  // For any original GEP Call and Base %2 like
-  //   %4 = bitcast %struct.net_device** %dev1 to i64*
-  // it is transformed to:
-  //   %6 = load sk_buff:50:$0:0:0:2:0
-  //   %7 = bitcast %struct.sk_buff* %2 to i8*
-  //   %8 = getelementptr i8, i8* %7, %6
-  //   %9 = bitcast i8* %8 to i64*
-  //   using %9 instead of %4
-  // The original Call inst is removed.
   BasicBlock *BB = Call->getParent();
   GlobalVariable *GV;
 
   if (GEPGlobals.find(AccessKey) == GEPGlobals.end()) {
-    GV = new GlobalVariable(M, Type::getInt64Ty(BB->getContext()), false,
-                            GlobalVariable::ExternalLinkage, NULL, AccessKey);
+    IntegerType *VarType;
+    if (CInfo.Kind == BPFPreserveFieldInfoAI)
+      VarType = Type::getInt32Ty(BB->getContext()); // 32bit return value
+    else
+      VarType = Type::getInt64Ty(BB->getContext()); // 64bit ptr arith
+
+    GV = new GlobalVariable(M, VarType, false, GlobalVariable::ExternalLinkage,
+                            NULL, AccessKey);
     GV->addAttribute(BPFCoreSharedInfo::AmaAttr);
     GV->setMetadata(LLVMContext::MD_preserve_access_index, TypeMeta);
     GEPGlobals[AccessKey] = GV;
@@ -628,6 +867,25 @@ bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call,
     GV = GEPGlobals[AccessKey];
   }
 
+  if (CInfo.Kind == BPFPreserveFieldInfoAI) {
+    // Load the global variable which represents the returned field info.
+    auto *LDInst = new LoadInst(Type::getInt32Ty(BB->getContext()), GV);
+    BB->getInstList().insert(Call->getIterator(), LDInst);
+    Call->replaceAllUsesWith(LDInst);
+    Call->eraseFromParent();
+    return true;
+  }
+
+  // For any original GEP Call and Base %2 like
+  //   %4 = bitcast %struct.net_device** %dev1 to i64*
+  // it is transformed to:
+  //   %6 = load sk_buff:50:$0:0:0:2:0
+  //   %7 = bitcast %struct.sk_buff* %2 to i8*
+  //   %8 = getelementptr i8, i8* %7, %6
+  //   %9 = bitcast i8* %8 to i64*
+  //   using %9 instead of %4
+  // The original Call inst is removed.
+
   // Load the global variable.
   auto *LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV);
   BB->getInstList().insert(Call->getIterator(), LDInst);
index e0950d95f8d7f467f809b4d9aaa477562f75ba5a..a6cb3cf5337606e95aebe6c03c9544d2e94d82a8 100644 (file)
@@ -13,6 +13,16 @@ namespace llvm {
 
 class BPFCoreSharedInfo {
 public:
+  enum OffsetRelocKind : uint32_t {
+    FIELD_BYTE_OFFSET = 0,
+    FIELD_BYTE_SIZE,
+    FIELD_EXISTENCE,
+    FIELD_SIGNEDNESS,
+    FIELD_LSHIFT_U64,
+    FIELD_RSHIFT_U64,
+
+    MAX_FIELD_RELOC_KIND,
+  };
   /// The attribute attached to globals representing a member offset
   static const std::string AmaAttr;
   /// The section name to identify a patchable external global
index a69a8067753934ec1dc1bab063623dd3020c6e9c..d940ac965c07df27fd196c3934af72f2dcc85b35 100644 (file)
@@ -94,7 +94,7 @@ TargetPassConfig *BPFTargetMachine::createPassConfig(PassManagerBase &PM) {
 
 void BPFPassConfig::addIRPasses() {
 
-  addPass(createBPFAbstractMemberAccess());
+  addPass(createBPFAbstractMemberAccess(&getBPFTargetMachine()));
 
   TargetPassConfig::addIRPasses();
 }
index ad56716710a6342a9541b77c4afe301b3d74ecd3..ef408dafd52b28fec52c090ad5dc144ca4272f2a 100644 (file)
@@ -17,7 +17,7 @@
 ///
 /// The binary layout for .BTF.ext section:
 ///   struct ExtHeader
-///   FuncInfo, LineInfo, OffsetReloc and ExternReloc subsections
+///   FuncInfo, LineInfo, FieldReloc and ExternReloc subsections
 /// The FuncInfo subsection is defined as below:
 ///   BTFFuncInfo Size
 ///   struct SecFuncInfo for ELF section #1
 ///   struct SecLineInfo for ELF section #2
 ///   A number of struct BPFLineInfo for ELF section #2
 ///   ...
-/// The OffsetReloc subsection is defined as below:
-///   BPFOffsetReloc Size
-///   struct SecOffsetReloc for ELF section #1
-///   A number of struct BPFOffsetReloc for ELF section #1
-///   struct SecOffsetReloc for ELF section #2
-///   A number of struct BPFOffsetReloc for ELF section #2
+/// The FieldReloc subsection is defined as below:
+///   BPFFieldReloc Size
+///   struct SecFieldReloc for ELF section #1
+///   A number of struct BPFFieldReloc for ELF section #1
+///   struct SecFieldReloc for ELF section #2
+///   A number of struct BPFFieldReloc for ELF section #2
 ///   ...
 /// The ExternReloc subsection is defined as below:
 ///   BPFExternReloc Size
@@ -72,11 +72,11 @@ enum {
   BTFDataSecVarSize = 12,
   SecFuncInfoSize = 8,
   SecLineInfoSize = 8,
-  SecOffsetRelocSize = 8,
+  SecFieldRelocSize = 8,
   SecExternRelocSize = 8,
   BPFFuncInfoSize = 8,
   BPFLineInfoSize = 16,
-  BPFOffsetRelocSize = 12,
+  BPFFieldRelocSize = 16,
   BPFExternRelocSize = 8,
 };
 
@@ -213,8 +213,8 @@ struct ExtHeader {
   uint32_t FuncInfoLen;    ///< Length of func info section
   uint32_t LineInfoOff;    ///< Offset of line info section
   uint32_t LineInfoLen;    ///< Length of line info section
-  uint32_t OffsetRelocOff; ///< Offset of offset reloc section
-  uint32_t OffsetRelocLen; ///< Length of offset reloc section
+  uint32_t FieldRelocOff; ///< Offset of offset reloc section
+  uint32_t FieldRelocLen; ///< Length of offset reloc section
   uint32_t ExternRelocOff; ///< Offset of extern reloc section
   uint32_t ExternRelocLen; ///< Length of extern reloc section
 };
@@ -247,16 +247,17 @@ struct SecLineInfo {
 };
 
 /// Specifying one offset relocation.
-struct BPFOffsetReloc {
+struct BPFFieldReloc {
   uint32_t InsnOffset;    ///< Byte offset in this section
   uint32_t TypeID;        ///< TypeID for the relocation
   uint32_t OffsetNameOff; ///< The string to traverse types
+  uint32_t RelocKind;     ///< What to patch the instruction
 };
 
 /// Specifying offset relocation's in one section.
-struct SecOffsetReloc {
+struct SecFieldReloc {
   uint32_t SecNameOff;     ///< Section name index in the .BTF string table
-  uint32_t NumOffsetReloc; ///< Number of offset reloc's in this section
+  uint32_t NumFieldReloc; ///< Number of offset reloc's in this section
 };
 
 /// Specifying one offset relocation.
index 3ad32347e0a1086c5e8966588eb717a4864f234d..a8f857343ec3339731474326af8b44dd1664e5c6 100644 (file)
@@ -754,7 +754,7 @@ void BTFDebug::emitBTFSection() {
 void BTFDebug::emitBTFExtSection() {
   // Do not emit section if empty FuncInfoTable and LineInfoTable.
   if (!FuncInfoTable.size() && !LineInfoTable.size() &&
-      !OffsetRelocTable.size() && !ExternRelocTable.size())
+      !FieldRelocTable.size() && !ExternRelocTable.size())
     return;
 
   MCContext &Ctx = OS.getContext();
@@ -766,8 +766,8 @@ void BTFDebug::emitBTFExtSection() {
 
   // Account for FuncInfo/LineInfo record size as well.
   uint32_t FuncLen = 4, LineLen = 4;
-  // Do not account for optional OffsetReloc/ExternReloc.
-  uint32_t OffsetRelocLen = 0, ExternRelocLen = 0;
+  // Do not account for optional FieldReloc/ExternReloc.
+  uint32_t FieldRelocLen = 0, ExternRelocLen = 0;
   for (const auto &FuncSec : FuncInfoTable) {
     FuncLen += BTF::SecFuncInfoSize;
     FuncLen += FuncSec.second.size() * BTF::BPFFuncInfoSize;
@@ -776,17 +776,17 @@ void BTFDebug::emitBTFExtSection() {
     LineLen += BTF::SecLineInfoSize;
     LineLen += LineSec.second.size() * BTF::BPFLineInfoSize;
   }
-  for (const auto &OffsetRelocSec : OffsetRelocTable) {
-    OffsetRelocLen += BTF::SecOffsetRelocSize;
-    OffsetRelocLen += OffsetRelocSec.second.size() * BTF::BPFOffsetRelocSize;
+  for (const auto &FieldRelocSec : FieldRelocTable) {
+    FieldRelocLen += BTF::SecFieldRelocSize;
+    FieldRelocLen += FieldRelocSec.second.size() * BTF::BPFFieldRelocSize;
   }
   for (const auto &ExternRelocSec : ExternRelocTable) {
     ExternRelocLen += BTF::SecExternRelocSize;
     ExternRelocLen += ExternRelocSec.second.size() * BTF::BPFExternRelocSize;
   }
 
-  if (OffsetRelocLen)
-    OffsetRelocLen += 4;
+  if (FieldRelocLen)
+    FieldRelocLen += 4;
   if (ExternRelocLen)
     ExternRelocLen += 4;
 
@@ -795,8 +795,8 @@ void BTFDebug::emitBTFExtSection() {
   OS.EmitIntValue(FuncLen, 4);
   OS.EmitIntValue(LineLen, 4);
   OS.EmitIntValue(FuncLen + LineLen, 4);
-  OS.EmitIntValue(OffsetRelocLen, 4);
-  OS.EmitIntValue(FuncLen + LineLen + OffsetRelocLen, 4);
+  OS.EmitIntValue(FieldRelocLen, 4);
+  OS.EmitIntValue(FuncLen + LineLen + FieldRelocLen, 4);
   OS.EmitIntValue(ExternRelocLen, 4);
 
   // Emit func_info table.
@@ -831,19 +831,20 @@ void BTFDebug::emitBTFExtSection() {
     }
   }
 
-  // Emit offset reloc table.
-  if (OffsetRelocLen) {
-    OS.AddComment("OffsetReloc");
-    OS.EmitIntValue(BTF::BPFOffsetRelocSize, 4);
-    for (const auto &OffsetRelocSec : OffsetRelocTable) {
-      OS.AddComment("Offset reloc section string offset=" +
-                    std::to_string(OffsetRelocSec.first));
-      OS.EmitIntValue(OffsetRelocSec.first, 4);
-      OS.EmitIntValue(OffsetRelocSec.second.size(), 4);
-      for (const auto &OffsetRelocInfo : OffsetRelocSec.second) {
-        Asm->EmitLabelReference(OffsetRelocInfo.Label, 4);
-        OS.EmitIntValue(OffsetRelocInfo.TypeID, 4);
-        OS.EmitIntValue(OffsetRelocInfo.OffsetNameOff, 4);
+  // Emit field reloc table.
+  if (FieldRelocLen) {
+    OS.AddComment("FieldReloc");
+    OS.EmitIntValue(BTF::BPFFieldRelocSize, 4);
+    for (const auto &FieldRelocSec : FieldRelocTable) {
+      OS.AddComment("Field reloc section string offset=" +
+                    std::to_string(FieldRelocSec.first));
+      OS.EmitIntValue(FieldRelocSec.first, 4);
+      OS.EmitIntValue(FieldRelocSec.second.size(), 4);
+      for (const auto &FieldRelocInfo : FieldRelocSec.second) {
+        Asm->EmitLabelReference(FieldRelocInfo.Label, 4);
+        OS.EmitIntValue(FieldRelocInfo.TypeID, 4);
+        OS.EmitIntValue(FieldRelocInfo.OffsetNameOff, 4);
+        OS.EmitIntValue(FieldRelocInfo.RelocKind, 4);
       }
     }
   }
@@ -958,23 +959,27 @@ unsigned BTFDebug::populateStructType(const DIType *Ty) {
   return Id;
 }
 
-/// Generate a struct member offset relocation.
-void BTFDebug::generateOffsetReloc(const MachineInstr *MI,
+/// Generate a struct member field relocation.
+void BTFDebug::generateFieldReloc(const MachineInstr *MI,
                                    const MCSymbol *ORSym, DIType *RootTy,
                                    StringRef AccessPattern) {
   unsigned RootId = populateStructType(RootTy);
   size_t FirstDollar = AccessPattern.find_first_of('$');
   size_t FirstColon = AccessPattern.find_first_of(':');
+  size_t SecondColon = AccessPattern.find_first_of(':', FirstColon + 1);
   StringRef IndexPattern = AccessPattern.substr(FirstDollar + 1);
-  StringRef OffsetStr = AccessPattern.substr(FirstColon + 1,
-      FirstDollar - FirstColon);
-
-  BTFOffsetReloc OffsetReloc;
-  OffsetReloc.Label = ORSym;
-  OffsetReloc.OffsetNameOff = addString(IndexPattern);
-  OffsetReloc.TypeID = RootId;
-  AccessOffsets[AccessPattern.str()] = std::stoi(OffsetStr);
-  OffsetRelocTable[SecNameOff].push_back(OffsetReloc);
+  StringRef RelocKindStr = AccessPattern.substr(FirstColon + 1,
+      SecondColon - FirstColon);
+  StringRef PatchImmStr = AccessPattern.substr(SecondColon + 1,
+      FirstDollar - SecondColon);
+
+  BTFFieldReloc FieldReloc;
+  FieldReloc.Label = ORSym;
+  FieldReloc.OffsetNameOff = addString(IndexPattern);
+  FieldReloc.TypeID = RootId;
+  FieldReloc.RelocKind = std::stoull(RelocKindStr);
+  PatchImms[AccessPattern.str()] = std::stoul(PatchImmStr);
+  FieldRelocTable[SecNameOff].push_back(FieldReloc);
 }
 
 void BTFDebug::processLDimm64(const MachineInstr *MI) {
@@ -982,7 +987,7 @@ void BTFDebug::processLDimm64(const MachineInstr *MI) {
   // will generate an .BTF.ext record.
   //
   // If the insn is "r2 = LD_imm64 @__BTF_...",
-  // add this insn into the .BTF.ext OffsetReloc subsection.
+  // add this insn into the .BTF.ext FieldReloc subsection.
   // Relocation looks like:
   //  . SecName:
   //    . InstOffset
@@ -1013,7 +1018,7 @@ void BTFDebug::processLDimm64(const MachineInstr *MI) {
 
       MDNode *MDN = GVar->getMetadata(LLVMContext::MD_preserve_access_index);
       DIType *Ty = dyn_cast<DIType>(MDN);
-      generateOffsetReloc(MI, ORSym, Ty, GVar->getName());
+      generateFieldReloc(MI, ORSym, Ty, GVar->getName());
     } else if (GVar && !GVar->hasInitializer() && GVar->hasExternalLinkage() &&
                GVar->getSection() == BPFCoreSharedInfo::PatchableExtSecName) {
       MCSymbol *ORSym = OS.getContext().createTempSymbol();
@@ -1154,8 +1159,8 @@ bool BTFDebug::InstLower(const MachineInstr *MI, MCInst &OutMI) {
       const GlobalValue *GVal = MO.getGlobal();
       auto *GVar = dyn_cast<GlobalVariable>(GVal);
       if (GVar && GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) {
-        // Emit "mov ri, <imm>" for abstract member accesses.
-        int64_t Imm = AccessOffsets[GVar->getName().str()];
+        // Emit "mov ri, <imm>" for patched immediate.
+        uint32_t Imm = PatchImms[GVar->getName().str()];
         OutMI.setOpcode(BPF::MOV_ri);
         OutMI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
         OutMI.addOperand(MCOperand::createImm(Imm));
index a79527d5e355168d34473a8288fe37bc4391d761..eec8614431663c18e1651f611ffab16cd62f1d06 100644 (file)
@@ -195,7 +195,7 @@ class BTFStringTable {
   /// A mapping from string table offset to the index
   /// of the Table. It is used to avoid putting
   /// duplicated strings in the table.
-  std::unordered_map<uint32_t, uint32_t> OffsetToIdMap;
+  std::map<uint32_t, uint32_t> OffsetToIdMap;
   /// A vector of strings to represent the string table.
   std::vector<std::string> Table;
 
@@ -224,10 +224,11 @@ struct BTFLineInfo {
 };
 
 /// Represent one offset relocation.
-struct BTFOffsetReloc {
+struct BTFFieldReloc {
   const MCSymbol *Label;  ///< MCSymbol identifying insn for the reloc
   uint32_t TypeID;        ///< Type ID
   uint32_t OffsetNameOff; ///< The string to traverse types
+  uint32_t RelocKind;     ///< What to patch the instruction
 };
 
 /// Represent one extern relocation.
@@ -249,12 +250,12 @@ class BTFDebug : public DebugHandlerBase {
   std::unordered_map<const DIType *, uint32_t> DIToIdMap;
   std::map<uint32_t, std::vector<BTFFuncInfo>> FuncInfoTable;
   std::map<uint32_t, std::vector<BTFLineInfo>> LineInfoTable;
-  std::map<uint32_t, std::vector<BTFOffsetReloc>> OffsetRelocTable;
+  std::map<uint32_t, std::vector<BTFFieldReloc>> FieldRelocTable;
   std::map<uint32_t, std::vector<BTFExternReloc>> ExternRelocTable;
   StringMap<std::vector<std::string>> FileContent;
   std::map<std::string, std::unique_ptr<BTFKindDataSec>> DataSecEntries;
   std::vector<BTFTypeStruct *> StructTypes;
-  std::map<std::string, int64_t> AccessOffsets;
+  std::map<std::string, uint32_t> PatchImms;
   std::map<StringRef, std::pair<bool, std::vector<BTFTypeDerived *>>>
       FixupDerivedTypes;
 
@@ -300,7 +301,7 @@ class BTFDebug : public DebugHandlerBase {
   void processGlobals(bool ProcessingMapDef);
 
   /// Generate one offset relocation record.
-  void generateOffsetReloc(const MachineInstr *MI, const MCSymbol *ORSym,
+  void generateFieldReloc(const MachineInstr *MI, const MCSymbol *ORSym,
                            DIType *RootTy, StringRef AccessPattern);
 
   /// Populating unprocessed struct type.
index fe2c1968fd9e536a368c7edc25a39e029c0c3a08..cf5511e7414039c5cb671326fae0ea0d98cb687b 100644 (file)
@@ -28,12 +28,13 @@ entry:
 ; CHECK:       exit
 ;
 ; CHECK:      .section        .BTF.ext,"",@progbits
-; CHECK:      .long   12                      # OffsetReloc
-; CHECK-NEXT: .long   20                      # Offset reloc section string offset=20
+; CHECK:      .long   16                      # FieldReloc
+; CHECK-NEXT: .long   20                      # Field reloc section string offset=20
 ; CHECK-NEXT: .long   1
 ; CHECK-NEXT: .long   [[RELOC]]
 ; CHECK-NEXT: .long   2
 ; CHECK-NEXT: .long   26
+; CHECK-NEXT: .long   0
 
 declare dso_local i32 @get_value(i8*) local_unnamed_addr #1
 
diff --git a/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-1.ll b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-1.ll
new file mode 100644 (file)
index 0000000..d8be7b8
--- /dev/null
@@ -0,0 +1,148 @@
+; 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:
+;   typedef struct s1 { int a1:7; int a2:4; int a3:5; int a4:16;} __s1;
+;   union u1 { int b1; __s1 b2; };
+;   enum { FIELD_BYTE_SIZE = 1, };
+;   int test(union u1 *arg) {
+;     unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_BYTE_SIZE);
+;     unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_BYTE_SIZE);
+;     unsigned r3 = __builtin_preserve_field_info(arg->b2.a3, FIELD_BYTE_SIZE);
+;     unsigned r4 = __builtin_preserve_field_info(arg->b2.a4, FIELD_BYTE_SIZE);
+;     /* r1: 4, r2: 4, r3: 4, r4: 4 */
+;     return r1 + r2 + r3 + r4;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { i32 }
+%struct.s1 = type { i32 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 {
+entry:
+  call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !28, metadata !DIExpression()), !dbg !33
+  %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !34, !llvm.preserve.access.index !16
+  %b2 = bitcast %union.u1* %0 to %struct.s1*, !dbg !34
+  %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !21
+  %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 1), !dbg !36
+  call void @llvm.dbg.value(metadata i32 %2, metadata !29, metadata !DIExpression()), !dbg !33
+  %3 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 1), !dbg !37, !llvm.preserve.access.index !21
+  %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %3, i64 1), !dbg !38
+  call void @llvm.dbg.value(metadata i32 %4, metadata !30, metadata !DIExpression()), !dbg !33
+  %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 2), !dbg !39, !llvm.preserve.access.index !21
+  %6 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %5, i64 1), !dbg !40
+  call void @llvm.dbg.value(metadata i32 %6, metadata !31, metadata !DIExpression()), !dbg !33
+  %7 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 3), !dbg !41, !llvm.preserve.access.index !21
+  %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %7, i64 1), !dbg !42
+  call void @llvm.dbg.value(metadata i32 %8, metadata !32, metadata !DIExpression()), !dbg !33
+  %add = add i32 %4, %2, !dbg !43
+  %add4 = add i32 %add, %6, !dbg !44
+  %add5 = add i32 %add4, %8, !dbg !45
+  ret i32 %add5, !dbg !46
+}
+
+; CHECK:             r1 = 4
+; CHECK:             r0 = 4
+; CHECK:             r0 += r1
+; CHECK:             r1 = 4
+; CHECK:             r0 += r1
+; CHECK:             r1 = 4
+; CHECK:             r0 += r1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_UNION(id = 2)
+; CHECK:             .ascii  "u1"                    # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=43
+; CHECK:             .ascii  "0:1:0"                 # string offset=49
+; CHECK:             .ascii  "0:1:1"                 # string offset=92
+; CHECK:             .ascii  "0:1:2"                 # string offset=98
+; CHECK:             .ascii  "0:1:3"                 # string offset=104
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   43                      # Field reloc section string offset=43
+; CHECK-NEXT:        .long   4
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   49
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   92
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   98
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   104
+; CHECK-NEXT:        .long   1
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", 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: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 32, elements: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 32)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 32, elements: !22)
+!22 = !{!23, !24, !25, !26}
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 7, flags: DIFlagBitField, extraData: i64 0)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !14, size: 4, offset: 7, flags: DIFlagBitField, extraData: i64 0)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !21, file: !1, line: 1, baseType: !14, size: 5, offset: 11, flags: DIFlagBitField, extraData: i64 0)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "a4", scope: !21, file: !1, line: 1, baseType: !14, size: 16, offset: 16, flags: DIFlagBitField, extraData: i64 0)
+!27 = !{!28, !29, !30, !31, !32}
+!28 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15)
+!29 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4)
+!30 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4)
+!31 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 7, type: !4)
+!32 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 8, type: !4)
+!33 = !DILocation(line: 0, scope: !11)
+!34 = !DILocation(line: 5, column: 52, scope: !11)
+!35 = !DILocation(line: 5, column: 55, scope: !11)
+!36 = !DILocation(line: 5, column: 17, scope: !11)
+!37 = !DILocation(line: 6, column: 55, scope: !11)
+!38 = !DILocation(line: 6, column: 17, scope: !11)
+!39 = !DILocation(line: 7, column: 55, scope: !11)
+!40 = !DILocation(line: 7, column: 17, scope: !11)
+!41 = !DILocation(line: 8, column: 55, scope: !11)
+!42 = !DILocation(line: 8, column: 17, scope: !11)
+!43 = !DILocation(line: 10, column: 13, scope: !11)
+!44 = !DILocation(line: 10, column: 18, scope: !11)
+!45 = !DILocation(line: 10, column: 23, scope: !11)
+!46 = !DILocation(line: 10, column: 3, scope: !11)
diff --git a/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-2.ll b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-2.ll
new file mode 100644 (file)
index 0000000..291d79f
--- /dev/null
@@ -0,0 +1,138 @@
+; 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:
+;   typedef struct s1 { int a1; char a2; } __s1;
+;   union u1 { int b1; __s1 b2; };
+;   enum { FIELD_BYTE_SIZE = 1, };
+;   int test(union u1 *arg) {
+;     unsigned r1 = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_SIZE);
+;     unsigned r2 = __builtin_preserve_field_info(arg->b2.a1, FIELD_BYTE_SIZE);
+;     unsigned r3 = __builtin_preserve_field_info(arg->b2.a2, FIELD_BYTE_SIZE);
+;     /* r1: 8, r2: 4, r3: 1 */
+;     return r1 + r2 + r3;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { i32, i8 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 {
+entry:
+  call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !27, metadata !DIExpression()), !dbg !31
+  %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !32, !llvm.preserve.access.index !16
+  %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !32
+  %1 = tail call i32 @llvm.bpf.preserve.field.info.p0s_struct.s1s(%struct.s1* %b2, i64 1), !dbg !33
+  call void @llvm.dbg.value(metadata i32 %1, metadata !28, metadata !DIExpression()), !dbg !31
+  %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !34, !llvm.preserve.access.index !21
+  %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %2, i64 1), !dbg !35
+  call void @llvm.dbg.value(metadata i32 %3, metadata !29, metadata !DIExpression()), !dbg !31
+  %4 = tail call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1* %b2, i32 1, i32 1), !dbg !36, !llvm.preserve.access.index !21
+  %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %4, i64 1), !dbg !37
+  call void @llvm.dbg.value(metadata i32 %5, metadata !30, metadata !DIExpression()), !dbg !31
+  %add = add i32 %3, %1, !dbg !38
+  %add3 = add i32 %add, %5, !dbg !39
+  ret i32 %add3, !dbg !40
+}
+
+; CHECK:             r1 = 8
+; CHECK:             r0 = 4
+; CHECK:             r0 += r1
+; CHECK:             r1 = 1
+; CHECK:             r0 += r1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_UNION(id = 2)
+; CHECK:             .ascii  "u1"                    # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=42
+; CHECK:             .ascii  "0:1"                   # string offset=48
+; CHECK:             .ascii  "0:1:0"                 # string offset=89
+; CHECK:             .ascii  "0:1:1"                 # string offset=95
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   42                      # Field reloc section string offset=42
+; CHECK-NEXT:        .long   3
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   48
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   89
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   95
+; CHECK-NEXT:        .long   1
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0s_struct.s1s(%struct.s1*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", 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: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 64, elements: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 64)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 64, elements: !22)
+!22 = !{!23, !24}
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 32)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !25, size: 8, offset: 32)
+!25 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!26 = !{!27, !28, !29, !30}
+!27 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15)
+!28 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4)
+!29 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4)
+!30 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 7, type: !4)
+!31 = !DILocation(line: 0, scope: !11)
+!32 = !DILocation(line: 5, column: 52, scope: !11)
+!33 = !DILocation(line: 5, column: 17, scope: !11)
+!34 = !DILocation(line: 6, column: 55, scope: !11)
+!35 = !DILocation(line: 6, column: 17, scope: !11)
+!36 = !DILocation(line: 7, column: 55, scope: !11)
+!37 = !DILocation(line: 7, column: 17, scope: !11)
+!38 = !DILocation(line: 9, column: 13, scope: !11)
+!39 = !DILocation(line: 9, column: 18, scope: !11)
+!40 = !DILocation(line: 9, column: 3, scope: !11)
diff --git a/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-3.ll b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-3.ll
new file mode 100644 (file)
index 0000000..fd517bf
--- /dev/null
@@ -0,0 +1,130 @@
+; 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:
+;   typedef struct s1 { int a1[10][10]; } __s1;
+;   union u1 { int b1; __s1 b2; };
+;   enum { FIELD_BYTE_SIZE = 1, };
+;   int test(union u1 *arg) {
+;     unsigned r1 = __builtin_preserve_field_info(arg->b2.a1[5], FIELD_BYTE_SIZE);
+;     unsigned r2 = __builtin_preserve_field_info(arg->b2.a1[5][5], FIELD_BYTE_SIZE);
+;     /* r1: 40, r2: 4 */
+;     return r1 + r2;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { [10 x [10 x i32]] }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !18 {
+entry:
+  call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !31, metadata !DIExpression()), !dbg !34
+  %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !35, !llvm.preserve.access.index !22
+  %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !35
+  %1 = tail call [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !27
+  %2 = tail call [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]* %1, i32 1, i32 5), !dbg !37, !llvm.preserve.access.index !8
+  %3 = tail call i32 @llvm.bpf.preserve.field.info.p0a10i32([10 x i32]* %2, i64 1), !dbg !38
+  call void @llvm.dbg.value(metadata i32 %3, metadata !32, metadata !DIExpression()), !dbg !34
+  %4 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]* %2, i32 1, i32 5), !dbg !39, !llvm.preserve.access.index !12
+  %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %4, i64 1), !dbg !40
+  call void @llvm.dbg.value(metadata i32 %5, metadata !33, metadata !DIExpression()), !dbg !34
+  %add = add i32 %5, %3, !dbg !41
+  ret i32 %add, !dbg !42
+}
+
+; CHECK:             r1 = 40
+; CHECK:             r0 = 4
+; CHECK:             r0 += r1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_UNION(id = 2)
+; CHECK:             .ascii  "u1"                    # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=54
+; CHECK:             .ascii  "0:1:0:5"               # string offset=60
+; CHECK:             .ascii  "0:1:0:5:5"             # string offset=105
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   54                      # Field reloc section string offset=54
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   60
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   105
+; CHECK-NEXT:        .long   1
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0a10i32([10 x i32]*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!14, !15, !16}
+!llvm.ident = !{!17}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !7, 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: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true)
+!7 = !{!8, !12}
+!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 3200, elements: !10)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !{!11, !11}
+!11 = !DISubrange(count: 10)
+!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 320, elements: !13)
+!13 = !{!11}
+!14 = !{i32 2, !"Dwarf Version", i32 4}
+!15 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !{i32 1, !"wchar_size", i32 4}
+!17 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)"}
+!18 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !19, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !30)
+!19 = !DISubroutineType(types: !20)
+!20 = !{!9, !21}
+!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64)
+!22 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 3200, elements: !23)
+!23 = !{!24, !25}
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !22, file: !1, line: 2, baseType: !9, size: 32)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !22, file: !1, line: 2, baseType: !26, size: 3200)
+!26 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !27)
+!27 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 3200, elements: !28)
+!28 = !{!29}
+!29 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !27, file: !1, line: 1, baseType: !8, size: 3200)
+!30 = !{!31, !32, !33}
+!31 = !DILocalVariable(name: "arg", arg: 1, scope: !18, file: !1, line: 4, type: !21)
+!32 = !DILocalVariable(name: "r1", scope: !18, file: !1, line: 5, type: !4)
+!33 = !DILocalVariable(name: "r2", scope: !18, file: !1, line: 6, type: !4)
+!34 = !DILocation(line: 0, scope: !18)
+!35 = !DILocation(line: 5, column: 52, scope: !18)
+!36 = !DILocation(line: 5, column: 55, scope: !18)
+!37 = !DILocation(line: 5, column: 47, scope: !18)
+!38 = !DILocation(line: 5, column: 17, scope: !18)
+!39 = !DILocation(line: 6, column: 47, scope: !18)
+!40 = !DILocation(line: 6, column: 17, scope: !18)
+!41 = !DILocation(line: 8, column: 13, scope: !18)
+!42 = !DILocation(line: 8, column: 3, scope: !18)
diff --git a/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-1.ll b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-1.ll
new file mode 100644 (file)
index 0000000..f140dcb
--- /dev/null
@@ -0,0 +1,162 @@
+; 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:
+;   typedef unsigned __uint;
+;   struct s1 { int a1; __uint a2:9; __uint a3:4; };
+;   union u1 { int b1; __uint b2:9; __uint b3:4; };
+;   enum { FIELD_EXISTENCE = 2, };
+;   int test(struct s1 *arg1, union u1 *arg2) {
+;     unsigned r1 = __builtin_preserve_field_info(arg1->a1, FIELD_EXISTENCE);
+;     unsigned r2 = __builtin_preserve_field_info(arg1->a3, FIELD_EXISTENCE);
+;     unsigned r3 = __builtin_preserve_field_info(arg2->b1, FIELD_EXISTENCE);
+;     unsigned r4 = __builtin_preserve_field_info(arg2->b3, FIELD_EXISTENCE);
+;     return r1 + r2 + r3 + r4;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.s1 = type { i32, i16 }
+%union.u1 = type { i32 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%struct.s1* %arg1, %union.u1* %arg2) local_unnamed_addr #0 !dbg !11 {
+entry:
+  call void @llvm.dbg.value(metadata %struct.s1* %arg1, metadata !29, metadata !DIExpression()), !dbg !35
+  call void @llvm.dbg.value(metadata %union.u1* %arg2, metadata !30, metadata !DIExpression()), !dbg !35
+  %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %arg1, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !16
+  %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %0, i64 2), !dbg !37
+  call void @llvm.dbg.value(metadata i32 %1, metadata !31, metadata !DIExpression()), !dbg !35
+  %2 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* %arg1, i32 1, i32 2), !dbg !38, !llvm.preserve.access.index !16
+  %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %2, i64 2), !dbg !39
+  call void @llvm.dbg.value(metadata i32 %3, metadata !32, metadata !DIExpression()), !dbg !35
+  %4 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg2, i32 0), !dbg !40, !llvm.preserve.access.index !23
+  %b1 = getelementptr inbounds %union.u1, %union.u1* %4, i64 0, i32 0, !dbg !40
+  %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %b1, i64 2), !dbg !41
+  call void @llvm.dbg.value(metadata i32 %5, metadata !33, metadata !DIExpression()), !dbg !35
+  %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_union.u1s(%union.u1* %arg2, i32 0, i32 2), !dbg !42, !llvm.preserve.access.index !23
+  %7 = bitcast i32* %6 to i8*, !dbg !42
+  %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %7, i64 2), !dbg !43
+  call void @llvm.dbg.value(metadata i32 %8, metadata !34, metadata !DIExpression()), !dbg !35
+  %add = add i32 %3, %1, !dbg !44
+  %add1 = add i32 %add, %5, !dbg !45
+  %add2 = add i32 %add1, %8, !dbg !46
+  ret i32 %add2, !dbg !47
+}
+
+; CHECK:             r1 = 1
+; CHECK:             r0 = 1
+; CHECK:             r0 += r1
+; CHECK:             r1 = 1
+; CHECK:             r0 += r1
+; CHECK:             r1 = 1
+; CHECK:             r0 += r1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_STRUCT(id = 2)
+; CHECK:             .long   37                      # BTF_KIND_UNION(id = 7)
+; CHECK:             .ascii  "s1"                    # string offset=1
+; CHECK:             .ascii  "u1"                    # string offset=37
+; CHECK:             .ascii  ".text"                 # string offset=64
+; CHECK:             .ascii  "0:0"                   # string offset=70
+; CHECK:             .ascii  "0:2"                   # string offset=111
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   64                      # Field reloc section string offset=64
+; CHECK-NEXT:        .long   4
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   70
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   111
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   7
+; CHECK-NEXT:        .long   70
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   7
+; CHECK-NEXT:        .long   111
+; CHECK-NEXT:        .long   2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_union.u1s(%union.u1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", 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: 4, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !12, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !28)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15, !22}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 2, size: 64, elements: !17)
+!17 = !{!18, !19, !21}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !16, file: !1, line: 2, baseType: !20, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint", file: !1, line: 1, baseType: !4)
+!21 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !16, file: !1, line: 2, baseType: !20, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32)
+!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64)
+!23 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 3, size: 32, elements: !24)
+!24 = !{!25, !26, !27}
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !23, file: !1, line: 3, baseType: !14, size: 32)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !23, file: !1, line: 3, baseType: !20, size: 9, flags: DIFlagBitField, extraData: i64 0)
+!27 = !DIDerivedType(tag: DW_TAG_member, name: "b3", scope: !23, file: !1, line: 3, baseType: !20, size: 4, flags: DIFlagBitField, extraData: i64 0)
+!28 = !{!29, !30, !31, !32, !33, !34}
+!29 = !DILocalVariable(name: "arg1", arg: 1, scope: !11, file: !1, line: 5, type: !15)
+!30 = !DILocalVariable(name: "arg2", arg: 2, scope: !11, file: !1, line: 5, type: !22)
+!31 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 6, type: !4)
+!32 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 7, type: !4)
+!33 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 8, type: !4)
+!34 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 9, type: !4)
+!35 = !DILocation(line: 0, scope: !11)
+!36 = !DILocation(line: 6, column: 53, scope: !11)
+!37 = !DILocation(line: 6, column: 17, scope: !11)
+!38 = !DILocation(line: 7, column: 53, scope: !11)
+!39 = !DILocation(line: 7, column: 17, scope: !11)
+!40 = !DILocation(line: 8, column: 53, scope: !11)
+!41 = !DILocation(line: 8, column: 17, scope: !11)
+!42 = !DILocation(line: 9, column: 53, scope: !11)
+!43 = !DILocation(line: 9, column: 17, scope: !11)
+!44 = !DILocation(line: 10, column: 13, scope: !11)
+!45 = !DILocation(line: 10, column: 18, scope: !11)
+!46 = !DILocation(line: 10, column: 23, scope: !11)
+!47 = !DILocation(line: 10, column: 3, scope: !11)
diff --git a/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-2.ll b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-2.ll
new file mode 100644 (file)
index 0000000..186af86
--- /dev/null
@@ -0,0 +1,121 @@
+; 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:
+;   typedef unsigned __uint;
+;   struct s1 { int a1; __uint a2:9; __uint a3:4; };
+;   union u1 { int b1; struct s1 b2; };
+;   enum { FIELD_EXISTENCE = 2, };
+;   int test(union u1 *arg) {
+;     unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_EXISTENCE);
+;     unsigned r2 = __builtin_preserve_field_info(arg->b2.a3, FIELD_EXISTENCE);
+;     return r1 + r2;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { i32, i16 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 {
+entry:
+  call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !27, metadata !DIExpression()), !dbg !30
+  %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !31, !llvm.preserve.access.index !16
+  %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !31
+  %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !32, !llvm.preserve.access.index !20
+  %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 2), !dbg !33
+  call void @llvm.dbg.value(metadata i32 %2, metadata !28, metadata !DIExpression()), !dbg !30
+  %3 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* %b2, i32 1, i32 2), !dbg !34, !llvm.preserve.access.index !20
+  %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %3, i64 2), !dbg !35
+  call void @llvm.dbg.value(metadata i32 %4, metadata !29, metadata !DIExpression()), !dbg !30
+  %add = add i32 %4, %2, !dbg !36
+  ret i32 %add, !dbg !37
+}
+
+; CHECK:             r1 = 1
+; CHECK:             r0 = 1
+; CHECK:             r0 += r1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_UNION(id = 2)
+; CHECK:             .ascii  "u1"                    # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=55
+; CHECK:             .ascii  "0:1:0"                 # string offset=61
+; CHECK:             .ascii  "0:1:2"                 # string offset=104
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   55                      # Field reloc section string offset=55
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   61
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   104
+; CHECK-NEXT:        .long   2
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", 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: 4, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !12, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 3, size: 64, elements: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 3, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 3, baseType: !20, size: 64)
+!20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 2, size: 64, elements: !21)
+!21 = !{!22, !23, !25}
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !20, file: !1, line: 2, baseType: !14, size: 32)
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !20, file: !1, line: 2, baseType: !24, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+!24 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint", file: !1, line: 1, baseType: !4)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !20, file: !1, line: 2, baseType: !24, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32)
+!26 = !{!27, !28, !29}
+!27 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 5, type: !15)
+!28 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 6, type: !4)
+!29 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 7, type: !4)
+!30 = !DILocation(line: 0, scope: !11)
+!31 = !DILocation(line: 6, column: 52, scope: !11)
+!32 = !DILocation(line: 6, column: 55, scope: !11)
+!33 = !DILocation(line: 6, column: 17, scope: !11)
+!34 = !DILocation(line: 7, column: 55, scope: !11)
+!35 = !DILocation(line: 7, column: 17, scope: !11)
+!36 = !DILocation(line: 8, column: 13, scope: !11)
+!37 = !DILocation(line: 8, column: 3, scope: !11)
diff --git a/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-3.ll b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-3.ll
new file mode 100644 (file)
index 0000000..4c0a93a
--- /dev/null
@@ -0,0 +1,129 @@
+; 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:
+;   typedef struct s1 { int a1[10][10]; } __s1;
+;   union u1 { int b1; __s1 b2; };
+;   enum { FIELD_EXISTENCE = 2, };
+;   int test(union u1 *arg) {
+;     unsigned r1 = __builtin_preserve_field_info(arg->b2.a1[5], FIELD_EXISTENCE);
+;     unsigned r2 = __builtin_preserve_field_info(arg->b2.a1[5][5], FIELD_EXISTENCE);
+;     return r1 + r2;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { [10 x [10 x i32]] }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !18 {
+entry:
+  call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !31, metadata !DIExpression()), !dbg !34
+  %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !35, !llvm.preserve.access.index !22
+  %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !35
+  %1 = tail call [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !27
+  %2 = tail call [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]* %1, i32 1, i32 5), !dbg !37, !llvm.preserve.access.index !8
+  %3 = tail call i32 @llvm.bpf.preserve.field.info.p0a10i32([10 x i32]* %2, i64 2), !dbg !38
+  call void @llvm.dbg.value(metadata i32 %3, metadata !32, metadata !DIExpression()), !dbg !34
+  %4 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]* %2, i32 1, i32 5), !dbg !39, !llvm.preserve.access.index !12
+  %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %4, i64 2), !dbg !40
+  call void @llvm.dbg.value(metadata i32 %5, metadata !33, metadata !DIExpression()), !dbg !34
+  %add = add i32 %5, %3, !dbg !41
+  ret i32 %add, !dbg !42
+}
+
+; CHECK:             r1 = 1
+; CHECK:             r0 = 1
+; CHECK:             r0 += r1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_UNION(id = 2)
+; CHECK:             .ascii  "u1"                    # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=54
+; CHECK:             .ascii  "0:1:0:5"               # string offset=60
+; CHECK:             .ascii  "0:1:0:5:5"             # string offset=105
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   54                      # Field reloc section string offset=54
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   60
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   105
+; CHECK-NEXT:        .long   2
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0a10i32([10 x i32]*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!14, !15, !16}
+!llvm.ident = !{!17}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !7, 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: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true)
+!7 = !{!8, !12}
+!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 3200, elements: !10)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !{!11, !11}
+!11 = !DISubrange(count: 10)
+!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 320, elements: !13)
+!13 = !{!11}
+!14 = !{i32 2, !"Dwarf Version", i32 4}
+!15 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !{i32 1, !"wchar_size", i32 4}
+!17 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)"}
+!18 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !19, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !30)
+!19 = !DISubroutineType(types: !20)
+!20 = !{!9, !21}
+!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64)
+!22 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 3200, elements: !23)
+!23 = !{!24, !25}
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !22, file: !1, line: 2, baseType: !9, size: 32)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !22, file: !1, line: 2, baseType: !26, size: 3200)
+!26 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !27)
+!27 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 3200, elements: !28)
+!28 = !{!29}
+!29 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !27, file: !1, line: 1, baseType: !8, size: 3200)
+!30 = !{!31, !32, !33}
+!31 = !DILocalVariable(name: "arg", arg: 1, scope: !18, file: !1, line: 4, type: !21)
+!32 = !DILocalVariable(name: "r1", scope: !18, file: !1, line: 5, type: !4)
+!33 = !DILocalVariable(name: "r2", scope: !18, file: !1, line: 6, type: !4)
+!34 = !DILocation(line: 0, scope: !18)
+!35 = !DILocation(line: 5, column: 52, scope: !18)
+!36 = !DILocation(line: 5, column: 55, scope: !18)
+!37 = !DILocation(line: 5, column: 47, scope: !18)
+!38 = !DILocation(line: 5, column: 17, scope: !18)
+!39 = !DILocation(line: 6, column: 47, scope: !18)
+!40 = !DILocation(line: 6, column: 17, scope: !18)
+!41 = !DILocation(line: 7, column: 13, scope: !18)
+!42 = !DILocation(line: 7, column: 3, scope: !18)
diff --git a/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-1.ll b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-1.ll
new file mode 100644 (file)
index 0000000..ce4074c
--- /dev/null
@@ -0,0 +1,153 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EL %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EB %s
+; Source code:
+;   typedef struct s1 { int a1:7; int a2:4; int a3:5; int a4:16;} __s1;
+;   union u1 { int b1; __s1 b2; };
+;   enum { FIELD_LSHIFT_U64 = 4, };
+;   int test(union u1 *arg) {
+;     unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_LSHIFT_U64);
+;     unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_LSHIFT_U64);
+;     unsigned r3 = __builtin_preserve_field_info(arg->b2.a3, FIELD_LSHIFT_U64);
+;     unsigned r4 = __builtin_preserve_field_info(arg->b2.a4, FIELD_LSHIFT_U64);
+;     /* big endian:    r1: 32, r2: 39, r3: 43, r4: 48 */
+;     /* little endian: r1: 57, r2: 53, r3: 48, r4: 32 */
+;     return r1 + r2 + r3 + r4;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { i32 }
+%struct.s1 = type { i32 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 {
+entry:
+  call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !28, metadata !DIExpression()), !dbg !33
+  %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !34, !llvm.preserve.access.index !16
+  %b2 = bitcast %union.u1* %0 to %struct.s1*, !dbg !34
+  %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !21
+  %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 4), !dbg !36
+  call void @llvm.dbg.value(metadata i32 %2, metadata !29, metadata !DIExpression()), !dbg !33
+  %3 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 1), !dbg !37, !llvm.preserve.access.index !21
+  %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %3, i64 4), !dbg !38
+  call void @llvm.dbg.value(metadata i32 %4, metadata !30, metadata !DIExpression()), !dbg !33
+  %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 2), !dbg !39, !llvm.preserve.access.index !21
+  %6 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %5, i64 4), !dbg !40
+  call void @llvm.dbg.value(metadata i32 %6, metadata !31, metadata !DIExpression()), !dbg !33
+  %7 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 3), !dbg !41, !llvm.preserve.access.index !21
+  %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %7, i64 4), !dbg !42
+  call void @llvm.dbg.value(metadata i32 %8, metadata !32, metadata !DIExpression()), !dbg !33
+  %add = add i32 %4, %2, !dbg !43
+  %add4 = add i32 %add, %6, !dbg !44
+  %add5 = add i32 %add4, %8, !dbg !45
+  ret i32 %add5, !dbg !46
+}
+
+; CHECK-EL:          r1 = 57
+; CHECK-EL:          r0 = 53
+; CHECK-EB:          r1 = 32
+; CHECK-EB:          r0 = 39
+; CHECK:             r0 += r1
+; CHECK-EL:          r1 = 48
+; CHECK-EB:          r1 = 43
+; CHECK:             r0 += r1
+; CHECK-EL:          r1 = 32
+; CHECK-EB:          r1 = 48
+; CHECK:             r0 += r1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_UNION(id = 2)
+; CHECK:             .ascii  "u1"                    # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=43
+; CHECK:             .ascii  "0:1:0"                 # string offset=49
+; CHECK:             .ascii  "0:1:1"                 # string offset=92
+; CHECK:             .ascii  "0:1:2"                 # string offset=98
+; CHECK:             .ascii  "0:1:3"                 # string offset=104
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   43                      # Field reloc section string offset=43
+; CHECK-NEXT:        .long   4
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   49
+; CHECK-NEXT:        .long   4
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   92
+; CHECK-NEXT:        .long   4
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   98
+; CHECK-NEXT:        .long   4
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   104
+; CHECK-NEXT:        .long   4
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 5635073377f153f7f2ff9b34c77af3c79885ff4a)", 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: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_LSHIFT_U64", value: 4, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 5635073377f153f7f2ff9b34c77af3c79885ff4a)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 32, elements: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 32)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 32, elements: !22)
+!22 = !{!23, !24, !25, !26}
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 7, flags: DIFlagBitField, extraData: i64 0)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !14, size: 4, offset: 7, flags: DIFlagBitField, extraData: i64 0)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !21, file: !1, line: 1, baseType: !14, size: 5, offset: 11, flags: DIFlagBitField, extraData: i64 0)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "a4", scope: !21, file: !1, line: 1, baseType: !14, size: 16, offset: 16, flags: DIFlagBitField, extraData: i64 0)
+!27 = !{!28, !29, !30, !31, !32}
+!28 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15)
+!29 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4)
+!30 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4)
+!31 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 7, type: !4)
+!32 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 8, type: !4)
+!33 = !DILocation(line: 0, scope: !11)
+!34 = !DILocation(line: 5, column: 52, scope: !11)
+!35 = !DILocation(line: 5, column: 55, scope: !11)
+!36 = !DILocation(line: 5, column: 17, scope: !11)
+!37 = !DILocation(line: 6, column: 55, scope: !11)
+!38 = !DILocation(line: 6, column: 17, scope: !11)
+!39 = !DILocation(line: 7, column: 55, scope: !11)
+!40 = !DILocation(line: 7, column: 17, scope: !11)
+!41 = !DILocation(line: 8, column: 55, scope: !11)
+!42 = !DILocation(line: 8, column: 17, scope: !11)
+!43 = !DILocation(line: 11, column: 13, scope: !11)
+!44 = !DILocation(line: 11, column: 18, scope: !11)
+!45 = !DILocation(line: 11, column: 23, scope: !11)
+!46 = !DILocation(line: 11, column: 3, scope: !11)
diff --git a/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-2.ll b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-2.ll
new file mode 100644 (file)
index 0000000..83d1b3e
--- /dev/null
@@ -0,0 +1,122 @@
+; 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:
+;   typedef struct s1 { int a1; short a2; } __s1;
+;   union u1 { int b1; __s1 b2; };
+;   enum { FIELD_LSHIFT_U64 = 4, };
+;   int test(union u1 *arg) {
+;     unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_LSHIFT_U64);
+;     unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_LSHIFT_U64);
+;     /* big endian:    r1: 32, r2: 48 */
+;     /* little endian: r1: 32, r2: 48 */
+;     return r1 + r2;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { i32, i16 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 {
+entry:
+  call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !27, metadata !DIExpression()), !dbg !30
+  %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !31, !llvm.preserve.access.index !16
+  %b2 = getelementptr %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !31
+  %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !32, !llvm.preserve.access.index !21
+  %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 4), !dbg !33
+  call void @llvm.dbg.value(metadata i32 %2, metadata !28, metadata !DIExpression()), !dbg !30
+  %3 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* %b2, i32 1, i32 1), !dbg !34, !llvm.preserve.access.index !21
+  %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %3, i64 4), !dbg !35
+  call void @llvm.dbg.value(metadata i32 %4, metadata !29, metadata !DIExpression()), !dbg !30
+  %add = add i32 %4, %2, !dbg !36
+  ret i32 %add, !dbg !37
+}
+
+; CHECK:             r1 = 32
+; CHECK:             r0 = 48
+; CHECK:             r0 += r1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_UNION(id = 2)
+; CHECK:             .ascii  "u1"                    # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=43
+; CHECK:             .ascii  "0:1:0"                 # string offset=49
+; CHECK:             .ascii  "0:1:1"                 # string offset=92
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   43                      # Field reloc section string offset=43
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   49
+; CHECK-NEXT:        .long   4
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   92
+; CHECK-NEXT:        .long   4
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 5635073377f153f7f2ff9b34c77af3c79885ff4a)", 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: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_LSHIFT_U64", value: 4, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 5635073377f153f7f2ff9b34c77af3c79885ff4a)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 64, elements: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 64)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 64, elements: !22)
+!22 = !{!23, !24}
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 32)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !25, size: 16, offset: 32)
+!25 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed)
+!26 = !{!27, !28, !29}
+!27 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15)
+!28 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4)
+!29 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4)
+!30 = !DILocation(line: 0, scope: !11)
+!31 = !DILocation(line: 5, column: 52, scope: !11)
+!32 = !DILocation(line: 5, column: 55, scope: !11)
+!33 = !DILocation(line: 5, column: 17, scope: !11)
+!34 = !DILocation(line: 6, column: 55, scope: !11)
+!35 = !DILocation(line: 6, column: 17, scope: !11)
+!36 = !DILocation(line: 9, column: 13, scope: !11)
+!37 = !DILocation(line: 9, column: 3, scope: !11)
diff --git a/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-1.ll b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-1.ll
new file mode 100644 (file)
index 0000000..70791d3
--- /dev/null
@@ -0,0 +1,148 @@
+; 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:
+;   typedef struct s1 { int a1:7; int a2:4; int a3:5; int a4:16;} __s1;
+;   union u1 { int b1; __s1 b2; };
+;   enum { FIELD_RSHIFT_U64 = 5, };
+;   int test(union u1 *arg) {
+;     unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_RSHIFT_U64);
+;     unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_RSHIFT_U64);
+;     unsigned r3 = __builtin_preserve_field_info(arg->b2.a3, FIELD_RSHIFT_U64);
+;     unsigned r4 = __builtin_preserve_field_info(arg->b2.a4, FIELD_RSHIFT_U64);
+;     /* r1: 57, r2: 60, r3: 59, r4: 48 */
+;     return r1 + r2 + r3 + r4;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { i32 }
+%struct.s1 = type { i32 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 {
+entry:
+  call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !28, metadata !DIExpression()), !dbg !33
+  %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !34, !llvm.preserve.access.index !16
+  %b2 = bitcast %union.u1* %0 to %struct.s1*, !dbg !34
+  %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !21
+  %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 5), !dbg !36
+  call void @llvm.dbg.value(metadata i32 %2, metadata !29, metadata !DIExpression()), !dbg !33
+  %3 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 1), !dbg !37, !llvm.preserve.access.index !21
+  %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %3, i64 5), !dbg !38
+  call void @llvm.dbg.value(metadata i32 %4, metadata !30, metadata !DIExpression()), !dbg !33
+  %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 2), !dbg !39, !llvm.preserve.access.index !21
+  %6 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %5, i64 5), !dbg !40
+  call void @llvm.dbg.value(metadata i32 %6, metadata !31, metadata !DIExpression()), !dbg !33
+  %7 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 3), !dbg !41, !llvm.preserve.access.index !21
+  %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %7, i64 5), !dbg !42
+  call void @llvm.dbg.value(metadata i32 %8, metadata !32, metadata !DIExpression()), !dbg !33
+  %add = add i32 %4, %2, !dbg !43
+  %add4 = add i32 %add, %6, !dbg !44
+  %add5 = add i32 %add4, %8, !dbg !45
+  ret i32 %add5, !dbg !46
+}
+
+; CHECK:             r1 = 57
+; CHECK:             r0 = 60
+; CHECK:             r0 += r1
+; CHECK:             r1 = 59
+; CHECK:             r0 += r1
+; CHECK:             r1 = 48
+; CHECK:             r0 += r1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_UNION(id = 2)
+; CHECK:             .ascii  "u1"                    # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=43
+; CHECK:             .ascii  "0:1:0"                 # string offset=49
+; CHECK:             .ascii  "0:1:1"                 # string offset=92
+; CHECK:             .ascii  "0:1:2"                 # string offset=98
+; CHECK:             .ascii  "0:1:3"                 # string offset=104
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   43                      # Field reloc section string offset=43
+; CHECK-NEXT:        .long   4
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   49
+; CHECK-NEXT:        .long   5
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   92
+; CHECK-NEXT:        .long   5
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   98
+; CHECK-NEXT:        .long   5
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   104
+; CHECK-NEXT:        .long   5
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", 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: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 32, elements: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 32)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 32, elements: !22)
+!22 = !{!23, !24, !25, !26}
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 7, flags: DIFlagBitField, extraData: i64 0)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !14, size: 4, offset: 7, flags: DIFlagBitField, extraData: i64 0)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !21, file: !1, line: 1, baseType: !14, size: 5, offset: 11, flags: DIFlagBitField, extraData: i64 0)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "a4", scope: !21, file: !1, line: 1, baseType: !14, size: 16, offset: 16, flags: DIFlagBitField, extraData: i64 0)
+!27 = !{!28, !29, !30, !31, !32}
+!28 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15)
+!29 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4)
+!30 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4)
+!31 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 7, type: !4)
+!32 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 8, type: !4)
+!33 = !DILocation(line: 0, scope: !11)
+!34 = !DILocation(line: 5, column: 52, scope: !11)
+!35 = !DILocation(line: 5, column: 55, scope: !11)
+!36 = !DILocation(line: 5, column: 17, scope: !11)
+!37 = !DILocation(line: 6, column: 55, scope: !11)
+!38 = !DILocation(line: 6, column: 17, scope: !11)
+!39 = !DILocation(line: 7, column: 55, scope: !11)
+!40 = !DILocation(line: 7, column: 17, scope: !11)
+!41 = !DILocation(line: 8, column: 55, scope: !11)
+!42 = !DILocation(line: 8, column: 17, scope: !11)
+!43 = !DILocation(line: 10, column: 13, scope: !11)
+!44 = !DILocation(line: 10, column: 18, scope: !11)
+!45 = !DILocation(line: 10, column: 23, scope: !11)
+!46 = !DILocation(line: 10, column: 3, scope: !11)
diff --git a/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-2.ll b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-2.ll
new file mode 100644 (file)
index 0000000..657b19c
--- /dev/null
@@ -0,0 +1,121 @@
+; 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:
+;   typedef struct s1 { int a1; char a2; } __s1;
+;   union u1 { int b1; __s1 b2; };
+;   enum { FIELD_RSHIFT_U64 = 5, };
+;   int test(union u1 *arg) {
+;     unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_RSHIFT_U64);
+;     unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_RSHIFT_U64);
+;     /* r1: 32, r2: 56 */
+;     return r1 + r2;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { i32, i8 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 {
+entry:
+  call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !27, metadata !DIExpression()), !dbg !30
+  %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !31, !llvm.preserve.access.index !16
+  %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !31
+  %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !32, !llvm.preserve.access.index !21
+  %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 5), !dbg !33
+  call void @llvm.dbg.value(metadata i32 %2, metadata !28, metadata !DIExpression()), !dbg !30
+  %3 = tail call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1* %b2, i32 1, i32 1), !dbg !34, !llvm.preserve.access.index !21
+  %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %3, i64 5), !dbg !35
+  call void @llvm.dbg.value(metadata i32 %4, metadata !29, metadata !DIExpression()), !dbg !30
+  %add = add i32 %4, %2, !dbg !36
+  ret i32 %add, !dbg !37
+}
+
+; CHECK:             r1 = 32
+; CHECK:             r0 = 56
+; CHECK:             r0 += r1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_UNION(id = 2)
+; CHECK:             .ascii  "u1"                    # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=42
+; CHECK:             .ascii  "0:1:0"                 # string offset=48
+; CHECK:             .ascii  "0:1:1"                 # string offset=91
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   42                      # Field reloc section string offset=42
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   48
+; CHECK-NEXT:        .long   5
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   91
+; CHECK-NEXT:        .long   5
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", 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: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 64, elements: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 64)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 64, elements: !22)
+!22 = !{!23, !24}
+!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 32)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !25, size: 8, offset: 32)
+!25 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!26 = !{!27, !28, !29}
+!27 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15)
+!28 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4)
+!29 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4)
+!30 = !DILocation(line: 0, scope: !11)
+!31 = !DILocation(line: 5, column: 52, scope: !11)
+!32 = !DILocation(line: 5, column: 55, scope: !11)
+!33 = !DILocation(line: 5, column: 17, scope: !11)
+!34 = !DILocation(line: 6, column: 55, scope: !11)
+!35 = !DILocation(line: 6, column: 17, scope: !11)
+!36 = !DILocation(line: 8, column: 13, scope: !11)
+!37 = !DILocation(line: 8, column: 3, scope: !11)
diff --git a/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-3.ll b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-3.ll
new file mode 100644 (file)
index 0000000..2f9cf2f
--- /dev/null
@@ -0,0 +1,131 @@
+; 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:
+;   typedef struct s1 { char a1 [5][5]; } __s1;
+;   union u1 { int b1; __s1 b2; };
+;   enum { FIELD_RSHIFT_U64 = 5, };
+;   int test(union u1 *arg) {
+;     unsigned r1 = __builtin_preserve_field_info(arg->b2.a1[3], FIELD_RSHIFT_U64);
+;     unsigned r2 = __builtin_preserve_field_info(arg->b2.a1[3][3], FIELD_RSHIFT_U64);
+;     /* r1 : 24, r2 : 56 */
+;     return r1 + r2;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { i32, [24 x i8] }
+%struct.s1 = type { [5 x [5 x i8]] }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !18 {
+entry:
+  call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !32, metadata !DIExpression()), !dbg !35
+  %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !36, !llvm.preserve.access.index !23
+  %b2 = bitcast %union.u1* %0 to %struct.s1*, !dbg !36
+  %1 = tail call [5 x [5 x i8]]* @llvm.preserve.struct.access.index.p0a5a5i8.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !37, !llvm.preserve.access.index !28
+  %2 = tail call [5 x i8]* @llvm.preserve.array.access.index.p0a5i8.p0a5a5i8([5 x [5 x i8]]* %1, i32 1, i32 3), !dbg !38, !llvm.preserve.access.index !8
+  %3 = tail call i32 @llvm.bpf.preserve.field.info.p0a5i8([5 x i8]* %2, i64 5), !dbg !39
+  call void @llvm.dbg.value(metadata i32 %3, metadata !33, metadata !DIExpression()), !dbg !35
+  %4 = tail call i8* @llvm.preserve.array.access.index.p0i8.p0a5i8([5 x i8]* %2, i32 1, i32 3), !dbg !40, !llvm.preserve.access.index !12
+  %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %4, i64 5), !dbg !41
+  call void @llvm.dbg.value(metadata i32 %5, metadata !34, metadata !DIExpression()), !dbg !35
+  %add = add i32 %5, %3, !dbg !42
+  ret i32 %add, !dbg !43
+}
+
+; CHECK:             r1 = 24
+; CHECK:             r0 = 56
+; CHECK:             r0 += r1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_UNION(id = 2)
+; CHECK:             .ascii  "u1"                    # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=59
+; CHECK:             .ascii  "0:1:0:3"               # string offset=65
+; CHECK:             .ascii  "0:1:0:3:3"             # string offset=110
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   59                      # Field reloc section string offset=59
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   65
+; CHECK-NEXT:        .long   5
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   110
+; CHECK-NEXT:        .long   5
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [5 x [5 x i8]]* @llvm.preserve.struct.access.index.p0a5a5i8.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [5 x i8]* @llvm.preserve.array.access.index.p0a5i8.p0a5a5i8([5 x [5 x i8]]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0a5i8([5 x i8]*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.preserve.array.access.index.p0i8.p0a5i8([5 x i8]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!14, !15, !16}
+!llvm.ident = !{!17}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !7, 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: 3, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true)
+!7 = !{!8, !12}
+!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 200, elements: !10)
+!9 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!10 = !{!11, !11}
+!11 = !DISubrange(count: 5)
+!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 40, elements: !13)
+!13 = !{!11}
+!14 = !{i32 2, !"Dwarf Version", i32 4}
+!15 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !{i32 1, !"wchar_size", i32 4}
+!17 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)"}
+!18 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !19, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !31)
+!19 = !DISubroutineType(types: !20)
+!20 = !{!21, !22}
+!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64)
+!23 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 224, elements: !24)
+!24 = !{!25, !26}
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !23, file: !1, line: 2, baseType: !21, size: 32)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !23, file: !1, line: 2, baseType: !27, size: 200)
+!27 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !28)
+!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 200, elements: !29)
+!29 = !{!30}
+!30 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !28, file: !1, line: 1, baseType: !8, size: 200)
+!31 = !{!32, !33, !34}
+!32 = !DILocalVariable(name: "arg", arg: 1, scope: !18, file: !1, line: 4, type: !22)
+!33 = !DILocalVariable(name: "r1", scope: !18, file: !1, line: 5, type: !4)
+!34 = !DILocalVariable(name: "r2", scope: !18, file: !1, line: 6, type: !4)
+!35 = !DILocation(line: 0, scope: !18)
+!36 = !DILocation(line: 5, column: 52, scope: !18)
+!37 = !DILocation(line: 5, column: 55, scope: !18)
+!38 = !DILocation(line: 5, column: 47, scope: !18)
+!39 = !DILocation(line: 5, column: 17, scope: !18)
+!40 = !DILocation(line: 6, column: 47, scope: !18)
+!41 = !DILocation(line: 6, column: 17, scope: !18)
+!42 = !DILocation(line: 8, column: 13, scope: !18)
+!43 = !DILocation(line: 8, column: 3, scope: !18)
diff --git a/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-1.ll b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-1.ll
new file mode 100644 (file)
index 0000000..f5605cb
--- /dev/null
@@ -0,0 +1,162 @@
+; 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:
+;   typedef unsigned __uint;
+;   struct s1 { int a1; __uint a2:9; __uint a3:4; };
+;   union u1 { int b1; __uint b2:9; __uint b3:4; };
+;   enum { FIELD_SIGNEDNESS = 3, };
+;   int test(struct s1 *arg1, union u1 *arg2) {
+;     unsigned r1 = __builtin_preserve_field_info(arg1->a1, FIELD_SIGNEDNESS);
+;     unsigned r2 = __builtin_preserve_field_info(arg1->a3, FIELD_SIGNEDNESS);
+;     unsigned r3 = __builtin_preserve_field_info(arg2->b1, FIELD_SIGNEDNESS);
+;     unsigned r4 = __builtin_preserve_field_info(arg2->b3, FIELD_SIGNEDNESS);
+;     return r1 + r2 + r3 + r4;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.s1 = type { i32, i16 }
+%union.u1 = type { i32 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%struct.s1* %arg1, %union.u1* %arg2) local_unnamed_addr #0 !dbg !11 {
+entry:
+  call void @llvm.dbg.value(metadata %struct.s1* %arg1, metadata !29, metadata !DIExpression()), !dbg !35
+  call void @llvm.dbg.value(metadata %union.u1* %arg2, metadata !30, metadata !DIExpression()), !dbg !35
+  %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %arg1, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !16
+  %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %0, i64 3), !dbg !37
+  call void @llvm.dbg.value(metadata i32 %1, metadata !31, metadata !DIExpression()), !dbg !35
+  %2 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* %arg1, i32 1, i32 2), !dbg !38, !llvm.preserve.access.index !16
+  %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %2, i64 3), !dbg !39
+  call void @llvm.dbg.value(metadata i32 %3, metadata !32, metadata !DIExpression()), !dbg !35
+  %4 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg2, i32 0), !dbg !40, !llvm.preserve.access.index !23
+  %b1 = getelementptr inbounds %union.u1, %union.u1* %4, i64 0, i32 0, !dbg !40
+  %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %b1, i64 3), !dbg !41
+  call void @llvm.dbg.value(metadata i32 %5, metadata !33, metadata !DIExpression()), !dbg !35
+  %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_union.u1s(%union.u1* %arg2, i32 0, i32 2), !dbg !42, !llvm.preserve.access.index !23
+  %7 = bitcast i32* %6 to i8*, !dbg !42
+  %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %7, i64 3), !dbg !43
+  call void @llvm.dbg.value(metadata i32 %8, metadata !34, metadata !DIExpression()), !dbg !35
+  %add = add i32 %3, %1, !dbg !44
+  %add1 = add i32 %add, %5, !dbg !45
+  %add2 = add i32 %add1, %8, !dbg !46
+  ret i32 %add2, !dbg !47
+}
+
+; CHECK:             r1 = 1
+; CHECK:             r0 = 0
+; CHECK:             r0 += r1
+; CHECK:             r1 = 1
+; CHECK:             r0 += r1
+; CHECK:             r1 = 0
+; CHECK:             r0 += r1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_STRUCT(id = 2)
+; CHECK:             .long   37                      # BTF_KIND_UNION(id = 7)
+; CHECK:             .ascii  "s1"                    # string offset=1
+; CHECK:             .ascii  "u1"                    # string offset=37
+; CHECK:             .ascii  ".text"                 # string offset=64
+; CHECK:             .ascii  "0:0"                   # string offset=70
+; CHECK:             .ascii  "0:2"                   # string offset=111
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   64                      # Field reloc section string offset=64
+; CHECK-NEXT:        .long   4
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   70
+; CHECK-NEXT:        .long   3
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   111
+; CHECK-NEXT:        .long   3
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   7
+; CHECK-NEXT:        .long   70
+; CHECK-NEXT:        .long   3
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   7
+; CHECK-NEXT:        .long   111
+; CHECK-NEXT:        .long   3
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_union.u1s(%union.u1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", 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: 4, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6}
+!6 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !12, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !28)
+!12 = !DISubroutineType(types: !13)
+!13 = !{!14, !15, !22}
+!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 2, size: 64, elements: !17)
+!17 = !{!18, !19, !21}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !16, file: !1, line: 2, baseType: !14, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !16, file: !1, line: 2, baseType: !20, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint", file: !1, line: 1, baseType: !4)
+!21 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !16, file: !1, line: 2, baseType: !20, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32)
+!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64)
+!23 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 3, size: 32, elements: !24)
+!24 = !{!25, !26, !27}
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !23, file: !1, line: 3, baseType: !14, size: 32)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !23, file: !1, line: 3, baseType: !20, size: 9, flags: DIFlagBitField, extraData: i64 0)
+!27 = !DIDerivedType(tag: DW_TAG_member, name: "b3", scope: !23, file: !1, line: 3, baseType: !20, size: 4, flags: DIFlagBitField, extraData: i64 0)
+!28 = !{!29, !30, !31, !32, !33, !34}
+!29 = !DILocalVariable(name: "arg1", arg: 1, scope: !11, file: !1, line: 5, type: !15)
+!30 = !DILocalVariable(name: "arg2", arg: 2, scope: !11, file: !1, line: 5, type: !22)
+!31 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 6, type: !4)
+!32 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 7, type: !4)
+!33 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 8, type: !4)
+!34 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 9, type: !4)
+!35 = !DILocation(line: 0, scope: !11)
+!36 = !DILocation(line: 6, column: 53, scope: !11)
+!37 = !DILocation(line: 6, column: 17, scope: !11)
+!38 = !DILocation(line: 7, column: 53, scope: !11)
+!39 = !DILocation(line: 7, column: 17, scope: !11)
+!40 = !DILocation(line: 8, column: 53, scope: !11)
+!41 = !DILocation(line: 8, column: 17, scope: !11)
+!42 = !DILocation(line: 9, column: 53, scope: !11)
+!43 = !DILocation(line: 9, column: 17, scope: !11)
+!44 = !DILocation(line: 10, column: 13, scope: !11)
+!45 = !DILocation(line: 10, column: 18, scope: !11)
+!46 = !DILocation(line: 10, column: 23, scope: !11)
+!47 = !DILocation(line: 10, column: 3, scope: !11)
diff --git a/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-2.ll b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-2.ll
new file mode 100644 (file)
index 0000000..cec9790
--- /dev/null
@@ -0,0 +1,151 @@
+; 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:
+;   enum A { AA = -1, AB = 0, }; /* signed */
+;   enum B { BA = 0, BB = 1, };  /* unsigned */
+;   typedef enum A __A;
+;   typedef enum B __B;
+;   typedef int __int;           /* signed */
+;   struct s1 { __A a1; __B a2:9; __int a3:4; };
+;   union u1 { int b1; struct s1 b2; };
+;   enum { FIELD_SIGNEDNESS = 3, };
+;   int test(union u1 *arg) {
+;     unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_SIGNEDNESS);
+;     unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_SIGNEDNESS);
+;     unsigned r3 = __builtin_preserve_field_info(arg->b2.a3, FIELD_SIGNEDNESS);
+;     return r1 + r2 + r3;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { i32, i16 }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !20 {
+entry:
+  call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !37, metadata !DIExpression()), !dbg !41
+  %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !42, !llvm.preserve.access.index !24
+  %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !42
+  %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !43, !llvm.preserve.access.index !28
+  %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 3), !dbg !44
+  call void @llvm.dbg.value(metadata i32 %2, metadata !38, metadata !DIExpression()), !dbg !41
+  %3 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* %b2, i32 1, i32 1), !dbg !45, !llvm.preserve.access.index !28
+  %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %3, i64 3), !dbg !46
+  call void @llvm.dbg.value(metadata i32 %4, metadata !39, metadata !DIExpression()), !dbg !41
+  %5 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* %b2, i32 1, i32 2), !dbg !47, !llvm.preserve.access.index !28
+  %6 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %5, i64 3), !dbg !48
+  call void @llvm.dbg.value(metadata i32 %6, metadata !40, metadata !DIExpression()), !dbg !41
+  %add = add i32 %4, %2, !dbg !49
+  %add3 = add i32 %add, %6, !dbg !50
+  ret i32 %add3, !dbg !51
+}
+
+; CHECK:             r1 = 1
+; CHECK:             r0 = 0
+; CHECK:             r0 += r1
+; CHECK:             r1 = 1
+; CHECK:             r0 += r1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_UNION(id = 2)
+; CHECK:             .ascii  "u1"                    # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=65
+; CHECK:             .ascii  "0:1:0"                 # string offset=71
+; CHECK:             .ascii  "0:1:1"                 # string offset=114
+; CHECK:             .ascii  "0:1:2"                 # string offset=120
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   65                      # Field reloc section string offset=65
+; CHECK-NEXT:        .long   3
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   71
+; CHECK-NEXT:        .long   3
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   114
+; CHECK-NEXT:        .long   3
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   120
+; CHECK-NEXT:        .long   3
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!16, !17, !18}
+!llvm.ident = !{!19}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3, !8, !13}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "A", file: !1, line: 1, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!5 = !{!6, !7}
+!6 = !DIEnumerator(name: "AA", value: -1)
+!7 = !DIEnumerator(name: "AB", value: 0)
+!8 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "B", file: !1, line: 2, baseType: !9, size: 32, elements: !10)
+!9 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!10 = !{!11, !12}
+!11 = !DIEnumerator(name: "BA", value: 0, isUnsigned: true)
+!12 = !DIEnumerator(name: "BB", value: 1, isUnsigned: true)
+!13 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 8, baseType: !9, size: 32, elements: !14)
+!14 = !{!15}
+!15 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true)
+!16 = !{i32 2, !"Dwarf Version", i32 4}
+!17 = !{i32 2, !"Debug Info Version", i32 3}
+!18 = !{i32 1, !"wchar_size", i32 4}
+!19 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"}
+!20 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !21, scopeLine: 9, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !36)
+!21 = !DISubroutineType(types: !22)
+!22 = !{!4, !23}
+!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !24, size: 64)
+!24 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 7, size: 64, elements: !25)
+!25 = !{!26, !27}
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !24, file: !1, line: 7, baseType: !4, size: 32)
+!27 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !24, file: !1, line: 7, baseType: !28, size: 64)
+!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 6, size: 64, elements: !29)
+!29 = !{!30, !32, !34}
+!30 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !28, file: !1, line: 6, baseType: !31, size: 32)
+!31 = !DIDerivedType(tag: DW_TAG_typedef, name: "__A", file: !1, line: 3, baseType: !3)
+!32 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !28, file: !1, line: 6, baseType: !33, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+!33 = !DIDerivedType(tag: DW_TAG_typedef, name: "__B", file: !1, line: 4, baseType: !8)
+!34 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !28, file: !1, line: 6, baseType: !35, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32)
+!35 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 5, baseType: !4)
+!36 = !{!37, !38, !39, !40}
+!37 = !DILocalVariable(name: "arg", arg: 1, scope: !20, file: !1, line: 9, type: !23)
+!38 = !DILocalVariable(name: "r1", scope: !20, file: !1, line: 10, type: !9)
+!39 = !DILocalVariable(name: "r2", scope: !20, file: !1, line: 11, type: !9)
+!40 = !DILocalVariable(name: "r3", scope: !20, file: !1, line: 12, type: !9)
+!41 = !DILocation(line: 0, scope: !20)
+!42 = !DILocation(line: 10, column: 52, scope: !20)
+!43 = !DILocation(line: 10, column: 55, scope: !20)
+!44 = !DILocation(line: 10, column: 17, scope: !20)
+!45 = !DILocation(line: 11, column: 55, scope: !20)
+!46 = !DILocation(line: 11, column: 17, scope: !20)
+!47 = !DILocation(line: 12, column: 55, scope: !20)
+!48 = !DILocation(line: 12, column: 17, scope: !20)
+!49 = !DILocation(line: 13, column: 13, scope: !20)
+!50 = !DILocation(line: 13, column: 18, scope: !20)
+!51 = !DILocation(line: 13, column: 3, scope: !20)
diff --git a/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-3.ll b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-3.ll
new file mode 100644 (file)
index 0000000..619ca8a
--- /dev/null
@@ -0,0 +1,149 @@
+; 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:
+;   enum A { AA = -1, AB = 0, };
+;   enum B { BA = 0, BB = 1, };
+;   typedef enum A __A;
+;   typedef enum B __B;
+;   typedef struct s1 { __A a1[10]; __B a2[10][10]; } __s1;
+;   union u1 { int b1; __s1 b2; };
+;   enum { FIELD_SIGNEDNESS = 3, };
+;   int test(union u1 *arg) {
+;     unsigned r1 = __builtin_preserve_field_info(arg->b2.a1[5], FIELD_SIGNEDNESS);
+;     unsigned r2 = __builtin_preserve_field_info(arg->b2.a2[5][5], FIELD_SIGNEDNESS);
+;     /* r1 : 1, r2 : 0 */
+;     return r1 + r2;
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.u1 = type { %struct.s1 }
+%struct.s1 = type { [10 x i32], [10 x [10 x i32]] }
+
+; Function Attrs: nounwind readnone
+define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !29 {
+entry:
+  call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !43, metadata !DIExpression()), !dbg !46
+  %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !47, !llvm.preserve.access.index !33
+  %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !47
+  %1 = tail call [10 x i32]* @llvm.preserve.struct.access.index.p0a10i32.p0s_struct.s1s(%struct.s1* %b2, i32 0, i32 0), !dbg !48, !llvm.preserve.access.index !38
+  %2 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]* %1, i32 1, i32 5), !dbg !49, !llvm.preserve.access.index !17
+  %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %2, i64 3), !dbg !50
+  call void @llvm.dbg.value(metadata i32 %3, metadata !44, metadata !DIExpression()), !dbg !46
+  %4 = tail call [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1* %b2, i32 1, i32 1), !dbg !51, !llvm.preserve.access.index !38
+  %5 = tail call [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]* %4, i32 1, i32 5), !dbg !52, !llvm.preserve.access.index !21
+  %6 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]* %5, i32 1, i32 5), !dbg !52, !llvm.preserve.access.index !24
+  %7 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %6, i64 3), !dbg !53
+  call void @llvm.dbg.value(metadata i32 %7, metadata !45, metadata !DIExpression()), !dbg !46
+  %add = add i32 %7, %3, !dbg !54
+  ret i32 %add, !dbg !55
+}
+
+; CHECK:             r1 = 1
+; CHECK:             r0 = 0
+; CHECK:             r0 += r1
+; CHECK:             exit
+
+; CHECK:             .long   1                       # BTF_KIND_UNION(id = 2)
+; CHECK:             .ascii  "u1"                    # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=81
+; CHECK:             .ascii  "0:1:0:5"               # string offset=87
+; CHECK:             .ascii  "0:1:1:5:5"             # string offset=132
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   81                      # Field reloc section string offset=81
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   87
+; CHECK-NEXT:        .long   3
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   132
+; CHECK-NEXT:        .long   3
+
+; Function Attrs: nounwind readnone
+declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x i32]* @llvm.preserve.struct.access.index.p0a10i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1
+
+; Function Attrs: nounwind readnone
+declare [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]*, i32, i32) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!25, !26, !27}
+!llvm.ident = !{!28}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !16, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
+!2 = !{!3, !8, !13}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "A", file: !1, line: 1, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!5 = !{!6, !7}
+!6 = !DIEnumerator(name: "AA", value: -1)
+!7 = !DIEnumerator(name: "AB", value: 0)
+!8 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "B", file: !1, line: 2, baseType: !9, size: 32, elements: !10)
+!9 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!10 = !{!11, !12}
+!11 = !DIEnumerator(name: "BA", value: 0, isUnsigned: true)
+!12 = !DIEnumerator(name: "BB", value: 1, isUnsigned: true)
+!13 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 7, baseType: !9, size: 32, elements: !14)
+!14 = !{!15}
+!15 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true)
+!16 = !{!17, !21, !24}
+!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 320, elements: !19)
+!18 = !DIDerivedType(tag: DW_TAG_typedef, name: "__A", file: !1, line: 3, baseType: !3)
+!19 = !{!20}
+!20 = !DISubrange(count: 10)
+!21 = !DICompositeType(tag: DW_TAG_array_type, baseType: !22, size: 3200, elements: !23)
+!22 = !DIDerivedType(tag: DW_TAG_typedef, name: "__B", file: !1, line: 4, baseType: !8)
+!23 = !{!20, !20}
+!24 = !DICompositeType(tag: DW_TAG_array_type, baseType: !22, size: 320, elements: !19)
+!25 = !{i32 2, !"Dwarf Version", i32 4}
+!26 = !{i32 2, !"Debug Info Version", i32 3}
+!27 = !{i32 1, !"wchar_size", i32 4}
+!28 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)"}
+!29 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !30, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !42)
+!30 = !DISubroutineType(types: !31)
+!31 = !{!4, !32}
+!32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64)
+!33 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 6, size: 3520, elements: !34)
+!34 = !{!35, !36}
+!35 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !33, file: !1, line: 6, baseType: !4, size: 32)
+!36 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !33, file: !1, line: 6, baseType: !37, size: 3520)
+!37 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 5, baseType: !38)
+!38 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 5, size: 3520, elements: !39)
+!39 = !{!40, !41}
+!40 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !38, file: !1, line: 5, baseType: !17, size: 320)
+!41 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !38, file: !1, line: 5, baseType: !21, size: 3200, offset: 320)
+!42 = !{!43, !44, !45}
+!43 = !DILocalVariable(name: "arg", arg: 1, scope: !29, file: !1, line: 8, type: !32)
+!44 = !DILocalVariable(name: "r1", scope: !29, file: !1, line: 9, type: !9)
+!45 = !DILocalVariable(name: "r2", scope: !29, file: !1, line: 10, type: !9)
+!46 = !DILocation(line: 0, scope: !29)
+!47 = !DILocation(line: 9, column: 52, scope: !29)
+!48 = !DILocation(line: 9, column: 55, scope: !29)
+!49 = !DILocation(line: 9, column: 47, scope: !29)
+!50 = !DILocation(line: 9, column: 17, scope: !29)
+!51 = !DILocation(line: 10, column: 55, scope: !29)
+!52 = !DILocation(line: 10, column: 47, scope: !29)
+!53 = !DILocation(line: 10, column: 17, scope: !29)
+!54 = !DILocation(line: 12, column: 13, scope: !29)
+!55 = !DILocation(line: 12, column: 3, scope: !29)
index c07c16f52284777fd8655d950614c2f8a2734edc..1c0189b0f09b88ef924e462af84a3f77688f7118 100644 (file)
@@ -28,12 +28,13 @@ entry:
 ; CHECK:       exit
 ;
 ; CHECK:      .section        .BTF.ext,"",@progbits
-; CHECK:      .long   12                      # OffsetReloc
-; CHECK-NEXT: .long   20                      # Offset reloc section string offset=20
+; CHECK:      .long   16                      # FieldReloc
+; CHECK-NEXT: .long   20                      # Field reloc section string offset=20
 ; CHECK-NEXT: .long   1
 ; CHECK-NEXT: .long   [[RELOC]]
 ; CHECK-NEXT: .long   2
 ; CHECK-NEXT: .long   26
+; CHECK-NEXT: .long   0
 
 declare dso_local i32 @get_value(i8*) local_unnamed_addr #1
 
index 19b459533be6ddd32585919599b02012ae94631a..48cfa4536f59a6ac83a9654b8f1721105108a315 100644 (file)
@@ -27,12 +27,13 @@ entry:
 ; CHECK:       exit
 
 ; CHECK:      .section        .BTF.ext,"",@progbits
-; CHECK:      .long   12                      # OffsetReloc
-; CHECK-NEXT: .long   20                      # Offset reloc section string offset=20
+; CHECK:      .long   16                      # FieldReloc
+; CHECK-NEXT: .long   20                      # Field reloc section string offset=20
 ; CHECK-NEXT: .long   1
 ; CHECK-NEXT: .long   [[RELOC]]
 ; CHECK-NEXT: .long   2
 ; CHECK-NEXT: .long   26
+; CHECK-NEXT: .long   0
 
 declare dso_local i32 @get_value(i8*) local_unnamed_addr #1
 
index 5625bf99fa486d88ab6f29fb484d7e4f6ab47016..c2e3296067c3e33c0db30f0d0b5043f986d2b048 100644 (file)
@@ -33,15 +33,17 @@ entry:
 ; CHECK:             .ascii  "0:1"                   # string offset=[[ACCESS_STR:[0-9]+]]
 ; CHECK-NEXT:        .byte   0
 ; CHECK:             .section        .BTF.ext,"",@progbits
-; CHECK:             .long   12                      # OffsetReloc
-; CHECK-NEXT:        .long   [[SEC_INDEX]]           # Offset reloc section string offset=[[SEC_INDEX]]
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   [[SEC_INDEX]]           # Field reloc section string offset=[[SEC_INDEX]]
 ; CHECK-NEXT:        .long   2
 ; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:        .long   {{[0-9]+}}
 ; CHECK-NEXT:        .long   [[ACCESS_STR]]
+; CHECK-NEXT:        .long   0
 ; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:        .long   {{[0-9]+}}
 ; CHECK-NEXT:        .long   [[ACCESS_STR]]
+; CHECK-NEXT:        .long   0
 
 declare dso_local i32 @get_value(i8*, i8*) local_unnamed_addr #1
 
index a6fb3a34dde8314b519b2ee1db9354565680f913..6c4bbf14ce794764d1418608988d7cbb03fb5f1c 100644 (file)
@@ -109,17 +109,18 @@ define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15
 ; CHECK-NEXT:        .long   20
 ; CHECK-NEXT:        .long   124
 ; CHECK-NEXT:        .long   144
-; CHECK-NEXT:        .long   24
-; CHECK-NEXT:        .long   168
+; CHECK-NEXT:        .long   28
+; CHECK-NEXT:        .long   172
 ; CHECK-NEXT:        .long   0
 ; CHECK-NEXT:        .long   8                       # FuncInfo
 
-; CHECK:             .long   12                      # OffsetReloc
-; CHECK-NEXT:        .long   43                      # Offset reloc section string offset=43
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   43                      # Field reloc section string offset=43
 ; CHECK-NEXT:        .long   1
 ; CHECK-NEXT:        .long   .Ltmp2
 ; CHECK-NEXT:        .long   2
 ; CHECK-NEXT:        .long   86
+; CHECK-NEXT:        .long   0
 
 ; Function Attrs: argmemonly nounwind
 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
index 9e291cd220ef8f14fcd042230e704fbcb5d045c8..ceda85b0e6e26f4c5666176252e962bc741e72d9 100644 (file)
@@ -45,15 +45,17 @@ entry:
 ; CHECK:              .ascii  "0:1:0"                 # string offset=52
 ; CHECK:              .ascii  "2:1"                   # string offset=107
 
-; CHECK:              .long   12                      # OffsetReloc
-; CHECK-NEXT:         .long   46                      # Offset reloc section string offset=46
+; CHECK:              .long   16                      # FieldReloc
+; CHECK-NEXT:         .long   46                      # Field reloc section string offset=46
 ; CHECK-NEXT:         .long   2
 ; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:         .long   [[TID1]]
 ; CHECK-NEXT:         .long   52
+; CHECK-NEXT:         .long   0
 ; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:         .long   [[TID2]]
 ; CHECK-NEXT:         .long   107
+; CHECK-NEXT:         .long   0
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
 
index 7903179dbdb92f62c12342bf7ddc5ef008e9e4b6..19a8aa3701ea1d22353eae415b5961cfa391dd8b 100644 (file)
@@ -47,15 +47,17 @@ entry:
 ; CHECK:              .ascii  "v1"                    # string offset=100
 ; CHECK:              .ascii  "11:1"                  # string offset=107
 
-; CHECK:              .long   12                      # OffsetReloc
-; CHECK-NEXT:         .long   46                      # Offset reloc section string offset=46
+; CHECK:              .long   16                      # FieldReloc
+; CHECK-NEXT:         .long   46                      # Field reloc section string offset=46
 ; CHECK-NEXT:         .long   2
 ; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:         .long   [[TID1]]
 ; CHECK-NEXT:         .long   52
+; CHECK-NEXT:         .long   0
 ; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:         .long   [[TID2]]
 ; CHECK-NEXT:         .long   107
+; CHECK-NEXT:         .long   0
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
 
index a97c6a039f5b279e721e09cad8806cade8d866c8..9ec78ddab72036a9d8703eaea9745e2dc2bf39cb 100644 (file)
@@ -46,15 +46,17 @@ entry:
 ; CHECK:             .ascii  "v1"                    # string offset=81
 ; CHECK-NEXT:        .byte   0
 
-; CHECK:             .long   12                      # OffsetReloc
-; CHECK-NEXT:        .long   [[SEC_STR]]             # Offset reloc section string offset=[[SEC_STR]]
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   [[SEC_STR]]             # Field reloc section string offset=[[SEC_STR]]
 ; CHECK-NEXT:        .long   2
 ; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:        .long   [[V3_TID]]
 ; CHECK-NEXT:        .long   [[ACCESS_STR]]
+; CHECK-NEXT:        .long   0
 ; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:        .long   [[V1_TID]]
 ; CHECK-NEXT:        .long   [[ACCESS_STR]]
+; CHECK-NEXT:        .long   0
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
 
index f65b3f3fd69df2b940c9d9f0d6cd1f41327017f8..ee2b617330708eefbc47c7b7740360b9597b1eda 100644 (file)
@@ -46,15 +46,17 @@ entry:
 ; CHECK:             .ascii  "v1"                    # string offset=91
 
 
-; CHECK:             .long   12                      # OffsetReloc
-; CHECK-NEXT:        .long   39                      # Offset reloc section string offset=39
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   39                      # Field reloc section string offset=39
 ; CHECK-NEXT:        .long   2
 ; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:        .long   [[TID1]]
 ; CHECK-NEXT:        .long   45
+; CHECK-NEXT:        .long   0
 ; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:        .long   [[TID2]]
 ; CHECK-NEXT:        .long   45
+; CHECK-NEXT:        .long   0
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
 
index ed78b84eedf519bc62c5f12f9d131b74dc55de66..7b51029f1a0739e8d63934916f070340636616af 100644 (file)
@@ -45,15 +45,17 @@ entry:
 ; CHECK:             .ascii  "v1"                    # string offset=111
 ; CHECK:             .ascii  "0:1"                   # string offset=118
 
-; CHECK:             .long   12                      # OffsetReloc
-; CHECK-NEXT:        .long   57                      # Offset reloc section string offset=57
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   57                      # Field reloc section string offset=57
 ; CHECK-NEXT:        .long   2
 ; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:        .long   [[TID1]]
 ; CHECK-NEXT:        .long   63
+; CHECK-NEXT:        .long   0
 ; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:        .long   [[TID2]]
 ; CHECK-NEXT:        .long   118
+; CHECK-NEXT:        .long   0
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
 
index 1e8f99cc6ae326db1566ea51e0a2a55c0e78d0fc..8a6f9089fb3ca1eae08422af6cf999cfeb9a1e02 100644 (file)
@@ -46,15 +46,17 @@ entry:
 ; CHECK:             .ascii  "0:1"                   # string offset=45
 ; CHECK:             .ascii  "v1"                    # string offset=91
 
-; CHECK:             .long   12                      # OffsetReloc
-; CHECK-NEXT:        .long   39                      # Offset reloc section string offset=39
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   39                      # Field reloc section string offset=39
 ; CHECK-NEXT:        .long   2
 ; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:        .long   [[TID1]]
 ; CHECK-NEXT:        .long   45
+; CHECK-NEXT:        .long   0
 ; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:        .long   [[TID2]]
 ; CHECK-NEXT:        .long   45
+; CHECK-NEXT:        .long   0
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
 
index 320b0a9383bc5b0cc16a85f4da232b4671ca23d3..fd4734bd675a395ca29ac5209c3350b698bb8257 100644 (file)
@@ -47,15 +47,17 @@ entry:
 ; CHECK:             .ascii  "v1"                    # string offset=111
 ; CHECK:             .ascii  "0:1"                   # string offset=118
 
-; CHECK:             .long   12                      # OffsetReloc
-; CHECK-NEXT:        .long   57                      # Offset reloc section string offset=57
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   57                      # Field reloc section string offset=57
 ; CHECK-NEXT:        .long   2
 ; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:        .long   [[TID1]]
 ; CHECK-NEXT:        .long   63
+; CHECK-NEXT:        .long   0
 ; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:        .long   [[TID2]]
 ; CHECK-NEXT:        .long   118
+; CHECK-NEXT:        .long   0
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
 
index 35415f6d9d3d4f57faaf347006d08cc2ca1ee57b..f175425a0a29c50e8bf245ff7f32b520ae345cbb 100644 (file)
@@ -30,12 +30,13 @@ entry:
 ; CHECK:       .ascii  ".text"                 # string offset=20
 ; CHECK:       .ascii  "0:1"                   # string offset=26
 ;
-; CHECK:       .long   12                      # OffsetReloc
-; CHECK-NEXT:  .long   20                      # Offset reloc section string offset=20
+; CHECK:       .long   16                      # FieldReloc
+; CHECK-NEXT:  .long   20                      # Field reloc section string offset=20
 ; CHECK-NEXT:  .long   1
 ; CHECK-NEXT:  .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:  .long   2
 ; CHECK-NEXT:  .long   26
+; CHECK-NEXT:  .long   0
 
 ; Function Attrs: nounwind readnone
 declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s*, i32, i32) #1
index 52a630027e932bb872ae533061a7fcbda83ec1e8..f15c9a3dd2ba459953cbba45a980268c5b211838 100644 (file)
@@ -30,12 +30,13 @@ entry:
 ; CHECK:       .ascii  ".text"                 # string offset=20
 ; CHECK:       .ascii  "0:1"                   # string offset=63
 ;
-; CHECK:       .long   12                      # OffsetReloc
-; CHECK-NEXT:  .long   20                      # Offset reloc section string offset=20
+; CHECK:       .long   16                      # FieldReloc
+; CHECK-NEXT:  .long   20                      # Field reloc section string offset=20
 ; CHECK-NEXT:  .long   1
 ; CHECK-NEXT:  .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:  .long   2
 ; CHECK-NEXT:  .long   63
+; CHECK-NEXT:  .long   0
 
 ; Function Attrs: nounwind readnone
 declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s*, i32, i32) #1
diff --git a/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-1.ll b/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-1.ll
new file mode 100644 (file)
index 0000000..49982a5
--- /dev/null
@@ -0,0 +1,189 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+;   struct s {
+;     int a;
+;     int b1:9;
+;     int b2:4;
+;   };
+;   enum {
+;       FIELD_BYTE_OFFSET = 0,
+;       FIELD_BYTE_SIZE,
+;       FIELD_EXISTENCE,
+;       FIELD_SIGNEDNESS,
+;       FIELD_LSHIFT_U64,
+;       FIELD_RSHIFT_U64,
+;   };
+;   void bpf_probe_read(void *, unsigned, const void *);
+;   int field_read(struct s *arg) {
+;     unsigned long long ull;
+;     unsigned offset = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_OFFSET);
+;     unsigned size = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_SIZE);
+;     unsigned lshift;
+;
+;     bpf_probe_read(&ull, size, (const void *)arg + offset);
+;     lshift = __builtin_preserve_field_info(arg->b2, FIELD_LSHIFT_U64);
+;   #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+;     lshift = lshift + (size << 3) - 64;
+;   #endif
+;     ull <<= lshift;
+;     if (__builtin_preserve_field_info(arg->b2, FIELD_SIGNEDNESS))
+;       return (long long)ull >> __builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64);
+;     return ull >> __builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64);
+;   }
+; Compilation flag:
+;   clang -target bpfel -O2 -g -S -emit-llvm test.c
+
+%struct.s = type { i32, i16 }
+
+; Function Attrs: nounwind
+define dso_local i32 @field_read(%struct.s* %arg) local_unnamed_addr #0 !dbg !20 {
+entry:
+  %ull = alloca i64, align 8
+  call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !31, metadata !DIExpression()), !dbg !37
+  %0 = bitcast i64* %ull to i8*, !dbg !38
+  call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %0) #5, !dbg !38
+  %1 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s* %arg, i32 1, i32 2), !dbg !39, !llvm.preserve.access.index !25
+  %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 0), !dbg !40
+  call void @llvm.dbg.value(metadata i32 %2, metadata !34, metadata !DIExpression()), !dbg !37
+  %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 1), !dbg !41
+  call void @llvm.dbg.value(metadata i32 %3, metadata !35, metadata !DIExpression()), !dbg !37
+  %4 = bitcast %struct.s* %arg to i8*, !dbg !42
+  %idx.ext = zext i32 %2 to i64, !dbg !43
+  %add.ptr = getelementptr i8, i8* %4, i64 %idx.ext, !dbg !43
+  call void @bpf_probe_read(i8* nonnull %0, i32 %3, i8* %add.ptr) #5, !dbg !44
+  %5 = call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 4), !dbg !45
+  call void @llvm.dbg.value(metadata i32 %5, metadata !36, metadata !DIExpression()), !dbg !37
+  %6 = load i64, i64* %ull, align 8, !dbg !46, !tbaa !47
+  call void @llvm.dbg.value(metadata i64 %6, metadata !32, metadata !DIExpression()), !dbg !37
+  %sh_prom = zext i32 %5 to i64, !dbg !46
+  %shl = shl i64 %6, %sh_prom, !dbg !46
+  call void @llvm.dbg.value(metadata i64 %shl, metadata !32, metadata !DIExpression()), !dbg !37
+  %7 = call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 3), !dbg !51
+  %tobool = icmp eq i32 %7, 0, !dbg !51
+  %8 = call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 5), !dbg !37
+  %sh_prom1 = zext i32 %8 to i64, !dbg !37
+  %shr = ashr i64 %shl, %sh_prom1, !dbg !53
+  %shr3 = lshr i64 %shl, %sh_prom1, !dbg !53
+  %retval.0.in = select i1 %tobool, i64 %shr3, i64 %shr, !dbg !53
+  %retval.0 = trunc i64 %retval.0.in to i32, !dbg !37
+  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %0) #5, !dbg !54
+  ret i32 %retval.0, !dbg !54
+}
+
+; CHECK:             r{{[0-9]+}} = 4
+; CHECK:             r{{[0-9]+}} = 4
+; CHECK:             r{{[0-9]+}} = 51
+; CHECK:             r{{[0-9]+}} = 60
+; CHECK:             r{{[0-9]+}} = 1
+
+; CHECK:             .byte   115                     # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=30
+; CHECK:             .ascii  "0:2"                   # string offset=73
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   30                      # Field reloc section string offset=30
+; CHECK-NEXT:        .long   5
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   73
+; CHECK-NEXT:        .long   0
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   73
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   73
+; CHECK-NEXT:        .long   4
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   73
+; CHECK-NEXT:        .long   5
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   73
+; CHECK-NEXT:        .long   3
+
+; Function Attrs: argmemonly nounwind willreturn
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone
+declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #2
+
+declare dso_local void @bpf_probe_read(i8*, i32, i8*) local_unnamed_addr #3
+
+; Function Attrs: argmemonly nounwind willreturn
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #4
+
+attributes #0 = { nounwind "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 = { argmemonly nounwind willreturn }
+attributes #2 = { nounwind readnone }
+attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="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 #4 = { nounwind readnone speculatable willreturn }
+attributes #5 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!16, !17, !18}
+!llvm.ident = !{!19}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 923aa0ce806f7739b754167239fee2c9a15e2f31)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !12, 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: 6, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6, !7, !8, !9, !10, !11}
+!6 = !DIEnumerator(name: "FIELD_BYTE_OFFSET", value: 0, isUnsigned: true)
+!7 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true)
+!8 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true)
+!9 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true)
+!10 = !DIEnumerator(name: "FIELD_LSHIFT_U64", value: 4, isUnsigned: true)
+!11 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true)
+!12 = !{!13, !15}
+!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64)
+!14 = !DIDerivedType(tag: DW_TAG_const_type, baseType: null)
+!15 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed)
+!16 = !{i32 2, !"Dwarf Version", i32 4}
+!17 = !{i32 2, !"Debug Info Version", i32 3}
+!18 = !{i32 1, !"wchar_size", i32 4}
+!19 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 923aa0ce806f7739b754167239fee2c9a15e2f31)"}
+!20 = distinct !DISubprogram(name: "field_read", scope: !1, file: !1, line: 15, type: !21, scopeLine: 15, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !30)
+!21 = !DISubroutineType(types: !22)
+!22 = !{!23, !24}
+!23 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!24 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !25, size: 64)
+!25 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !26)
+!26 = !{!27, !28, !29}
+!27 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !25, file: !1, line: 2, baseType: !23, size: 32)
+!28 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !25, file: !1, line: 3, baseType: !23, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+!29 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !25, file: !1, line: 4, baseType: !23, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32)
+!30 = !{!31, !32, !34, !35, !36}
+!31 = !DILocalVariable(name: "arg", arg: 1, scope: !20, file: !1, line: 15, type: !24)
+!32 = !DILocalVariable(name: "ull", scope: !20, file: !1, line: 16, type: !33)
+!33 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned)
+!34 = !DILocalVariable(name: "offset", scope: !20, file: !1, line: 17, type: !4)
+!35 = !DILocalVariable(name: "size", scope: !20, file: !1, line: 18, type: !4)
+!36 = !DILocalVariable(name: "lshift", scope: !20, file: !1, line: 19, type: !4)
+!37 = !DILocation(line: 0, scope: !20)
+!38 = !DILocation(line: 16, column: 3, scope: !20)
+!39 = !DILocation(line: 17, column: 56, scope: !20)
+!40 = !DILocation(line: 17, column: 21, scope: !20)
+!41 = !DILocation(line: 18, column: 19, scope: !20)
+!42 = !DILocation(line: 21, column: 30, scope: !20)
+!43 = !DILocation(line: 21, column: 48, scope: !20)
+!44 = !DILocation(line: 21, column: 3, scope: !20)
+!45 = !DILocation(line: 22, column: 12, scope: !20)
+!46 = !DILocation(line: 26, column: 7, scope: !20)
+!47 = !{!48, !48, i64 0}
+!48 = !{!"long long", !49, i64 0}
+!49 = !{!"omnipotent char", !50, i64 0}
+!50 = !{!"Simple C/C++ TBAA"}
+!51 = !DILocation(line: 27, column: 7, scope: !52)
+!52 = distinct !DILexicalBlock(scope: !20, file: !1, line: 27, column: 7)
+!53 = !DILocation(line: 27, column: 7, scope: !20)
+!54 = !DILocation(line: 30, column: 1, scope: !20)
diff --git a/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-2.ll b/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-2.ll
new file mode 100644 (file)
index 0000000..96680c9
--- /dev/null
@@ -0,0 +1,246 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EL %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK,CHECK-EB %s
+; Source code:
+;   struct s {
+;     int a;
+;     int b1:9;
+;     int b2:4;
+;   };
+;   enum {
+;     FIELD_BYTE_OFFSET = 0,
+;     FIELD_BYTE_SIZE,
+;     FIELD_EXISTENCE,
+;     FIELD_SIGNEDNESS,
+;     FIELD_LSHIFT_U64,
+;     FIELD_RSHIFT_U64,
+;   };
+;   int field_read(struct s *arg) {
+;     unsigned long long ull;
+;     unsigned offset = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_OFFSET);
+;     unsigned size = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_SIZE);
+;     switch(size) {
+;     case 1:
+;       ull = *(unsigned char *)((void *)arg + offset); break;
+;     case 2:
+;       ull = *(unsigned short *)((void *)arg + offset); break;
+;     case 4:
+;       ull = *(unsigned int *)((void *)arg + offset); break;
+;     case 8:
+;       ull = *(unsigned long long *)((void *)arg + offset); break;
+;     }
+;     ull <<= __builtin_preserve_field_info(arg->b2, FIELD_LSHIFT_U64);
+;     if (__builtin_preserve_field_info(arg->b2, FIELD_SIGNEDNESS))
+;       return ((long long)ull) >>__builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64);
+;     return ull >> __builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64);
+;   }
+; Compilation flag:
+;   clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.s = type { i32, i16 }
+
+; Function Attrs: nounwind readonly
+define dso_local i32 @field_read(%struct.s* %arg) local_unnamed_addr #0 !dbg !26 {
+entry:
+  call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !37, metadata !DIExpression()), !dbg !41
+  %0 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s* %arg, i32 1, i32 2), !dbg !42, !llvm.preserve.access.index !31
+  %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 0), !dbg !43
+  call void @llvm.dbg.value(metadata i32 %1, metadata !39, metadata !DIExpression()), !dbg !41
+  %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 1), !dbg !44
+  call void @llvm.dbg.value(metadata i32 %2, metadata !40, metadata !DIExpression()), !dbg !41
+  switch i32 %2, label %sw.epilog [
+    i32 1, label %sw.bb
+    i32 2, label %sw.bb1
+    i32 4, label %sw.bb5
+    i32 8, label %sw.bb9
+  ], !dbg !45
+
+sw.bb:                                            ; preds = %entry
+  %3 = bitcast %struct.s* %arg to i8*, !dbg !46
+  %idx.ext = zext i32 %1 to i64, !dbg !48
+  %add.ptr = getelementptr i8, i8* %3, i64 %idx.ext, !dbg !48
+  %4 = load i8, i8* %add.ptr, align 1, !dbg !49, !tbaa !50
+  %conv = zext i8 %4 to i64, !dbg !49
+  call void @llvm.dbg.value(metadata i64 %conv, metadata !38, metadata !DIExpression()), !dbg !41
+  br label %sw.epilog, !dbg !53
+
+sw.bb1:                                           ; preds = %entry
+  %5 = bitcast %struct.s* %arg to i8*, !dbg !54
+  %idx.ext2 = zext i32 %1 to i64, !dbg !55
+  %add.ptr3 = getelementptr i8, i8* %5, i64 %idx.ext2, !dbg !55
+  %6 = bitcast i8* %add.ptr3 to i16*, !dbg !56
+  %7 = load i16, i16* %6, align 2, !dbg !57, !tbaa !58
+  %conv4 = zext i16 %7 to i64, !dbg !57
+  call void @llvm.dbg.value(metadata i64 %conv4, metadata !38, metadata !DIExpression()), !dbg !41
+  br label %sw.epilog, !dbg !60
+
+sw.bb5:                                           ; preds = %entry
+  %8 = bitcast %struct.s* %arg to i8*, !dbg !61
+  %idx.ext6 = zext i32 %1 to i64, !dbg !62
+  %add.ptr7 = getelementptr i8, i8* %8, i64 %idx.ext6, !dbg !62
+  %9 = bitcast i8* %add.ptr7 to i32*, !dbg !63
+  %10 = load i32, i32* %9, align 4, !dbg !64, !tbaa !65
+  %conv8 = zext i32 %10 to i64, !dbg !64
+  call void @llvm.dbg.value(metadata i64 %conv8, metadata !38, metadata !DIExpression()), !dbg !41
+  br label %sw.epilog, !dbg !67
+
+sw.bb9:                                           ; preds = %entry
+  %11 = bitcast %struct.s* %arg to i8*, !dbg !68
+  %idx.ext10 = zext i32 %1 to i64, !dbg !69
+  %add.ptr11 = getelementptr i8, i8* %11, i64 %idx.ext10, !dbg !69
+  %12 = bitcast i8* %add.ptr11 to i64*, !dbg !70
+  %13 = load i64, i64* %12, align 8, !dbg !71, !tbaa !72
+  call void @llvm.dbg.value(metadata i64 %13, metadata !38, metadata !DIExpression()), !dbg !41
+  br label %sw.epilog, !dbg !74
+
+sw.epilog:                                        ; preds = %entry, %sw.bb9, %sw.bb5, %sw.bb1, %sw.bb
+  %ull.0 = phi i64 [ undef, %entry ], [ %13, %sw.bb9 ], [ %conv8, %sw.bb5 ], [ %conv4, %sw.bb1 ], [ %conv, %sw.bb ]
+  call void @llvm.dbg.value(metadata i64 %ull.0, metadata !38, metadata !DIExpression()), !dbg !41
+  %14 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 4), !dbg !75
+  %sh_prom = zext i32 %14 to i64, !dbg !76
+  %shl = shl i64 %ull.0, %sh_prom, !dbg !76
+  call void @llvm.dbg.value(metadata i64 %shl, metadata !38, metadata !DIExpression()), !dbg !41
+  %15 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 3), !dbg !77
+  %tobool = icmp eq i32 %15, 0, !dbg !77
+  %16 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 5), !dbg !41
+  %sh_prom12 = zext i32 %16 to i64, !dbg !41
+  %shr = ashr i64 %shl, %sh_prom12, !dbg !79
+  %shr15 = lshr i64 %shl, %sh_prom12, !dbg !79
+  %retval.0.in = select i1 %tobool, i64 %shr15, i64 %shr, !dbg !79
+  %retval.0 = trunc i64 %retval.0.in to i32, !dbg !41
+  ret i32 %retval.0, !dbg !80
+}
+
+; CHECK:             r{{[0-9]+}} = 4
+; CHECK:             r{{[0-9]+}} = 4
+; CHECK-EL:          r{{[0-9]+}} = 51
+; CHECK-EB:          r{{[0-9]+}} = 41
+; CHECK:             r{{[0-9]+}} = 60
+; CHECK:             r{{[0-9]+}} = 1
+
+; CHECK:             .long   1                       # BTF_KIND_STRUCT(id = 2)
+; CHECK:             .byte   115                     # string offset=1
+; CHECK:             .ascii  ".text"                 # string offset=30
+; CHECK:             .ascii  "0:2"                   # string offset=36
+
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   30                      # Field reloc section string offset=30
+; CHECK-NEXT:        .long   5
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   36
+; CHECK-NEXT:        .long   0
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   36
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   36
+; CHECK-NEXT:        .long   4
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   36
+; CHECK-NEXT:        .long   5
+; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   36
+; CHECK-NEXT:        .long   3
+
+; 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 willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind readonly "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 willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!22, !23, !24}
+!llvm.ident = !{!25}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 923aa0ce806f7739b754167239fee2c9a15e2f31)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !12, 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: 6, baseType: !4, size: 32, elements: !5)
+!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!5 = !{!6, !7, !8, !9, !10, !11}
+!6 = !DIEnumerator(name: "FIELD_BYTE_OFFSET", value: 0, isUnsigned: true)
+!7 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true)
+!8 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true)
+!9 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true)
+!10 = !DIEnumerator(name: "FIELD_LSHIFT_U64", value: 4, isUnsigned: true)
+!11 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true)
+!12 = !{!13, !15, !16, !18, !19, !21}
+!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64)
+!14 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64)
+!17 = !DIBasicType(name: "unsigned short", size: 16, encoding: DW_ATE_unsigned)
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !4, size: 64)
+!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64)
+!20 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned)
+!21 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed)
+!22 = !{i32 2, !"Dwarf Version", i32 4}
+!23 = !{i32 2, !"Debug Info Version", i32 3}
+!24 = !{i32 1, !"wchar_size", i32 4}
+!25 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 923aa0ce806f7739b754167239fee2c9a15e2f31)"}
+!26 = distinct !DISubprogram(name: "field_read", scope: !1, file: !1, line: 14, type: !27, scopeLine: 14, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !36)
+!27 = !DISubroutineType(types: !28)
+!28 = !{!29, !30}
+!29 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !31, size: 64)
+!31 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !32)
+!32 = !{!33, !34, !35}
+!33 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !31, file: !1, line: 2, baseType: !29, size: 32)
+!34 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !31, file: !1, line: 3, baseType: !29, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+!35 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !31, file: !1, line: 4, baseType: !29, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32)
+!36 = !{!37, !38, !39, !40}
+!37 = !DILocalVariable(name: "arg", arg: 1, scope: !26, file: !1, line: 14, type: !30)
+!38 = !DILocalVariable(name: "ull", scope: !26, file: !1, line: 15, type: !20)
+!39 = !DILocalVariable(name: "offset", scope: !26, file: !1, line: 16, type: !4)
+!40 = !DILocalVariable(name: "size", scope: !26, file: !1, line: 17, type: !4)
+!41 = !DILocation(line: 0, scope: !26)
+!42 = !DILocation(line: 16, column: 56, scope: !26)
+!43 = !DILocation(line: 16, column: 21, scope: !26)
+!44 = !DILocation(line: 17, column: 19, scope: !26)
+!45 = !DILocation(line: 18, column: 3, scope: !26)
+!46 = !DILocation(line: 20, column: 30, scope: !47)
+!47 = distinct !DILexicalBlock(scope: !26, file: !1, line: 18, column: 16)
+!48 = !DILocation(line: 20, column: 42, scope: !47)
+!49 = !DILocation(line: 20, column: 11, scope: !47)
+!50 = !{!51, !51, i64 0}
+!51 = !{!"omnipotent char", !52, i64 0}
+!52 = !{!"Simple C/C++ TBAA"}
+!53 = !DILocation(line: 20, column: 53, scope: !47)
+!54 = !DILocation(line: 22, column: 31, scope: !47)
+!55 = !DILocation(line: 22, column: 43, scope: !47)
+!56 = !DILocation(line: 22, column: 12, scope: !47)
+!57 = !DILocation(line: 22, column: 11, scope: !47)
+!58 = !{!59, !59, i64 0}
+!59 = !{!"short", !51, i64 0}
+!60 = !DILocation(line: 22, column: 54, scope: !47)
+!61 = !DILocation(line: 24, column: 29, scope: !47)
+!62 = !DILocation(line: 24, column: 41, scope: !47)
+!63 = !DILocation(line: 24, column: 12, scope: !47)
+!64 = !DILocation(line: 24, column: 11, scope: !47)
+!65 = !{!66, !66, i64 0}
+!66 = !{!"int", !51, i64 0}
+!67 = !DILocation(line: 24, column: 52, scope: !47)
+!68 = !DILocation(line: 26, column: 35, scope: !47)
+!69 = !DILocation(line: 26, column: 47, scope: !47)
+!70 = !DILocation(line: 26, column: 12, scope: !47)
+!71 = !DILocation(line: 26, column: 11, scope: !47)
+!72 = !{!73, !73, i64 0}
+!73 = !{!"long long", !51, i64 0}
+!74 = !DILocation(line: 26, column: 58, scope: !47)
+!75 = !DILocation(line: 28, column: 11, scope: !26)
+!76 = !DILocation(line: 28, column: 7, scope: !26)
+!77 = !DILocation(line: 29, column: 7, scope: !78)
+!78 = distinct !DILexicalBlock(scope: !26, file: !1, line: 29, column: 7)
+!79 = !DILocation(line: 29, column: 7, scope: !26)
+!80 = !DILocation(line: 32, column: 1, scope: !26)
index 296e2d434a26e88adcea06128de4cc38f507fb1c..e83b32940909acd25d203e54807ea9ab75766468 100644 (file)
@@ -34,12 +34,13 @@ entry:
 ; CHECK:              .ascii  "v3"                    # string offset=16
 ; CHECK:              .ascii  "0:1"                   # string offset=23
 
-; CHECK:              .long   12                      # OffsetReloc
-; CHECK-NEXT:         .long   10                      # Offset reloc section string offset=10
+; CHECK:              .long   16                      # FieldReloc
+; CHECK-NEXT:         .long   10                      # Field reloc section string offset=10
 ; CHECK-NEXT:         .long   1
 ; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:         .long   [[TID1]]
 ; CHECK-NEXT:         .long   23
+; CHECK-NEXT:         .long   0
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
 
index 721081e29d2b3b16487a744efdeb9b429dbd4a69..66e8e66d083b67c9d4674cc4012d47e617f1a847 100644 (file)
@@ -36,12 +36,13 @@ entry:
 ; CHECK:              .ascii  "v3"                    # string offset=16
 ; CHECK:              .ascii  "7:1"                   # string offset=23
 
-; CHECK:              .long   12                      # OffsetReloc
-; CHECK-NEXT:         .long   10                      # Offset reloc section string offset=10
+; CHECK:              .long   16                      # FieldReloc
+; CHECK-NEXT:         .long   10                      # Field reloc section string offset=10
 ; CHECK-NEXT:         .long   1
 ; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:         .long   [[TID1]]
 ; CHECK-NEXT:         .long   23
+; CHECK-NEXT:         .long   0
 
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
index 394d04f9f81ff454941937665e869349a1738aa4..13c70fd40555d67bb0fc720a418253acca53fe0f 100644 (file)
@@ -34,12 +34,13 @@ entry:
 ; CHECK:              .ascii  "v3"                    # string offset=16
 ; CHECK:              .ascii  "0:1"                   # string offset=23
 
-; CHECK:              .long   12                      # OffsetReloc
-; CHECK-NEXT:         .long   10                      # Offset reloc section string offset=10
+; CHECK:              .long   16                      # FieldReloc
+; CHECK-NEXT:         .long   10                      # Field reloc section string offset=10
 ; CHECK-NEXT:         .long   1
 ; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:         .long   [[TID1]]
 ; CHECK-NEXT:         .long   23
+; CHECK-NEXT:         .long   0
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
 
index 2d14e7157b4df7b8cf4bb349c36a8054ed48fd9a..4646377cfbf39d9bc31a158382e49286f8d84e03 100644 (file)
@@ -21,7 +21,7 @@ entry:
 ; CHECK:             r1 += 16
 ; CHECK:             call get_value
 ; CHECK:             .section        .BTF.ext,"",@progbits
-; CHECK-NOT:         .long   12                      # OffsetReloc
+; CHECK-NOT:         .long   16                      # FieldReloc
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
 
index 0f75cd8124215135f1a1f51d7a4ea76df97a2f38..14e58d7c97a1ce2a19ef2faed03d39e7a66b7f3c 100644 (file)
@@ -50,18 +50,21 @@ entry:
 ; CHECK:             .ascii  "0:0:0"                 # string offset=76
 ; CHECK:             .ascii  "0:0:0:0"               # string offset=82
 
-; CHECK:             .long   12                      # OffsetReloc
-; CHECK-NEXT:        .long   29                      # Offset reloc section string offset=29
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   29                      # Field reloc section string offset=29
 ; CHECK-NEXT:        .long   3
 ; CHECK_NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK_NEXT:        .long   2
 ; CHECK_NEXT:        .long   72
+; CHECK_NEXT:        .long   0
 ; CHECK_NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK_NEXT:        .long   2
 ; CHECK_NEXT:        .long   76
+; CHECK_NEXT:        .long   0
 ; CHECK_NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK_NEXT:        .long   2
 ; CHECK_NEXT:        .long   82
+; CHECK_NEXT:        .long   0
 
 ; Function Attrs: nounwind readnone
 declare %struct.s1* @llvm.preserve.struct.access.index.p0s_struct.s1s.p0s_struct.r1s(%struct.r1*, i32, i32) #1
index 7f79196f9eb1e3a123d84d263a4e469faec690e4..61ff0f69f39c79d8d78292270d6ae73ff1614d96 100644 (file)
@@ -35,12 +35,13 @@ entry:
 ; CHECK:              .ascii  ".text"                 # string offset=52
 ; CHECK:              .ascii  "1:1:2:3"               # string offset=58
 
-; CHECK:              .long   12                      # OffsetReloc
-; CHECK-NEXT:         .long   52                      # Offset reloc section string offset=52
+; CHECK:              .long   16                      # FieldReloc
+; CHECK-NEXT:         .long   52                      # Field reloc section string offset=52
 ; CHECK-NEXT:         .long   1
 ; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:         .long   [[TID1]]
 ; CHECK-NEXT:         .long   58
+; CHECK-NEXT:         .long   0
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
 
index a9c29aa6b7c3d79edee66539e151308c47e98f1b..612c3d2af2763887c98b5e2ed570c32ceaf827a3 100644 (file)
@@ -36,12 +36,13 @@ entry:
 ; CHECK:             .ascii  ".text"                 # string offset=52
 ; CHECK:             .ascii  "1:1:2:3:2"             # string offset=58
 
-; CHECK:             .long   12                      # OffsetReloc
-; CHECK-NEXT:        .long   52                      # Offset reloc section string offset=52
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   52                      # Field reloc section string offset=52
 ; CHECK-NEXT:        .long   1
 ; CHECK-NEXT:        .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:        .long   [[TID1]]
 ; CHECK-NEXT:        .long   58
+; CHECK-NEXT:        .long   0
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
 
index 779b395299d43274e0b0060c5d5dc27350b18fd2..120b85d8687b84fea91fcc3fc38c23fb1973a189 100644 (file)
@@ -117,17 +117,18 @@ define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15
 ; CHECK-NEXT:        .long   20
 ; CHECK-NEXT:        .long   76
 ; CHECK-NEXT:        .long   96
-; CHECK-NEXT:        .long   24
-; CHECK-NEXT:        .long   120
+; CHECK-NEXT:        .long   28
+; CHECK-NEXT:        .long   124
 ; CHECK-NEXT:        .long   0
 ; CHECK-NEXT:        .long   8                       # FuncInfo
 
-; CHECK:             .long   12                      # OffsetReloc
-; CHECK-NEXT:        .long   57                      # Offset reloc section string offset=57
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   57                      # Field reloc section string offset=57
 ; CHECK-NEXT:        .long   1
 ; CHECK-NEXT:        .long   .Ltmp2
 ; CHECK-NEXT:        .long   2
 ; CHECK-NEXT:        .long   100
+; CHECK-NEXT:        .long   0
 
 ; Function Attrs: argmemonly nounwind
 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
index e85b3934e5a7073153de10ad57c0254d14c6c12d..4d8875c33415256a89e9e8c3d9607fc720617371 100644 (file)
@@ -32,12 +32,13 @@ entry:
 ; CHECK:              .ascii  ".text"                 # string offset=26
 ; CHECK:              .byte   49                      # string offset=32
 
-; CHECK:              .long   12                      # OffsetReloc
-; CHECK-NEXT:         .long   26                      # Offset reloc section string offset=26
+; CHECK:              .long   16                      # FieldReloc
+; CHECK-NEXT:         .long   26                      # Field reloc section string offset=26
 ; CHECK-NEXT:         .long   1
 ; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:         .long   [[TID1]]
 ; CHECK-NEXT:         .long   32
+; CHECK-NEXT:         .long   0
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
 
index 1c54935902d17cfedb2d226076e5f6b096c3d850..35279023aa35e318a01307490f49fd9a6f2addb3 100644 (file)
@@ -31,12 +31,13 @@ entry:
 ; CHECK:              .ascii  ".text"                 # string offset=26
 ; CHECK:              .ascii  "1:1"                   # string offset=32
 
-; CHECK:              .long   12                      # OffsetReloc
-; CHECK-NEXT:         .long   26                      # Offset reloc section string offset=26
+; CHECK:              .long   16                      # FieldReloc
+; CHECK-NEXT:         .long   26                      # Field reloc section string offset=26
 ; CHECK-NEXT:         .long   1
 ; CHECK-NEXT:         .long   .Ltmp{{[0-9]+}}
 ; CHECK-NEXT:         .long   [[TID1]]
 ; CHECK-NEXT:         .long   32
+; CHECK-NEXT:         .long   0
 
 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
 
index 08a204f77896516f8e360e7a6dc169bbab1c9f06..f77152b448b3430e9fca31298f633bed3687083a 100644 (file)
@@ -127,17 +127,18 @@ define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15
 ; CHECK-NEXT:        .long   20
 ; CHECK-NEXT:        .long   76
 ; CHECK-NEXT:        .long   96
-; CHECK-NEXT:        .long   24
-; CHECK-NEXT:        .long   120
+; CHECK-NEXT:        .long   28
+; CHECK-NEXT:        .long   124
 ; CHECK-NEXT:        .long   0
 ; CHECK-NEXT:        .long   8                       # FuncInfo
 
-; CHECK:             .long   12                      # OffsetReloc
-; CHECK-NEXT:        .long   66                      # Offset reloc section string offset=66
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   66                      # Field reloc section string offset=66
 ; CHECK-NEXT:        .long   1
 ; CHECK-NEXT:        .long   .Ltmp2
 ; CHECK-NEXT:        .long   2
 ; CHECK-NEXT:        .long   109
+; CHECK-NEXT:        .long   0
 
 ; Function Attrs: argmemonly nounwind
 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
index b18a4ab37f4686a111d127e924be199429f4bedc..a56b8fd84095ee4e7f10b8736679dc8237460dc1 100644 (file)
@@ -130,17 +130,18 @@ define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15
 ; CHECK-NEXT:        .long   20
 ; CHECK-NEXT:        .long   76
 ; CHECK-NEXT:        .long   96
-; CHECK-NEXT:        .long   24
-; CHECK-NEXT:        .long   120
+; CHECK-NEXT:        .long   28
+; CHECK-NEXT:        .long   124
 ; CHECK-NEXT:        .long   0
 ; CHECK-NEXT:        .long   8                       # FuncInfo
 
-; CHECK:             .long   12                      # OffsetReloc
-; CHECK-NEXT:        .long   77                      # Offset reloc section string offset=77
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   77                      # Field reloc section string offset=77
 ; CHECK-NEXT:        .long   1
 ; CHECK-NEXT:        .long   .Ltmp2
 ; CHECK-NEXT:        .long   2
 ; CHECK-NEXT:        .long   120
+; CHECK-NEXT:        .long   0
 
 ; Function Attrs: argmemonly nounwind
 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
index d63bc070c9d8ea3ee9e0bd80b58e5d694544c295..4659d1ba21352a0ea8432932bf4e4a2c5ae69d2c 100644 (file)
@@ -38,12 +38,13 @@ entry:
 ; CHECK-NEXT:    .byte   0
 ; CHECK:         .ascii  "0:0:1"                 # string offset=[[ACCESS_STR:[0-9]+]]
 ; CHECK-NEXT:    .byte   0
-; CHECK:         .long   12                      # OffsetReloc
-; CHECK-NEXT:    .long   [[SEC_INDEX]]           # Offset reloc section string offset=[[SEC_INDEX]]
+; CHECK:         .long   16                      # FieldReloc
+; CHECK-NEXT:    .long   [[SEC_INDEX]]           # Field reloc section string offset=[[SEC_INDEX]]
 ; CHECK-NEXT:    .long   1
 ; CHECK-NEXT:    .long   [[RELOC]]
 ; CHECK-NEXT:    .long   [[TYPE_ID]]
 ; CHECK-NEXT:    .long   [[ACCESS_STR]]
+; CHECK-NEXT:    .long   0
 
 declare dso_local i32 @get_value(i8*) local_unnamed_addr #1
 
index a0d7532bf4809dce0a333d69befadc17de5bf5ce..4bf6cffb1082ec5cb061010da8a17a92f1bfdca5 100644 (file)
@@ -37,12 +37,13 @@ entry:
 ; CHECK-NEXT:   .byte   0
 ; CHECK:        .ascii  "0:1"                   # string offset=[[ACCESS_STR:[0-9]+]]
 ; CHECK-NEXT:   .byte   0
-; CHECK:        .long   12                      # OffsetReloc
-; CHECK-NEXT:   .long   [[SEC_STR]]             # Offset reloc section string offset={{[0-9]+}}
+; CHECK:        .long   16                      # FieldReloc
+; CHECK-NEXT:   .long   [[SEC_STR]]             # Field reloc section string offset={{[0-9]+}}
 ; CHECK-NEXT:   .long   1
 ; CHECK-NEXT:   .long   [[RELOC]]
 ; CHECK-NEXT:   .long   [[TYPE_ID]]
 ; CHECK-NEXT:   .long   [[ACCESS_STR]]
+; CHECK-NEXT:   .long   0
 
 declare dso_local i32 @get_value(i8*) local_unnamed_addr #1
 
index caefc2b4bc6a1fcaa55321e1224e12a2c6495c25..707a45802ae8ecf8acb920a0f4ab796bc10f2bd7 100644 (file)
@@ -37,12 +37,13 @@ entry:
 ; CHECK-NEXT:    .byte   0
 ; CHECK:         .ascii  "0:1"                   # string offset=[[ACCESS_STR:[0-9]+]]
 ; CHECK-NEXT:    .byte   0
-; CHECK:         .long   12                      # OffsetReloc
-; CHECK-NEXT:    .long   [[SEC_INDEX]]           # Offset reloc section string offset=[[SEC_INDEX]]
+; CHECK:         .long   16                      # FieldReloc
+; CHECK-NEXT:    .long   [[SEC_INDEX]]           # Field reloc section string offset=[[SEC_INDEX]]
 ; CHECK-NEXT:    .long   1
 ; CHECK-NEXT:    .long   [[RELOC]]
 ; CHECK-NEXT:    .long   [[TYPE_ID]]
 ; CHECK-NEXT:    .long   [[ACCESS_STR]]
+; CHECK-NEXT:    .long   0
 
 declare dso_local i32 @get_value(i8*) local_unnamed_addr #1
 
index 82816944072e8981ce9057f7fff985b95105d5d6..b6a08549a507e9702bc288478d7602ea6d5a9eca 100644 (file)
@@ -45,12 +45,13 @@ entry:
 ; CHECK-NEXT:    .byte   0
 ; CHECK:         .ascii  "1:1:1"                 # string offset=[[ACCESS_STR:[0-9]+]]
 ; CHECK-NEXT:    .byte   0
-; CHECK:         .long   12                      # OffsetReloc
-; CHECK-NEXT:    .long   [[SEC_STR:[0-9]+]]      # Offset reloc section string offset=[[SEC_STR:[0-9]+]]
+; CHECK:         .long   16                      # FieldReloc
+; CHECK-NEXT:    .long   [[SEC_STR:[0-9]+]]      # Field reloc section string offset=[[SEC_STR:[0-9]+]]
 ; CHECK-NEXT:    .long   1
 ; CHECK-NEXT:    .long   [[RELOC:.Ltmp[0-9]+]]
 ; CHECK-NEXT:    .long   [[TYPE_ID:[0-9]+]]
 ; CHECK-NEXT:    .long   [[ACCESS_STR:[0-9]+]]
+; CHECK-NEXT:    .long   0
 
 declare dso_local i32 @get_value(i8*) local_unnamed_addr #1
 
index eefa1ebda737dff03c63db030635f805dbdcc258..cb60c81d58a15d72b112e450137c7f884b516728 100644 (file)
@@ -133,17 +133,18 @@ define dso_local i32 @bpf_prog(%union.sk_buff*) local_unnamed_addr #0 !dbg !15 {
 ; CHECK-NEXT:        .long   20
 ; CHECK-NEXT:        .long   76
 ; CHECK-NEXT:        .long   96
-; CHECK-NEXT:        .long   24
-; CHECK-NEXT:        .long   120
+; CHECK-NEXT:        .long   28
+; CHECK-NEXT:        .long   124
 ; CHECK-NEXT:        .long   0
 ; CHECK-NEXT:        .long   8                       # FuncInfo
 
-; CHECK:             .long   12                      # OffsetReloc
-; CHECK-NEXT:        .long   54                      # Offset reloc section string offset=54
+; CHECK:             .long   16                      # FieldReloc
+; CHECK-NEXT:        .long   54                      # Field reloc section string offset=54
 ; CHECK-NEXT:        .long   1
 ; CHECK-NEXT:        .long   .Ltmp2
 ; CHECK-NEXT:        .long   2
 ; CHECK-NEXT:        .long   97
+; CHECK-NEXT:        .long   0
 
 ; Function Attrs: argmemonly nounwind
 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1