diff --git a/clang/include/clang/Basic/BuiltinsBPF.def b/clang/include/clang/Basic/BuiltinsBPF.def new file mode 100644 --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsBPF.def @@ -0,0 +1,24 @@ +//===--- BuiltinsBPF.def - BPF Builtin function database --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the BPF-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +#if defined(BUILTIN) && !defined(TARGET_BUILTIN) +# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS) +#endif + +// Get record field information. +TARGET_BUILTIN(__builtin_preserve_field_info, "Ui.", "t", "") + +#undef BUILTIN +#undef TARGET_BUILTIN diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9953,6 +9953,11 @@ "%select{non-pointer|function pointer|void pointer}0 argument to " "'__builtin_launder' is not allowed">; +def err_preserve_field_info_not_field : Error< + "__builtin_preserve_field_info argument %0 not a field access">; +def err_preserve_field_info_not_const: Error< + "__builtin_preserve_field_info argument %0 not a constant">; + def err_bit_cast_non_trivially_copyable : Error< "__builtin_bit_cast %select{source|destination}0 type must be trivially copyable">; def err_bit_cast_type_size_mismatch : Error< diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h --- a/clang/include/clang/Basic/TargetBuiltins.h +++ b/clang/include/clang/Basic/TargetBuiltins.h @@ -52,6 +52,16 @@ }; } + /// BPF builtins + namespace BPF { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, + #define BUILTIN(ID, TYPE, ATTRS) BI##ID, + #include "clang/Basic/BuiltinsBPF.def" + LastTSBuiltin + }; + } + /// PPC builtins namespace PPC { enum { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11052,6 +11052,7 @@ bool CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall); bool CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall); diff --git a/clang/include/clang/module.modulemap b/clang/include/clang/module.modulemap --- a/clang/include/clang/module.modulemap +++ b/clang/include/clang/module.modulemap @@ -34,6 +34,7 @@ textual header "Basic/BuiltinsAArch64.def" textual header "Basic/BuiltinsAMDGPU.def" textual header "Basic/BuiltinsARM.def" + textual header "Basic/BuiltinsBPF.def" textual header "Basic/Builtins.def" textual header "Basic/BuiltinsHexagon.def" textual header "Basic/BuiltinsLe64.def" diff --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h --- a/clang/lib/Basic/Targets/BPF.h +++ b/clang/lib/Basic/Targets/BPF.h @@ -22,6 +22,8 @@ namespace targets { class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + public: BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { @@ -54,7 +56,7 @@ Features[Name] = Enabled; } - ArrayRef getTargetBuiltins() const override { return None; } + ArrayRef getTargetBuiltins() const override; const char *getClobbers() const override { return ""; } diff --git a/clang/lib/Basic/Targets/BPF.cpp b/clang/lib/Basic/Targets/BPF.cpp --- a/clang/lib/Basic/Targets/BPF.cpp +++ b/clang/lib/Basic/Targets/BPF.cpp @@ -13,11 +13,18 @@ #include "BPF.h" #include "Targets.h" #include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" #include "llvm/ADT/StringRef.h" using namespace clang; using namespace clang::targets; +const Builtin::Info BPFTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsBPF.def" +}; + void BPFTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { Builder.defineMacro("__bpf__"); @@ -34,3 +41,8 @@ void BPFTargetInfo::fillValidCPUList(SmallVectorImpl &Values) const { Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); } + +ArrayRef BPFTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::BPF::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -4242,6 +4242,9 @@ case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: return CGF->EmitAArch64BuiltinExpr(BuiltinID, E, Arch); + case llvm::Triple::bpfeb: + case llvm::Triple::bpfel: + return CGF->EmitBPFBuiltinExpr(BuiltinID, E); case llvm::Triple::x86: case llvm::Triple::x86_64: return CGF->EmitX86BuiltinExpr(BuiltinID, E); @@ -9300,6 +9303,37 @@ } } +Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, + const CallExpr *E) { + assert(BuiltinID == BPF::BI__builtin_preserve_field_info && + "unexpected ARM builtin"); + + const Expr *Arg = E->getArg(0); + bool IsBitField = Arg->IgnoreParens()->getObjectKind() == OK_BitField; + + if (!getDebugInfo()) { + CGM.Error(E->getExprLoc(), "using builtin_preserve_field_info() without -g"); + return IsBitField ? EmitLValue(Arg).getBitFieldPointer() + : EmitLValue(Arg).getPointer(); + } + + // Enable underlying preserve_*_access_index() generation. + bool OldIsInPreservedAIRegion = IsInPreservedAIRegion; + IsInPreservedAIRegion = true; + Value *FieldAddr = IsBitField ? EmitLValue(Arg).getBitFieldPointer() + : EmitLValue(Arg).getPointer(); + IsInPreservedAIRegion = OldIsInPreservedAIRegion; + + ConstantInt *C = cast(EmitScalarExpr(E->getArg(1))); + Value *InfoKind = ConstantInt::get(Int64Ty, C->getSExtValue()); + + // Built the IR for the preserve_field_info intrinsic. + llvm::Function *FnGetFieldInfo = llvm::Intrinsic::getDeclaration( + &CGM.getModule(), llvm::Intrinsic::bpf_preserve_field_info, + {FieldAddr->getType()}); + return Builder.CreateCall(FnGetFieldInfo, {FieldAddr, InfoKind}); +} + llvm::Value *CodeGenFunction:: BuildVector(ArrayRef Ops) { assert((Ops.size() & (Ops.size() - 1)) == 0 && diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -3990,9 +3990,19 @@ const CGBitFieldInfo &Info = RL.getBitFieldInfo(field); Address Addr = base.getAddress(); unsigned Idx = RL.getLLVMFieldNo(field); - if (Idx != 0) - // For structs, we GEP to the field that the record layout suggests. - Addr = Builder.CreateStructGEP(Addr, Idx, field->getName()); + if (!IsInPreservedAIRegion) { + if (Idx != 0) + // For structs, we GEP to the field that the record layout suggests. + Addr = Builder.CreateStructGEP(Addr, Idx, field->getName()); + } else { + const RecordDecl *rec = field->getParent(); + llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateRecordType( + getContext().getRecordType(rec), rec->getLocation()); + Addr = Builder.CreatePreserveStructAccessIndex(Addr, Idx, + getDebugInfoFIndex(rec, field->getFieldIndex()), + DbgInfo); + } + // Get the access type. llvm::Type *FieldIntTy = llvm::Type::getIntNTy(getLLVMContext(), Info.StorageSize); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3760,6 +3760,7 @@ llvm::Value *vectorWrapScalar16(llvm::Value *Op); llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E, llvm::Triple::ArchType Arch); + llvm::Value *EmitBPFBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *BuildVector(ArrayRef Ops); llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1540,6 +1540,11 @@ if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; + case llvm::Triple::bpfeb: + case llvm::Triple::bpfel: + if (CheckBPFBuiltinFunctionCall(BuiltinID, TheCall)) + return ExprError(); + break; case llvm::Triple::hexagon: if (CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); @@ -1940,6 +1945,40 @@ return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } +bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + assert(BuiltinID == BPF::BI__builtin_preserve_field_info && + "unexpected ARM builtin"); + + if (checkArgCount(*this, TheCall, 2)) + return true; + + // The first argument needs to be a record field access. + // If it is an array element access, we delay decision + // to BPF backend to check whether the access is a + // field access or not. + Expr *Arg = TheCall->getArg(0); + if (Arg->getType()->getAsPlaceholderType() || + (Arg->IgnoreParens()->getObjectKind() != OK_BitField && + !dyn_cast(Arg->IgnoreParens()) && + !dyn_cast(Arg->IgnoreParens()))) { + Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_field) + << 1 << Arg->getSourceRange(); + return true; + } + + // The second argument needs to be a constant int + llvm::APSInt Value; + if (!TheCall->getArg(1)->isIntegerConstantExpr(Value, Context)) { + Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_const) + << 2 << Arg->getSourceRange(); + return true; + } + + TheCall->setType(Context.UnsignedIntTy); + return false; +} + bool Sema::CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) { struct BuiltinAndString { unsigned BuiltinID; diff --git a/clang/test/CodeGen/builtins-bpf-preserve-field-info-1.c b/clang/test/CodeGen/builtins-bpf-preserve-field-info-1.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/builtins-bpf-preserve-field-info-1.c @@ -0,0 +1,35 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s + +#define _(x, y) (__builtin_preserve_field_info((x), (y))) + +struct s1 { + char a; + char b:2; +}; + +union u1 { + char a; + char b:2; +}; + +unsigned unit1(struct s1 *arg) { + return _(arg->a, 10) + _(arg->b, 10); +} +// CHECK: define dso_local i32 @unit1 +// CHECK: call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 0, i32 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S1:[0-9]+]] +// CHECK: call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %{{[0-9a-z]+}}, i64 10), !dbg !{{[0-9]+}} +// CHECK: call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 1, i32 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S1:[0-9]+]] +// CHECK: call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %{{[0-9a-z]+}}, i64 10), !dbg !{{[0-9]+}} + +unsigned unit2(union u1 *arg) { + return _(arg->a, 10) + _(arg->b, 10); +} +// CHECK: define dso_local i32 @unit2 +// CHECK: call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %{{[0-9a-z]+}}, i32 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[UNION_U1:[0-9]+]] +// CHECK: call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %{{[0-9a-z]+}}, i64 10), !dbg !{{[0-9]+}} +// CHECK: call i8* @llvm.preserve.struct.access.index.p0i8.p0s_union.u1s(%union.u1* %{{[0-9a-z]+}}, i32 0, i32 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[UNION_U1:[0-9]+]] +// CHECK: call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %{{[0-9a-z]+}}, i64 10), !dbg !{{[0-9]+}} + +// CHECK: ![[STRUCT_S1]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1" +// CHECK: ![[UNION_U1]] = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1" diff --git a/clang/test/CodeGen/builtins-bpf-preserve-field-info-2.c b/clang/test/CodeGen/builtins-bpf-preserve-field-info-2.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/builtins-bpf-preserve-field-info-2.c @@ -0,0 +1,26 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s + +#define _(x, y) (__builtin_preserve_field_info((x), (y))) + +struct s1 { + char a; + char b:2; +}; +struct s2 { + struct s1 s; +}; + +unsigned unit1(struct s2 *arg) { + return _(arg->s.a, 10) + _(arg->s.b, 10); +} +// CHECK: define dso_local i32 @unit1 +// CHECK: call %struct.s1* @llvm.preserve.struct.access.index.p0s_struct.s1s.p0s_struct.s2s(%struct.s2* %{{[0-9a-z]+}}, i32 0, i32 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S2:[0-9]+]] +// CHECK: call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 0, i32 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S1:[0-9]+]] +// CHECK: call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %{{[0-9a-z]+}}, i64 10), !dbg !{{[0-9]+}} +// CHECK: call %struct.s1* @llvm.preserve.struct.access.index.p0s_struct.s1s.p0s_struct.s2s(%struct.s2* %{{[0-9a-z]+}}, i32 0, i32 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S2:[0-9]+]] +// CHECK: call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1* %{{[0-9a-z]+}}, i32 1, i32 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S1:[0-9]+]] +// CHECK: call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %{{[0-9a-z]+}}, i64 10), !dbg !{{[0-9]+}} + +// CHECK: ![[STRUCT_S2]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s2" +// CHECK: ![[STRUCT_S1]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1" diff --git a/clang/test/Sema/builtins-bpf.c b/clang/test/Sema/builtins-bpf.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/builtins-bpf.c @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -x c -triple bpf-pc-linux-gnu -dwarf-version=4 -fsyntax-only -verify %s + +struct s { int a; int b[4]; int c:1; }; +union u { int a; int b[4]; int c:1; }; + +unsigned invalid1(const int *arg) { + return __builtin_preserve_field_info(arg, 1); // expected-error {{__builtin_preserve_field_info argument 1 not a field access}} +} + +unsigned invalid2(const int *arg) { + return __builtin_preserve_field_info(*arg, 1); // expected-error {{__builtin_preserve_field_info argument 1 not a field access}} +} + +void *invalid3(struct s *arg) { + return __builtin_preserve_field_info(arg->a, 1); // expected-warning {{incompatible integer to pointer conversion returning 'unsigned int' from a function with result type 'void *'}} +} + +unsigned valid4(struct s *arg) { + return __builtin_preserve_field_info(arg->b[1], 1); +} + +unsigned valid5(union u *arg) { + return __builtin_preserve_field_info(arg->b[2], 1); +} + +unsigned valid6(struct s *arg) { + return __builtin_preserve_field_info(arg->a, 1); +} + +unsigned valid7(struct s *arg) { + return __builtin_preserve_field_info(arg->c, 1ULL); +} + +unsigned valid8(union u *arg) { + return __builtin_preserve_field_info(arg->a, 1); +} + +unsigned valid9(union u *arg) { + return __builtin_preserve_field_info(arg->c, 'a'); +} + +unsigned invalid10(struct s *arg) { + return __builtin_preserve_field_info(arg->a, arg); // expected-error {{__builtin_preserve_field_info argument 2 not a constant}} +} + +unsigned invalid11(struct s *arg, int info_kind) { + return __builtin_preserve_field_info(arg->a, info_kind); // expected-error {{__builtin_preserve_field_info argument 2 not a constant}} +} diff --git a/llvm/include/llvm/IR/IntrinsicsBPF.td b/llvm/include/llvm/IR/IntrinsicsBPF.td --- a/llvm/include/llvm/IR/IntrinsicsBPF.td +++ b/llvm/include/llvm/IR/IntrinsicsBPF.td @@ -20,4 +20,7 @@ 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/llvm/lib/Target/BPF/BPF.h b/llvm/lib/Target/BPF/BPF.h --- a/llvm/lib/Target/BPF/BPF.h +++ b/llvm/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/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp --- a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp +++ b/llvm/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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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::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,203 @@ 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); + return (NextSBitOffset - SBitOffset) >> 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_BUF || + InfoKind == BPFCoreSharedInfo::FIELD_LSHIFT_U64_VAL) { + 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"); + /* endianness */ + if (InfoKind == BPFCoreSharedInfo::FIELD_LSHIFT_U64_VAL) { + return 64 - SizeInBits; + } else { + if (Triple.getArch() == Triple::bpfeb) + return 0; + else + 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"); + + // For little endian, put the result in a value or in a buffer + // has the same effect for left shifting. + // This is not the case for big endian. For example, + // a structure { int a:4; int b:3; int c:1; } can be loaded into a byte. + // If loaded into a 64bit buffer, for bitfield "b", + // the leftshift will be 4. + // But if loaded into a byte and then extended to a 64bit value, + // the leftshift should be 56 + 4 = 60. + // For this example, the lshift value for little endian is 56 + 1 = 57 + // for both scenarios. + unsigned OffsetInBits = MemberTy->getOffsetInBits(); + if (Triple.getArch() == Triple::bpfel) { + return SBitOffset + 64 - OffsetInBits - SizeInBits; + } else { + if (InfoKind == BPFCoreSharedInfo::FIELD_LSHIFT_U64_VAL) + return OffsetInBits + 64 - NextSBitOffset; + else + return OffsetInBits - SBitOffset; + } + } + + 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 +715,7 @@ 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 +735,8 @@ // 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 +751,12 @@ // 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 +792,22 @@ 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 +821,20 @@ 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 +842,13 @@ 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 +864,18 @@ 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 +883,25 @@ 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/llvm/lib/Target/BPF/BPFCORE.h b/llvm/lib/Target/BPF/BPFCORE.h --- a/llvm/lib/Target/BPF/BPFCORE.h +++ b/llvm/lib/Target/BPF/BPFCORE.h @@ -13,6 +13,17 @@ class BPFCoreSharedInfo { public: + enum OffsetRelocKind : uint32_t { + FIELD_BYTE_OFFSET = 0, + FIELD_BYTE_SIZE, + FIELD_EXISTENCE, + FIELD_SIGNEDNESS, + FIELD_LSHIFT_U64_BUF, + FIELD_LSHIFT_U64_VAL, + 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/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/llvm/lib/Target/BPF/BPFTargetMachine.cpp --- a/llvm/lib/Target/BPF/BPFTargetMachine.cpp +++ b/llvm/lib/Target/BPF/BPFTargetMachine.cpp @@ -94,7 +94,7 @@ void BPFPassConfig::addIRPasses() { - addPass(createBPFAbstractMemberAccess()); + addPass(createBPFAbstractMemberAccess(&getBPFTargetMachine())); TargetPassConfig::addIRPasses(); } diff --git a/llvm/lib/Target/BPF/BTF.h b/llvm/lib/Target/BPF/BTF.h --- a/llvm/lib/Target/BPF/BTF.h +++ b/llvm/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 @@ 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 @@ 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 @@ }; /// 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/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h --- a/llvm/lib/Target/BPF/BTFDebug.h +++ b/llvm/lib/Target/BPF/BTFDebug.h @@ -195,7 +195,7 @@ /// 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 @@ }; /// 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 @@ 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 @@ 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/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp --- a/llvm/lib/Target/BPF/BTFDebug.cpp +++ b/llvm/lib/Target/BPF/BTFDebug.cpp @@ -754,7 +754,7 @@ 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 @@ // 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 @@ 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 @@ 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 @@ } } - // 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 @@ 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 @@ // 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 @@ 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 @@ 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/llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll --- a/llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll +++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll @@ -28,12 +28,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-1.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-1.ll new file mode 100644 --- /dev/null +++ b/llvm/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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-2.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-2.ll new file mode 100644 --- /dev/null +++ b/llvm/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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-3.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-byte-size-3.ll new file mode 100644 --- /dev/null +++ b/llvm/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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-1.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-1.ll new file mode 100644 --- /dev/null +++ b/llvm/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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-2.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-2.ll new file mode 100644 --- /dev/null +++ b/llvm/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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-3.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-existence-3.ll new file mode 100644 --- /dev/null +++ b/llvm/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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-buf-1.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-buf-1.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-buf-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_BUF = 4, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_LSHIFT_U64_BUF); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_LSHIFT_U64_BUF); +; unsigned r3 = __builtin_preserve_field_info(arg->b2.a3, FIELD_LSHIFT_U64_BUF); +; unsigned r4 = __builtin_preserve_field_info(arg->b2.a4, FIELD_LSHIFT_U64_BUF); +; /* big endian: r1: 0, r2: 7, r3: 11, r4: 16 */ +; /* 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 = 0 +; CHECK-EB: r0 = 7 +; CHECK: r0 += r1 +; CHECK-EL: r1 = 48 +; CHECK-EB: r1 = 11 +; CHECK: r0 += r1 +; CHECK-EL: r1 = 32 +; CHECK-EB: r1 = 16 +; 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 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_LSHIFT_U64_BUF", 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 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: 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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-buf-2.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-buf-2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-buf-2.ll @@ -0,0 +1,124 @@ +; 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; char a2; } __s1; +; union u1 { int b1; __s1 b2; }; +; enum { FIELD_LSHIFT_U64_BUF = 4, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_LSHIFT_U64_BUF); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_LSHIFT_U64_BUF); +; /* big endian: r1: 0, r2: 0 */ +; /* little endian: 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 4), !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 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-EL: r1 = 32 +; CHECK-EL: r0 = 56 +; CHECK-EB: r1 = 0 +; CHECK-EB: 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=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 4 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 91 +; 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 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_LSHIFT_U64_BUF", 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 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: 9, column: 13, scope: !11) +!37 = !DILocation(line: 9, column: 3, scope: !11) diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-buf-3.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-buf-3.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-buf-3.ll @@ -0,0 +1,134 @@ +; 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 { char a1 [5][5]; } __s1; +; union u1 { int b1; __s1 b2; }; +; enum { FIELD_LSHIFT_U64_BUF = 4, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1[3], FIELD_LSHIFT_U64_BUF); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a1[3][3], FIELD_LSHIFT_U64_BUF); +; /* little endian: r1 : 24, r2 : 56 */ +; /* big endian: r1 : 0, r2 : 0 */ +; 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 4), !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 4), !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-EL: r1 = 24 +; CHECK-EL: r0 = 56 +; CHECK-EB: r1 = 0 +; CHECK-EB: 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=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 4 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 110 +; 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 [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_LSHIFT_U64_BUF", value: 4, 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: 9, column: 13, scope: !18) +!43 = !DILocation(line: 9, column: 3, scope: !18) diff --git a/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-val-1.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-val-1.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-val-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_VAL = 5, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_LSHIFT_U64_VAL); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_LSHIFT_U64_VAL); +; unsigned r3 = __builtin_preserve_field_info(arg->b2.a3, FIELD_LSHIFT_U64_VAL); +; unsigned r4 = __builtin_preserve_field_info(arg->b2.a4, FIELD_LSHIFT_U64_VAL); +; /* 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 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-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 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 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_VAL", 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 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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-val-2.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-val-2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-lshift-val-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_VAL = 5, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_LSHIFT_U64_VAL); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_LSHIFT_U64_VAL); +; /* 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 5), !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 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 = 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 5 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 92 +; 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 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_VAL", 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 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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-1.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-1.ll new file mode 100644 --- /dev/null +++ b/llvm/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 = 6, }; +; 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 6), !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 6), !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 6), !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 6), !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 6 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 92 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 98 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 104 +; CHECK-NEXT: .long 6 + +; 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: 6, 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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-2.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-2.ll new file mode 100644 --- /dev/null +++ b/llvm/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 = 6, }; +; 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 6), !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 6), !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 6 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 91 +; CHECK-NEXT: .long 6 + +; 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: 6, 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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-3.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-rshift-3.ll new file mode 100644 --- /dev/null +++ b/llvm/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 = 6, }; +; 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 6), !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 6), !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 6 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 110 +; CHECK-NEXT: .long 6 + +; 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: 6, 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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-1.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-1.ll new file mode 100644 --- /dev/null +++ b/llvm/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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-2.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-2.ll new file mode 100644 --- /dev/null +++ b/llvm/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/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-3.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-fieldinfo-signedness-3.ll new file mode 100644 --- /dev/null +++ b/llvm/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/llvm/test/CodeGen/BPF/CORE/intrinsic-struct.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-struct.ll --- a/llvm/test/CodeGen/BPF/CORE/intrinsic-struct.ll +++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-struct.ll @@ -28,12 +28,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/intrinsic-union.ll b/llvm/test/CodeGen/BPF/CORE/intrinsic-union.ll --- a/llvm/test/CodeGen/BPF/CORE/intrinsic-union.ll +++ b/llvm/test/CodeGen/BPF/CORE/intrinsic-union.ll @@ -27,12 +27,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll @@ -33,15 +33,17 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll @@ -109,17 +109,18 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll @@ -45,15 +45,17 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll @@ -47,15 +47,17 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll @@ -46,15 +46,17 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll @@ -46,15 +46,17 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll @@ -45,15 +45,17 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll @@ -46,15 +46,17 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll @@ -47,15 +47,17 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll @@ -30,12 +30,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll @@ -30,12 +30,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-1.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-1.ll @@ -0,0 +1,187 @@ +; 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_BUF, +; FIELD_LSHIFT_U64_VAL, +; 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); +; +; bpf_probe_read(&ull, size, (const void *)arg + offset); +; ull <<= __builtin_preserve_field_info(arg->b2, FIELD_LSHIFT_U64_BUF); +; 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 +define dso_local i32 @field_read(%struct.s* %arg) local_unnamed_addr #0 !dbg !21 { +entry: + %ull = alloca i64, align 8 + call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !32, 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 !26 + %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 !35, 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 !36, 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 + %6 = load i64, i64* %ull, align 8, !dbg !46, !tbaa !47 + call void @llvm.dbg.value(metadata i64 %6, metadata !33, 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 !33, 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 6), !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-EL: r{{[0-9]+}} = 51 +; CHECK-EB: r{{[0-9]+}} = 9 +; 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=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 6 +; 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 = !{!17, !18, !19} +!llvm.ident = !{!20} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 77bc546f9d7666b22dcc149f59df6a6a148f6649)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !13, 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, !12} +!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_BUF", value: 4, isUnsigned: true) +!11 = !DIEnumerator(name: "FIELD_LSHIFT_U64_VAL", value: 5, isUnsigned: true) +!12 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 6, isUnsigned: true) +!13 = !{!14, !16} +!14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) +!15 = !DIDerivedType(tag: DW_TAG_const_type, baseType: null) +!16 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed) +!17 = !{i32 2, !"Dwarf Version", i32 4} +!18 = !{i32 2, !"Debug Info Version", i32 3} +!19 = !{i32 1, !"wchar_size", i32 4} +!20 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 77bc546f9d7666b22dcc149f59df6a6a148f6649)"} +!21 = distinct !DISubprogram(name: "field_read", scope: !1, file: !1, line: 16, type: !22, scopeLine: 16, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !31) +!22 = !DISubroutineType(types: !23) +!23 = !{!24, !25} +!24 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !26, size: 64) +!26 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !27) +!27 = !{!28, !29, !30} +!28 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !26, file: !1, line: 2, baseType: !24, size: 32) +!29 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !26, file: !1, line: 3, baseType: !24, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32) +!30 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !26, file: !1, line: 4, baseType: !24, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32) +!31 = !{!32, !33, !35, !36} +!32 = !DILocalVariable(name: "arg", arg: 1, scope: !21, file: !1, line: 16, type: !25) +!33 = !DILocalVariable(name: "ull", scope: !21, file: !1, line: 17, type: !34) +!34 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned) +!35 = !DILocalVariable(name: "offset", scope: !21, file: !1, line: 18, type: !4) +!36 = !DILocalVariable(name: "size", scope: !21, file: !1, line: 19, type: !4) +!37 = !DILocation(line: 0, scope: !21) +!38 = !DILocation(line: 17, column: 3, scope: !21) +!39 = !DILocation(line: 18, column: 56, scope: !21) +!40 = !DILocation(line: 18, column: 21, scope: !21) +!41 = !DILocation(line: 19, column: 19, scope: !21) +!42 = !DILocation(line: 21, column: 30, scope: !21) +!43 = !DILocation(line: 21, column: 48, scope: !21) +!44 = !DILocation(line: 21, column: 3, scope: !21) +!45 = !DILocation(line: 22, column: 11, scope: !21) +!46 = !DILocation(line: 22, column: 7, scope: !21) +!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: 23, column: 7, scope: !52) +!52 = distinct !DILexicalBlock(scope: !21, file: !1, line: 23, column: 7) +!53 = !DILocation(line: 23, column: 7, scope: !21) +!54 = !DILocation(line: 26, column: 1, scope: !21) diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-fieldinfo-2.ll @@ -0,0 +1,248 @@ +; 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_BUF, +; FIELD_LSHIFT_U64_VAL, +; 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_VAL); +; 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 !27 { +entry: + call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !38, metadata !DIExpression()), !dbg !42 + %0 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s* %arg, i32 1, i32 2), !dbg !43, !llvm.preserve.access.index !32 + %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 0), !dbg !44 + call void @llvm.dbg.value(metadata i32 %1, metadata !40, metadata !DIExpression()), !dbg !42 + %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 1), !dbg !45 + call void @llvm.dbg.value(metadata i32 %2, metadata !41, metadata !DIExpression()), !dbg !42 + 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 !46 + +sw.bb: ; preds = %entry + %3 = bitcast %struct.s* %arg to i8*, !dbg !47 + %idx.ext = zext i32 %1 to i64, !dbg !49 + %add.ptr = getelementptr i8, i8* %3, i64 %idx.ext, !dbg !49 + %4 = load i8, i8* %add.ptr, align 1, !dbg !50, !tbaa !51 + %conv = zext i8 %4 to i64, !dbg !50 + call void @llvm.dbg.value(metadata i64 %conv, metadata !39, metadata !DIExpression()), !dbg !42 + br label %sw.epilog, !dbg !54 + +sw.bb1: ; preds = %entry + %5 = bitcast %struct.s* %arg to i8*, !dbg !55 + %idx.ext2 = zext i32 %1 to i64, !dbg !56 + %add.ptr3 = getelementptr i8, i8* %5, i64 %idx.ext2, !dbg !56 + %6 = bitcast i8* %add.ptr3 to i16*, !dbg !57 + %7 = load i16, i16* %6, align 2, !dbg !58, !tbaa !59 + %conv4 = zext i16 %7 to i64, !dbg !58 + call void @llvm.dbg.value(metadata i64 %conv4, metadata !39, metadata !DIExpression()), !dbg !42 + br label %sw.epilog, !dbg !61 + +sw.bb5: ; preds = %entry + %8 = bitcast %struct.s* %arg to i8*, !dbg !62 + %idx.ext6 = zext i32 %1 to i64, !dbg !63 + %add.ptr7 = getelementptr i8, i8* %8, i64 %idx.ext6, !dbg !63 + %9 = bitcast i8* %add.ptr7 to i32*, !dbg !64 + %10 = load i32, i32* %9, align 4, !dbg !65, !tbaa !66 + %conv8 = zext i32 %10 to i64, !dbg !65 + call void @llvm.dbg.value(metadata i64 %conv8, metadata !39, metadata !DIExpression()), !dbg !42 + br label %sw.epilog, !dbg !68 + +sw.bb9: ; preds = %entry + %11 = bitcast %struct.s* %arg to i8*, !dbg !69 + %idx.ext10 = zext i32 %1 to i64, !dbg !70 + %add.ptr11 = getelementptr i8, i8* %11, i64 %idx.ext10, !dbg !70 + %12 = bitcast i8* %add.ptr11 to i64*, !dbg !71 + %13 = load i64, i64* %12, align 8, !dbg !72, !tbaa !73 + call void @llvm.dbg.value(metadata i64 %13, metadata !39, metadata !DIExpression()), !dbg !42 + br label %sw.epilog, !dbg !75 + +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 !39, metadata !DIExpression()), !dbg !42 + %14 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 5), !dbg !76 + %sh_prom = zext i32 %14 to i64, !dbg !77 + %shl = shl i64 %ull.0, %sh_prom, !dbg !77 + call void @llvm.dbg.value(metadata i64 %shl, metadata !39, metadata !DIExpression()), !dbg !42 + %15 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 3), !dbg !78 + %tobool = icmp eq i32 %15, 0, !dbg !78 + %16 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 6), !dbg !42 + %sh_prom12 = zext i32 %16 to i64, !dbg !42 + %shr = ashr i64 %shl, %sh_prom12, !dbg !80 + %shr15 = lshr i64 %shl, %sh_prom12, !dbg !80 + %retval.0.in = select i1 %tobool, i64 %shr15, i64 %shr, !dbg !80 + %retval.0 = trunc i64 %retval.0.in to i32, !dbg !42 + ret i32 %retval.0, !dbg !81 +} + +; CHECK: r{{[0-9]+}} = 4 +; CHECK: r{{[0-9]+}} = 4 +; CHECK-EB: r{{[0-9]+}} = 41 +; CHECK-EL: r{{[0-9]+}} = 51 +; 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 5 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 36 +; CHECK-NEXT: .long 6 +; 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 = !{!23, !24, !25} +!llvm.ident = !{!26} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 77bc546f9d7666b22dcc149f59df6a6a148f6649)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !13, 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, !12} +!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_BUF", value: 4, isUnsigned: true) +!11 = !DIEnumerator(name: "FIELD_LSHIFT_U64_VAL", value: 5, isUnsigned: true) +!12 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 6, isUnsigned: true) +!13 = !{!14, !16, !17, !19, !20, !22} +!14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) +!15 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64) +!18 = !DIBasicType(name: "unsigned short", size: 16, encoding: DW_ATE_unsigned) +!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !4, size: 64) +!20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) +!21 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned) +!22 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed) +!23 = !{i32 2, !"Dwarf Version", i32 4} +!24 = !{i32 2, !"Debug Info Version", i32 3} +!25 = !{i32 1, !"wchar_size", i32 4} +!26 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 77bc546f9d7666b22dcc149f59df6a6a148f6649)"} +!27 = distinct !DISubprogram(name: "field_read", scope: !1, file: !1, line: 15, type: !28, scopeLine: 15, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !37) +!28 = !DISubroutineType(types: !29) +!29 = !{!30, !31} +!30 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !32, size: 64) +!32 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !33) +!33 = !{!34, !35, !36} +!34 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !32, file: !1, line: 2, baseType: !30, size: 32) +!35 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !32, file: !1, line: 3, baseType: !30, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32) +!36 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !32, file: !1, line: 4, baseType: !30, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32) +!37 = !{!38, !39, !40, !41} +!38 = !DILocalVariable(name: "arg", arg: 1, scope: !27, file: !1, line: 15, type: !31) +!39 = !DILocalVariable(name: "ull", scope: !27, file: !1, line: 16, type: !21) +!40 = !DILocalVariable(name: "offset", scope: !27, file: !1, line: 17, type: !4) +!41 = !DILocalVariable(name: "size", scope: !27, file: !1, line: 18, type: !4) +!42 = !DILocation(line: 0, scope: !27) +!43 = !DILocation(line: 17, column: 56, scope: !27) +!44 = !DILocation(line: 17, column: 21, scope: !27) +!45 = !DILocation(line: 18, column: 19, scope: !27) +!46 = !DILocation(line: 19, column: 3, scope: !27) +!47 = !DILocation(line: 21, column: 30, scope: !48) +!48 = distinct !DILexicalBlock(scope: !27, file: !1, line: 19, column: 16) +!49 = !DILocation(line: 21, column: 42, scope: !48) +!50 = !DILocation(line: 21, column: 11, scope: !48) +!51 = !{!52, !52, i64 0} +!52 = !{!"omnipotent char", !53, i64 0} +!53 = !{!"Simple C/C++ TBAA"} +!54 = !DILocation(line: 21, column: 53, scope: !48) +!55 = !DILocation(line: 23, column: 31, scope: !48) +!56 = !DILocation(line: 23, column: 43, scope: !48) +!57 = !DILocation(line: 23, column: 12, scope: !48) +!58 = !DILocation(line: 23, column: 11, scope: !48) +!59 = !{!60, !60, i64 0} +!60 = !{!"short", !52, i64 0} +!61 = !DILocation(line: 23, column: 54, scope: !48) +!62 = !DILocation(line: 25, column: 29, scope: !48) +!63 = !DILocation(line: 25, column: 41, scope: !48) +!64 = !DILocation(line: 25, column: 12, scope: !48) +!65 = !DILocation(line: 25, column: 11, scope: !48) +!66 = !{!67, !67, i64 0} +!67 = !{!"int", !52, i64 0} +!68 = !DILocation(line: 25, column: 52, scope: !48) +!69 = !DILocation(line: 27, column: 35, scope: !48) +!70 = !DILocation(line: 27, column: 47, scope: !48) +!71 = !DILocation(line: 27, column: 12, scope: !48) +!72 = !DILocation(line: 27, column: 11, scope: !48) +!73 = !{!74, !74, i64 0} +!74 = !{!"long long", !52, i64 0} +!75 = !DILocation(line: 27, column: 58, scope: !48) +!76 = !DILocation(line: 29, column: 11, scope: !27) +!77 = !DILocation(line: 29, column: 7, scope: !27) +!78 = !DILocation(line: 30, column: 7, scope: !79) +!79 = distinct !DILexicalBlock(scope: !27, file: !1, line: 30, column: 7) +!80 = !DILocation(line: 30, column: 7, scope: !27) +!81 = !DILocation(line: 33, column: 1, scope: !27) diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll @@ -34,12 +34,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll @@ -36,12 +36,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll @@ -34,12 +34,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll @@ -21,7 +21,7 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll @@ -50,18 +50,21 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll @@ -35,12 +35,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll @@ -36,12 +36,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll @@ -117,17 +117,18 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll @@ -32,12 +32,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll @@ -31,12 +31,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll @@ -127,17 +127,18 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll @@ -130,17 +130,18 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll @@ -38,12 +38,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll @@ -37,12 +37,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll @@ -37,12 +37,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll @@ -45,12 +45,13 @@ ; 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/llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll --- a/llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll @@ -133,17 +133,18 @@ ; 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