From 7be5366d0dd12d298e530acec79fb59aad347fc1 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 8 Oct 2019 18:23:17 +0000 Subject: [PATCH] [BPF] do compile-once run-everywhere relocation for bitfields 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 --- include/llvm/IR/IntrinsicsBPF.td | 3 + lib/Target/BPF/BPF.h | 2 +- lib/Target/BPF/BPFAbstractMemberAccess.cpp | 332 ++++++++++++++++-- lib/Target/BPF/BPFCORE.h | 10 + lib/Target/BPF/BPFTargetMachine.cpp | 2 +- lib/Target/BPF/BTF.h | 29 +- lib/Target/BPF/BTFDebug.cpp | 81 +++-- lib/Target/BPF/BTFDebug.h | 11 +- test/CodeGen/BPF/CORE/intrinsic-array.ll | 5 +- .../CORE/intrinsic-fieldinfo-byte-size-1.ll | 148 ++++++++ .../CORE/intrinsic-fieldinfo-byte-size-2.ll | 138 ++++++++ .../CORE/intrinsic-fieldinfo-byte-size-3.ll | 130 +++++++ .../CORE/intrinsic-fieldinfo-existence-1.ll | 162 +++++++++ .../CORE/intrinsic-fieldinfo-existence-2.ll | 121 +++++++ .../CORE/intrinsic-fieldinfo-existence-3.ll | 129 +++++++ .../BPF/CORE/intrinsic-fieldinfo-lshift-1.ll | 153 ++++++++ .../BPF/CORE/intrinsic-fieldinfo-lshift-2.ll | 122 +++++++ .../BPF/CORE/intrinsic-fieldinfo-rshift-1.ll | 148 ++++++++ .../BPF/CORE/intrinsic-fieldinfo-rshift-2.ll | 121 +++++++ .../BPF/CORE/intrinsic-fieldinfo-rshift-3.ll | 131 +++++++ .../CORE/intrinsic-fieldinfo-signedness-1.ll | 162 +++++++++ .../CORE/intrinsic-fieldinfo-signedness-2.ll | 151 ++++++++ .../CORE/intrinsic-fieldinfo-signedness-3.ll | 149 ++++++++ test/CodeGen/BPF/CORE/intrinsic-struct.ll | 5 +- test/CodeGen/BPF/CORE/intrinsic-union.ll | 5 +- .../BPF/CORE/offset-reloc-access-str.ll | 6 +- test/CodeGen/BPF/CORE/offset-reloc-basic.ll | 9 +- .../BPF/CORE/offset-reloc-cast-array-1.ll | 6 +- .../BPF/CORE/offset-reloc-cast-array-2.ll | 6 +- .../BPF/CORE/offset-reloc-cast-struct-1.ll | 6 +- .../BPF/CORE/offset-reloc-cast-struct-2.ll | 6 +- .../BPF/CORE/offset-reloc-cast-struct-3.ll | 6 +- .../BPF/CORE/offset-reloc-cast-union-1.ll | 6 +- .../BPF/CORE/offset-reloc-cast-union-2.ll | 6 +- .../CodeGen/BPF/CORE/offset-reloc-end-load.ll | 5 +- test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll | 5 +- .../BPF/CORE/offset-reloc-fieldinfo-1.ll | 189 ++++++++++ .../BPF/CORE/offset-reloc-fieldinfo-2.ll | 246 +++++++++++++ .../CodeGen/BPF/CORE/offset-reloc-global-1.ll | 5 +- .../CodeGen/BPF/CORE/offset-reloc-global-2.ll | 5 +- .../CodeGen/BPF/CORE/offset-reloc-global-3.ll | 5 +- test/CodeGen/BPF/CORE/offset-reloc-ignore.ll | 2 +- .../BPF/CORE/offset-reloc-middle-chain.ll | 7 +- .../BPF/CORE/offset-reloc-multi-array-1.ll | 5 +- .../BPF/CORE/offset-reloc-multi-array-2.ll | 5 +- .../BPF/CORE/offset-reloc-multilevel.ll | 9 +- .../BPF/CORE/offset-reloc-pointer-1.ll | 5 +- .../BPF/CORE/offset-reloc-pointer-2.ll | 5 +- .../BPF/CORE/offset-reloc-struct-anonymous.ll | 9 +- .../BPF/CORE/offset-reloc-struct-array.ll | 9 +- .../BPF/CORE/offset-reloc-typedef-array.ll | 5 +- .../BPF/CORE/offset-reloc-typedef-struct.ll | 5 +- .../BPF/CORE/offset-reloc-typedef-union.ll | 5 +- test/CodeGen/BPF/CORE/offset-reloc-typedef.ll | 5 +- test/CodeGen/BPF/CORE/offset-reloc-union.ll | 9 +- 55 files changed, 2885 insertions(+), 167 deletions(-) create mode 100644 test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-1.ll create mode 100644 test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-2.ll create mode 100644 test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-3.ll create mode 100644 test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-1.ll create mode 100644 test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-2.ll create mode 100644 test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-3.ll create mode 100644 test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-1.ll create mode 100644 test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-2.ll create mode 100644 test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-1.ll create mode 100644 test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-2.ll create mode 100644 test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-3.ll create mode 100644 test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-1.ll create mode 100644 test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-2.ll create mode 100644 test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-3.ll create mode 100644 test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-1.ll create mode 100644 test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-2.ll diff --git a/include/llvm/IR/IntrinsicsBPF.td b/include/llvm/IR/IntrinsicsBPF.td index d7595a2a770..3618cc6a412 100644 --- a/include/llvm/IR/IntrinsicsBPF.td +++ b/include/llvm/IR/IntrinsicsBPF.td @@ -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>]>; } diff --git a/lib/Target/BPF/BPF.h b/lib/Target/BPF/BPF.h index d311fc15409..ba21503d868 100644 --- a/lib/Target/BPF/BPF.h +++ b/lib/Target/BPF/BPF.h @@ -15,7 +15,7 @@ namespace llvm { class BPFTargetMachine; -ModulePass *createBPFAbstractMemberAccess(); +ModulePass *createBPFAbstractMemberAccess(BPFTargetMachine *TM); FunctionPass *createBPFISelDag(BPFTargetMachine &TM); FunctionPass *createBPFMISimplifyPatchablePass(); diff --git a/lib/Target/BPF/BPFAbstractMemberAccess.cpp b/lib/Target/BPF/BPFAbstractMemberAccess.cpp index 5a9a34e4af3..1b442815c7e 100644 --- a/lib/Target/BPF/BPFAbstractMemberAccess.cpp +++ b/lib/Target/BPF/BPFAbstractMemberAccess.cpp @@ -50,6 +50,28 @@ // addr = preserve_struct_access_index(base, gep_index, di_index) // !llvm.preserve.access.index // +// 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> CallInfoStack; private: enum : uint32_t { BPFPreserveArrayAI = 1, BPFPreserveUnionAI = 2, BPFPreserveStructAI = 3, + BPFPreserveFieldInfoAI = 4, }; std::map GEPGlobals; // A map to link preserve_*_access_index instrinsic calls. std::map> 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 BaseAICalls; @@ -127,6 +155,12 @@ private: bool removePreserveAccessIndexIntrinsic(Module &M); void replaceWithGEP(std::vector &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(ParentType)); const DIType *CType = stripQualifiers(cast(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(MemberTy->getStorageOffsetInBits()); + assert(SOff); + StartBitOffset = SOff->getZExtValue(); + + EndBitOffset = CTy->getSizeInBits(); + uint32_t Index = AccessIndex + 1; + for (; Index < CTy->getElements().size(); ++Index) { + auto Member = cast(CTy->getElements()[Index]); + if (!Member->getStorageOffsetInBits()) { + EndBitOffset = Member->getOffsetInBits(); + break; + } + SOff = dyn_cast(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(CTy->getElements()[AccessIndex]); + if (!MemberTy->isBitField()) { + PatchImm += MemberTy->getOffsetInBits() >> 3; + } else { + auto SOffset = dyn_cast(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(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(CTy->getElements()[AccessIndex]); + BaseTy = stripQualifiers(MemberTy->getBaseType()); + } + + // Only basic types and enum types have signedness. + const auto *BTy = dyn_cast(BaseTy); + while (!BTy) { + const auto *CompTy = dyn_cast(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(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(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(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> 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(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(stripQualifiers(cast(MDN))); - uint32_t Tag = CTy->getTag(); - if (Tag == dwarf::DW_TAG_structure_type) { - auto *MemberTy = cast(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); diff --git a/lib/Target/BPF/BPFCORE.h b/lib/Target/BPF/BPFCORE.h index e0950d95f8d..a6cb3cf5337 100644 --- a/lib/Target/BPF/BPFCORE.h +++ b/lib/Target/BPF/BPFCORE.h @@ -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 diff --git a/lib/Target/BPF/BPFTargetMachine.cpp b/lib/Target/BPF/BPFTargetMachine.cpp index a69a8067753..d940ac965c0 100644 --- a/lib/Target/BPF/BPFTargetMachine.cpp +++ b/lib/Target/BPF/BPFTargetMachine.cpp @@ -94,7 +94,7 @@ TargetPassConfig *BPFTargetMachine::createPassConfig(PassManagerBase &PM) { void BPFPassConfig::addIRPasses() { - addPass(createBPFAbstractMemberAccess()); + addPass(createBPFAbstractMemberAccess(&getBPFTargetMachine())); TargetPassConfig::addIRPasses(); } diff --git a/lib/Target/BPF/BTF.h b/lib/Target/BPF/BTF.h index ad56716710a..ef408dafd52 100644 --- a/lib/Target/BPF/BTF.h +++ b/lib/Target/BPF/BTF.h @@ -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 @@ -32,12 +32,12 @@ /// 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. diff --git a/lib/Target/BPF/BTFDebug.cpp b/lib/Target/BPF/BTFDebug.cpp index 3ad32347e0a..a8f857343ec 100644 --- a/lib/Target/BPF/BTFDebug.cpp +++ b/lib/Target/BPF/BTFDebug.cpp @@ -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(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(GVal); if (GVar && GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) { - // Emit "mov ri, " for abstract member accesses. - int64_t Imm = AccessOffsets[GVar->getName().str()]; + // Emit "mov ri, " 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)); diff --git a/lib/Target/BPF/BTFDebug.h b/lib/Target/BPF/BTFDebug.h index a79527d5e35..eec86144316 100644 --- a/lib/Target/BPF/BTFDebug.h +++ b/lib/Target/BPF/BTFDebug.h @@ -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 OffsetToIdMap; + std::map OffsetToIdMap; /// A vector of strings to represent the string table. std::vector 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 DIToIdMap; std::map> FuncInfoTable; std::map> LineInfoTable; - std::map> OffsetRelocTable; + std::map> FieldRelocTable; std::map> ExternRelocTable; StringMap> FileContent; std::map> DataSecEntries; std::vector StructTypes; - std::map AccessOffsets; + std::map PatchImms; std::map>> 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. diff --git a/test/CodeGen/BPF/CORE/intrinsic-array.ll b/test/CodeGen/BPF/CORE/intrinsic-array.ll index fe2c1968fd9..cf5511e7414 100644 --- a/test/CodeGen/BPF/CORE/intrinsic-array.ll +++ b/test/CodeGen/BPF/CORE/intrinsic-array.ll @@ -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 index 00000000000..d8be7b85a9d --- /dev/null +++ b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-1.ll @@ -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 index 00000000000..291d79f6514 --- /dev/null +++ b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-2.ll @@ -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 index 00000000000..fd517bf7357 --- /dev/null +++ b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-3.ll @@ -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 index 00000000000..f140dcbc127 --- /dev/null +++ b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-1.ll @@ -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 index 00000000000..186af8648b2 --- /dev/null +++ b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-2.ll @@ -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 index 00000000000..4c0a93a5638 --- /dev/null +++ b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-3.ll @@ -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 index 00000000000..ce4074cd558 --- /dev/null +++ b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-1.ll @@ -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 index 00000000000..83d1b3e1b00 --- /dev/null +++ b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-2.ll @@ -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 index 00000000000..70791d39cf7 --- /dev/null +++ b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-1.ll @@ -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 index 00000000000..657b19c872b --- /dev/null +++ b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-2.ll @@ -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 index 00000000000..2f9cf2fa843 --- /dev/null +++ b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-3.ll @@ -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 index 00000000000..f5605cb9b62 --- /dev/null +++ b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-1.ll @@ -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 index 00000000000..cec9790f577 --- /dev/null +++ b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-2.ll @@ -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 index 00000000000..619ca8af9ee --- /dev/null +++ b/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-3.ll @@ -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) diff --git a/test/CodeGen/BPF/CORE/intrinsic-struct.ll b/test/CodeGen/BPF/CORE/intrinsic-struct.ll index c07c16f5228..1c0189b0f09 100644 --- a/test/CodeGen/BPF/CORE/intrinsic-struct.ll +++ b/test/CodeGen/BPF/CORE/intrinsic-struct.ll @@ -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-union.ll b/test/CodeGen/BPF/CORE/intrinsic-union.ll index 19b459533be..48cfa4536f5 100644 --- a/test/CodeGen/BPF/CORE/intrinsic-union.ll +++ b/test/CodeGen/BPF/CORE/intrinsic-union.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll b/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll index 5625bf99fa4..c2e3296067c 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-basic.ll b/test/CodeGen/BPF/CORE/offset-reloc-basic.ll index a6fb3a34dde..6c4bbf14ce7 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-basic.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-basic.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll b/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll index 9e291cd220e..ceda85b0e6e 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll b/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll index 7903179dbdb..19a8aa3701e 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll b/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll index a97c6a039f5..9ec78ddab72 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll b/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll index f65b3f3fd69..ee2b6173307 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll b/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll index ed78b84eedf..7b51029f1a0 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll b/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll index 1e8f99cc6ae..8a6f9089fb3 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll b/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll index 320b0a9383b..fd4734bd675 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll b/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll index 35415f6d9d3..f175425a0a2 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll b/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll index 52a630027e9..f15c9a3dd2b 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll @@ -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 index 00000000000..49982a53959 --- /dev/null +++ b/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-1.ll @@ -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 index 00000000000..96680c91e72 --- /dev/null +++ b/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-2.ll @@ -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) diff --git a/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll b/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll index 296e2d434a2..e83b3294090 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll b/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll index 721081e29d2..66e8e66d083 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll b/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll index 394d04f9f81..13c70fd4055 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll b/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll index 2d14e7157b4..4646377cfbf 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll b/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll index 0f75cd81242..14e58d7c97a 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll b/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll index 7f79196f9eb..61ff0f69f39 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll b/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll index a9c29aa6b7c..612c3d2af27 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll b/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll index 779b395299d..120b85d8687 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll b/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll index e85b3934e5a..4d8875c3341 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll b/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll index 1c54935902d..35279023aa3 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll b/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll index 08a204f7789..f77152b448b 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll b/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll index b18a4ab37f4..a56b8fd8409 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll b/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll index d63bc070c9d..4659d1ba213 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll b/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll index a0d7532bf48..4bf6cffb108 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll b/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll index caefc2b4bc6..707a45802ae 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll b/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll index 82816944072..b6a08549a50 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll @@ -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 diff --git a/test/CodeGen/BPF/CORE/offset-reloc-union.ll b/test/CodeGen/BPF/CORE/offset-reloc-union.ll index eefa1ebda73..cb60c81d58a 100644 --- a/test/CodeGen/BPF/CORE/offset-reloc-union.ll +++ b/test/CodeGen/BPF/CORE/offset-reloc-union.ll @@ -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 -- 2.40.0