10b57cec5SDimitry Andric //===------ BPFAbstractMemberAccess.cpp - Abstracting Member Accesses -----===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This pass abstracted struct/union member accesses in order to support 100b57cec5SDimitry Andric // compile-once run-everywhere (CO-RE). The CO-RE intends to compile the program 110b57cec5SDimitry Andric // which can run on different kernels. In particular, if bpf program tries to 120b57cec5SDimitry Andric // access a particular kernel data structure member, the details of the 130b57cec5SDimitry Andric // intermediate member access will be remembered so bpf loader can do 140b57cec5SDimitry Andric // necessary adjustment right before program loading. 150b57cec5SDimitry Andric // 160b57cec5SDimitry Andric // For example, 170b57cec5SDimitry Andric // 180b57cec5SDimitry Andric // struct s { 190b57cec5SDimitry Andric // int a; 200b57cec5SDimitry Andric // int b; 210b57cec5SDimitry Andric // }; 220b57cec5SDimitry Andric // struct t { 230b57cec5SDimitry Andric // struct s c; 240b57cec5SDimitry Andric // int d; 250b57cec5SDimitry Andric // }; 260b57cec5SDimitry Andric // struct t e; 270b57cec5SDimitry Andric // 280b57cec5SDimitry Andric // For the member access e.c.b, the compiler will generate code 290b57cec5SDimitry Andric // &e + 4 300b57cec5SDimitry Andric // 310b57cec5SDimitry Andric // The compile-once run-everywhere instead generates the following code 320b57cec5SDimitry Andric // r = 4 330b57cec5SDimitry Andric // &e + r 340b57cec5SDimitry Andric // The "4" in "r = 4" can be changed based on a particular kernel version. 350b57cec5SDimitry Andric // For example, on a particular kernel version, if struct s is changed to 360b57cec5SDimitry Andric // 370b57cec5SDimitry Andric // struct s { 380b57cec5SDimitry Andric // int new_field; 390b57cec5SDimitry Andric // int a; 400b57cec5SDimitry Andric // int b; 410b57cec5SDimitry Andric // } 420b57cec5SDimitry Andric // 430b57cec5SDimitry Andric // By repeating the member access on the host, the bpf loader can 440b57cec5SDimitry Andric // adjust "r = 4" as "r = 8". 450b57cec5SDimitry Andric // 460b57cec5SDimitry Andric // This feature relies on the following three intrinsic calls: 470b57cec5SDimitry Andric // addr = preserve_array_access_index(base, dimension, index) 480b57cec5SDimitry Andric // addr = preserve_union_access_index(base, di_index) 490b57cec5SDimitry Andric // !llvm.preserve.access.index <union_ditype> 500b57cec5SDimitry Andric // addr = preserve_struct_access_index(base, gep_index, di_index) 510b57cec5SDimitry Andric // !llvm.preserve.access.index <struct_ditype> 520b57cec5SDimitry Andric // 538bcb0991SDimitry Andric // Bitfield member access needs special attention. User cannot take the 548bcb0991SDimitry Andric // address of a bitfield acceess. To facilitate kernel verifier 558bcb0991SDimitry Andric // for easy bitfield code optimization, a new clang intrinsic is introduced: 568bcb0991SDimitry Andric // uint32_t __builtin_preserve_field_info(member_access, info_kind) 578bcb0991SDimitry Andric // In IR, a chain with two (or more) intrinsic calls will be generated: 588bcb0991SDimitry Andric // ... 598bcb0991SDimitry Andric // addr = preserve_struct_access_index(base, 1, 1) !struct s 608bcb0991SDimitry Andric // uint32_t result = bpf_preserve_field_info(addr, info_kind) 618bcb0991SDimitry Andric // 628bcb0991SDimitry Andric // Suppose the info_kind is FIELD_SIGNEDNESS, 638bcb0991SDimitry Andric // The above two IR intrinsics will be replaced with 648bcb0991SDimitry Andric // a relocatable insn: 658bcb0991SDimitry Andric // signness = /* signness of member_access */ 668bcb0991SDimitry Andric // and signness can be changed by bpf loader based on the 678bcb0991SDimitry Andric // types on the host. 688bcb0991SDimitry Andric // 698bcb0991SDimitry Andric // User can also test whether a field exists or not with 708bcb0991SDimitry Andric // uint32_t result = bpf_preserve_field_info(member_access, FIELD_EXISTENCE) 718bcb0991SDimitry Andric // The field will be always available (result = 1) during initial 728bcb0991SDimitry Andric // compilation, but bpf loader can patch with the correct value 738bcb0991SDimitry Andric // on the target host where the member_access may or may not be available 748bcb0991SDimitry Andric // 750b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric #include "BPF.h" 780b57cec5SDimitry Andric #include "BPFCORE.h" 790b57cec5SDimitry Andric #include "BPFTargetMachine.h" 8081ad6265SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h" 815f757f3fSDimitry Andric #include "llvm/DebugInfo/BTF/BTF.h" 820b57cec5SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h" 830b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h" 840b57cec5SDimitry Andric #include "llvm/IR/Instruction.h" 850b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 86e8d8bef9SDimitry Andric #include "llvm/IR/IntrinsicsBPF.h" 870b57cec5SDimitry Andric #include "llvm/IR/Module.h" 88e8d8bef9SDimitry Andric #include "llvm/IR/PassManager.h" 890b57cec5SDimitry Andric #include "llvm/IR/Type.h" 900b57cec5SDimitry Andric #include "llvm/IR/User.h" 910b57cec5SDimitry Andric #include "llvm/IR/Value.h" 925f757f3fSDimitry Andric #include "llvm/IR/ValueHandle.h" 930b57cec5SDimitry Andric #include "llvm/Pass.h" 940b57cec5SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h" 958bcb0991SDimitry Andric #include <stack> 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric #define DEBUG_TYPE "bpf-abstract-member-access" 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric namespace llvm { 1005ffd83dbSDimitry Andric constexpr StringRef BPFCoreSharedInfo::AmaAttr; 101e8d8bef9SDimitry Andric uint32_t BPFCoreSharedInfo::SeqNum; 102e8d8bef9SDimitry Andric 103e8d8bef9SDimitry Andric Instruction *BPFCoreSharedInfo::insertPassThrough(Module *M, BasicBlock *BB, 104e8d8bef9SDimitry Andric Instruction *Input, 105e8d8bef9SDimitry Andric Instruction *Before) { 106e8d8bef9SDimitry Andric Function *Fn = Intrinsic::getDeclaration( 107e8d8bef9SDimitry Andric M, Intrinsic::bpf_passthrough, {Input->getType(), Input->getType()}); 108e8d8bef9SDimitry Andric Constant *SeqNumVal = ConstantInt::get(Type::getInt32Ty(BB->getContext()), 109e8d8bef9SDimitry Andric BPFCoreSharedInfo::SeqNum++); 110e8d8bef9SDimitry Andric 111e8d8bef9SDimitry Andric auto *NewInst = CallInst::Create(Fn, {SeqNumVal, Input}); 112bdd1243dSDimitry Andric NewInst->insertBefore(Before); 113e8d8bef9SDimitry Andric return NewInst; 114e8d8bef9SDimitry Andric } 1150b57cec5SDimitry Andric } // namespace llvm 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric using namespace llvm; 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric namespace { 120e8d8bef9SDimitry Andric class BPFAbstractMemberAccess final { 1210b57cec5SDimitry Andric public: 122e8d8bef9SDimitry Andric BPFAbstractMemberAccess(BPFTargetMachine *TM) : TM(TM) {} 123e8d8bef9SDimitry Andric 124e8d8bef9SDimitry Andric bool run(Function &F); 1258bcb0991SDimitry Andric 1268bcb0991SDimitry Andric struct CallInfo { 1278bcb0991SDimitry Andric uint32_t Kind; 1288bcb0991SDimitry Andric uint32_t AccessIndex; 12981ad6265SDimitry Andric MaybeAlign RecordAlignment; 1308bcb0991SDimitry Andric MDNode *Metadata; 131bdd1243dSDimitry Andric WeakTrackingVH Base; 1328bcb0991SDimitry Andric }; 1338bcb0991SDimitry Andric typedef std::stack<std::pair<CallInst *, CallInfo>> CallInfoStack; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric private: 1360b57cec5SDimitry Andric enum : uint32_t { 1370b57cec5SDimitry Andric BPFPreserveArrayAI = 1, 1380b57cec5SDimitry Andric BPFPreserveUnionAI = 2, 1390b57cec5SDimitry Andric BPFPreserveStructAI = 3, 1408bcb0991SDimitry Andric BPFPreserveFieldInfoAI = 4, 1410b57cec5SDimitry Andric }; 1420b57cec5SDimitry Andric 143e8d8bef9SDimitry Andric TargetMachine *TM; 144480093f4SDimitry Andric const DataLayout *DL = nullptr; 145e8d8bef9SDimitry Andric Module *M = nullptr; 146480093f4SDimitry Andric 147e8d8bef9SDimitry Andric static std::map<std::string, GlobalVariable *> GEPGlobals; 14881ad6265SDimitry Andric // A map to link preserve_*_access_index intrinsic calls. 1498bcb0991SDimitry Andric std::map<CallInst *, std::pair<CallInst *, CallInfo>> AIChain; 15081ad6265SDimitry Andric // A map to hold all the base preserve_*_access_index intrinsic calls. 1518bcb0991SDimitry Andric // The base call is not an input of any other preserve_* 1520b57cec5SDimitry Andric // intrinsics. 1538bcb0991SDimitry Andric std::map<CallInst *, CallInfo> BaseAICalls; 154753f127fSDimitry Andric // A map to hold <AnonRecord, TypeDef> relationships 155753f127fSDimitry Andric std::map<DICompositeType *, DIDerivedType *> AnonRecords; 156753f127fSDimitry Andric 157753f127fSDimitry Andric void CheckAnonRecordType(DIDerivedType *ParentTy, DIType *Ty); 158753f127fSDimitry Andric void CheckCompositeType(DIDerivedType *ParentTy, DICompositeType *CTy); 159753f127fSDimitry Andric void CheckDerivedType(DIDerivedType *ParentTy, DIDerivedType *DTy); 160753f127fSDimitry Andric void ResetMetadata(struct CallInfo &CInfo); 1610b57cec5SDimitry Andric 162e8d8bef9SDimitry Andric bool doTransformation(Function &F); 1630b57cec5SDimitry Andric 1648bcb0991SDimitry Andric void traceAICall(CallInst *Call, CallInfo &ParentInfo); 1658bcb0991SDimitry Andric void traceBitCast(BitCastInst *BitCast, CallInst *Parent, 1668bcb0991SDimitry Andric CallInfo &ParentInfo); 1678bcb0991SDimitry Andric void traceGEP(GetElementPtrInst *GEP, CallInst *Parent, 1688bcb0991SDimitry Andric CallInfo &ParentInfo); 169e8d8bef9SDimitry Andric void collectAICallChains(Function &F); 1700b57cec5SDimitry Andric 1718bcb0991SDimitry Andric bool IsPreserveDIAccessIndexCall(const CallInst *Call, CallInfo &Cinfo); 1728bcb0991SDimitry Andric bool IsValidAIChain(const MDNode *ParentMeta, uint32_t ParentAI, 1738bcb0991SDimitry Andric const MDNode *ChildMeta); 174e8d8bef9SDimitry Andric bool removePreserveAccessIndexIntrinsic(Function &F); 1758bcb0991SDimitry Andric bool HasPreserveFieldInfoCall(CallInfoStack &CallStack); 1765ffd83dbSDimitry Andric void GetStorageBitRange(DIDerivedType *MemberTy, Align RecordAlignment, 177480093f4SDimitry Andric uint32_t &StartBitOffset, uint32_t &EndBitOffset); 1788bcb0991SDimitry Andric uint32_t GetFieldInfo(uint32_t InfoKind, DICompositeType *CTy, 179480093f4SDimitry Andric uint32_t AccessIndex, uint32_t PatchImm, 18081ad6265SDimitry Andric MaybeAlign RecordAlignment); 1810b57cec5SDimitry Andric 1828bcb0991SDimitry Andric Value *computeBaseAndAccessKey(CallInst *Call, CallInfo &CInfo, 1838bcb0991SDimitry Andric std::string &AccessKey, MDNode *&BaseMeta); 184e8d8bef9SDimitry Andric MDNode *computeAccessKey(CallInst *Call, CallInfo &CInfo, 185e8d8bef9SDimitry Andric std::string &AccessKey, bool &IsInt32Ret); 186e8d8bef9SDimitry Andric bool transformGEPChain(CallInst *Call, CallInfo &CInfo); 1870b57cec5SDimitry Andric }; 1880b57cec5SDimitry Andric 189e8d8bef9SDimitry Andric std::map<std::string, GlobalVariable *> BPFAbstractMemberAccess::GEPGlobals; 190e8d8bef9SDimitry Andric } // End anonymous namespace 191e8d8bef9SDimitry Andric 192e8d8bef9SDimitry Andric bool BPFAbstractMemberAccess::run(Function &F) { 1930b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** Abstract Member Accesses **********\n"); 1940b57cec5SDimitry Andric 195e8d8bef9SDimitry Andric M = F.getParent(); 196e8d8bef9SDimitry Andric if (!M) 1970b57cec5SDimitry Andric return false; 1980b57cec5SDimitry Andric 199e8d8bef9SDimitry Andric // Bail out if no debug info. 200e8d8bef9SDimitry Andric if (M->debug_compile_units().empty()) 201e8d8bef9SDimitry Andric return false; 202e8d8bef9SDimitry Andric 203753f127fSDimitry Andric // For each argument/return/local_variable type, trace the type 204753f127fSDimitry Andric // pattern like '[derived_type]* [composite_type]' to check 205753f127fSDimitry Andric // and remember (anon record -> typedef) relations where the 206753f127fSDimitry Andric // anon record is defined as 207753f127fSDimitry Andric // typedef [const/volatile/restrict]* [anon record] 208753f127fSDimitry Andric DISubprogram *SP = F.getSubprogram(); 209753f127fSDimitry Andric if (SP && SP->isDefinition()) { 210753f127fSDimitry Andric for (DIType *Ty: SP->getType()->getTypeArray()) 211753f127fSDimitry Andric CheckAnonRecordType(nullptr, Ty); 212753f127fSDimitry Andric for (const DINode *DN : SP->getRetainedNodes()) { 213753f127fSDimitry Andric if (const auto *DV = dyn_cast<DILocalVariable>(DN)) 214753f127fSDimitry Andric CheckAnonRecordType(nullptr, DV->getType()); 215753f127fSDimitry Andric } 216753f127fSDimitry Andric } 217753f127fSDimitry Andric 218e8d8bef9SDimitry Andric DL = &M->getDataLayout(); 219e8d8bef9SDimitry Andric return doTransformation(F); 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric 222753f127fSDimitry Andric void BPFAbstractMemberAccess::ResetMetadata(struct CallInfo &CInfo) { 223753f127fSDimitry Andric if (auto Ty = dyn_cast<DICompositeType>(CInfo.Metadata)) { 224753f127fSDimitry Andric if (AnonRecords.find(Ty) != AnonRecords.end()) { 225753f127fSDimitry Andric if (AnonRecords[Ty] != nullptr) 226753f127fSDimitry Andric CInfo.Metadata = AnonRecords[Ty]; 227753f127fSDimitry Andric } 228753f127fSDimitry Andric } 229753f127fSDimitry Andric } 230753f127fSDimitry Andric 231753f127fSDimitry Andric void BPFAbstractMemberAccess::CheckCompositeType(DIDerivedType *ParentTy, 232753f127fSDimitry Andric DICompositeType *CTy) { 233753f127fSDimitry Andric if (!CTy->getName().empty() || !ParentTy || 234753f127fSDimitry Andric ParentTy->getTag() != dwarf::DW_TAG_typedef) 235753f127fSDimitry Andric return; 236753f127fSDimitry Andric 237753f127fSDimitry Andric if (AnonRecords.find(CTy) == AnonRecords.end()) { 238753f127fSDimitry Andric AnonRecords[CTy] = ParentTy; 239753f127fSDimitry Andric return; 240753f127fSDimitry Andric } 241753f127fSDimitry Andric 242753f127fSDimitry Andric // Two or more typedef's may point to the same anon record. 243753f127fSDimitry Andric // If this is the case, set the typedef DIType to be nullptr 244753f127fSDimitry Andric // to indicate the duplication case. 245753f127fSDimitry Andric DIDerivedType *CurrTy = AnonRecords[CTy]; 246753f127fSDimitry Andric if (CurrTy == ParentTy) 247753f127fSDimitry Andric return; 248753f127fSDimitry Andric AnonRecords[CTy] = nullptr; 249753f127fSDimitry Andric } 250753f127fSDimitry Andric 251753f127fSDimitry Andric void BPFAbstractMemberAccess::CheckDerivedType(DIDerivedType *ParentTy, 252753f127fSDimitry Andric DIDerivedType *DTy) { 253753f127fSDimitry Andric DIType *BaseType = DTy->getBaseType(); 254753f127fSDimitry Andric if (!BaseType) 255753f127fSDimitry Andric return; 256753f127fSDimitry Andric 257753f127fSDimitry Andric unsigned Tag = DTy->getTag(); 258753f127fSDimitry Andric if (Tag == dwarf::DW_TAG_pointer_type) 259753f127fSDimitry Andric CheckAnonRecordType(nullptr, BaseType); 260753f127fSDimitry Andric else if (Tag == dwarf::DW_TAG_typedef) 261753f127fSDimitry Andric CheckAnonRecordType(DTy, BaseType); 262753f127fSDimitry Andric else 263753f127fSDimitry Andric CheckAnonRecordType(ParentTy, BaseType); 264753f127fSDimitry Andric } 265753f127fSDimitry Andric 266753f127fSDimitry Andric void BPFAbstractMemberAccess::CheckAnonRecordType(DIDerivedType *ParentTy, 267753f127fSDimitry Andric DIType *Ty) { 268753f127fSDimitry Andric if (!Ty) 269753f127fSDimitry Andric return; 270753f127fSDimitry Andric 271753f127fSDimitry Andric if (auto *CTy = dyn_cast<DICompositeType>(Ty)) 272753f127fSDimitry Andric return CheckCompositeType(ParentTy, CTy); 273753f127fSDimitry Andric else if (auto *DTy = dyn_cast<DIDerivedType>(Ty)) 274753f127fSDimitry Andric return CheckDerivedType(ParentTy, DTy); 275753f127fSDimitry Andric } 276753f127fSDimitry Andric 2775ffd83dbSDimitry Andric static bool SkipDIDerivedTag(unsigned Tag, bool skipTypedef) { 2788bcb0991SDimitry Andric if (Tag != dwarf::DW_TAG_typedef && Tag != dwarf::DW_TAG_const_type && 2798bcb0991SDimitry Andric Tag != dwarf::DW_TAG_volatile_type && 2808bcb0991SDimitry Andric Tag != dwarf::DW_TAG_restrict_type && 2818bcb0991SDimitry Andric Tag != dwarf::DW_TAG_member) 2828bcb0991SDimitry Andric return false; 2835ffd83dbSDimitry Andric if (Tag == dwarf::DW_TAG_typedef && !skipTypedef) 2845ffd83dbSDimitry Andric return false; 2858bcb0991SDimitry Andric return true; 2868bcb0991SDimitry Andric } 2878bcb0991SDimitry Andric 2885ffd83dbSDimitry Andric static DIType * stripQualifiers(DIType *Ty, bool skipTypedef = true) { 2898bcb0991SDimitry Andric while (auto *DTy = dyn_cast<DIDerivedType>(Ty)) { 2905ffd83dbSDimitry Andric if (!SkipDIDerivedTag(DTy->getTag(), skipTypedef)) 2918bcb0991SDimitry Andric break; 2928bcb0991SDimitry Andric Ty = DTy->getBaseType(); 2938bcb0991SDimitry Andric } 2948bcb0991SDimitry Andric return Ty; 2958bcb0991SDimitry Andric } 2968bcb0991SDimitry Andric 2978bcb0991SDimitry Andric static const DIType * stripQualifiers(const DIType *Ty) { 2988bcb0991SDimitry Andric while (auto *DTy = dyn_cast<DIDerivedType>(Ty)) { 2995ffd83dbSDimitry Andric if (!SkipDIDerivedTag(DTy->getTag(), true)) 3008bcb0991SDimitry Andric break; 3018bcb0991SDimitry Andric Ty = DTy->getBaseType(); 3028bcb0991SDimitry Andric } 3038bcb0991SDimitry Andric return Ty; 3048bcb0991SDimitry Andric } 3058bcb0991SDimitry Andric 3068bcb0991SDimitry Andric static uint32_t calcArraySize(const DICompositeType *CTy, uint32_t StartDim) { 3078bcb0991SDimitry Andric DINodeArray Elements = CTy->getElements(); 3088bcb0991SDimitry Andric uint32_t DimSize = 1; 3098bcb0991SDimitry Andric for (uint32_t I = StartDim; I < Elements.size(); ++I) { 3108bcb0991SDimitry Andric if (auto *Element = dyn_cast_or_null<DINode>(Elements[I])) 3118bcb0991SDimitry Andric if (Element->getTag() == dwarf::DW_TAG_subrange_type) { 3128bcb0991SDimitry Andric const DISubrange *SR = cast<DISubrange>(Element); 3138bcb0991SDimitry Andric auto *CI = SR->getCount().dyn_cast<ConstantInt *>(); 3148bcb0991SDimitry Andric DimSize *= CI->getSExtValue(); 3158bcb0991SDimitry Andric } 3168bcb0991SDimitry Andric } 3178bcb0991SDimitry Andric 3188bcb0991SDimitry Andric return DimSize; 3198bcb0991SDimitry Andric } 3208bcb0991SDimitry Andric 321fe6060f1SDimitry Andric static Type *getBaseElementType(const CallInst *Call) { 322fe6060f1SDimitry Andric // Element type is stored in an elementtype() attribute on the first param. 32381ad6265SDimitry Andric return Call->getParamElementType(0); 324fe6060f1SDimitry Andric } 325fe6060f1SDimitry Andric 3265f757f3fSDimitry Andric static uint64_t getConstant(const Value *IndexValue) { 3275f757f3fSDimitry Andric const ConstantInt *CV = dyn_cast<ConstantInt>(IndexValue); 3285f757f3fSDimitry Andric assert(CV); 3295f757f3fSDimitry Andric return CV->getValue().getZExtValue(); 3305f757f3fSDimitry Andric } 3315f757f3fSDimitry Andric 3320b57cec5SDimitry Andric /// Check whether a call is a preserve_*_access_index intrinsic call or not. 3330b57cec5SDimitry Andric bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call, 3348bcb0991SDimitry Andric CallInfo &CInfo) { 3350b57cec5SDimitry Andric if (!Call) 3360b57cec5SDimitry Andric return false; 3370b57cec5SDimitry Andric 3385ffd83dbSDimitry Andric const auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand()); 3390b57cec5SDimitry Andric if (!GV) 3400b57cec5SDimitry Andric return false; 3415f757f3fSDimitry Andric if (GV->getName().starts_with("llvm.preserve.array.access.index")) { 3428bcb0991SDimitry Andric CInfo.Kind = BPFPreserveArrayAI; 3438bcb0991SDimitry Andric CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index); 3448bcb0991SDimitry Andric if (!CInfo.Metadata) 3458bcb0991SDimitry Andric report_fatal_error("Missing metadata for llvm.preserve.array.access.index intrinsic"); 3468bcb0991SDimitry Andric CInfo.AccessIndex = getConstant(Call->getArgOperand(2)); 3478bcb0991SDimitry Andric CInfo.Base = Call->getArgOperand(0); 348fe6060f1SDimitry Andric CInfo.RecordAlignment = DL->getABITypeAlign(getBaseElementType(Call)); 3490b57cec5SDimitry Andric return true; 3500b57cec5SDimitry Andric } 3515f757f3fSDimitry Andric if (GV->getName().starts_with("llvm.preserve.union.access.index")) { 3528bcb0991SDimitry Andric CInfo.Kind = BPFPreserveUnionAI; 3538bcb0991SDimitry Andric CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index); 3548bcb0991SDimitry Andric if (!CInfo.Metadata) 3558bcb0991SDimitry Andric report_fatal_error("Missing metadata for llvm.preserve.union.access.index intrinsic"); 356753f127fSDimitry Andric ResetMetadata(CInfo); 3578bcb0991SDimitry Andric CInfo.AccessIndex = getConstant(Call->getArgOperand(1)); 3588bcb0991SDimitry Andric CInfo.Base = Call->getArgOperand(0); 3590b57cec5SDimitry Andric return true; 3600b57cec5SDimitry Andric } 3615f757f3fSDimitry Andric if (GV->getName().starts_with("llvm.preserve.struct.access.index")) { 3628bcb0991SDimitry Andric CInfo.Kind = BPFPreserveStructAI; 3638bcb0991SDimitry Andric CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index); 3648bcb0991SDimitry Andric if (!CInfo.Metadata) 3658bcb0991SDimitry Andric report_fatal_error("Missing metadata for llvm.preserve.struct.access.index intrinsic"); 366753f127fSDimitry Andric ResetMetadata(CInfo); 3678bcb0991SDimitry Andric CInfo.AccessIndex = getConstant(Call->getArgOperand(2)); 3688bcb0991SDimitry Andric CInfo.Base = Call->getArgOperand(0); 369fe6060f1SDimitry Andric CInfo.RecordAlignment = DL->getABITypeAlign(getBaseElementType(Call)); 3708bcb0991SDimitry Andric return true; 3718bcb0991SDimitry Andric } 3725f757f3fSDimitry Andric if (GV->getName().starts_with("llvm.bpf.preserve.field.info")) { 3738bcb0991SDimitry Andric CInfo.Kind = BPFPreserveFieldInfoAI; 3748bcb0991SDimitry Andric CInfo.Metadata = nullptr; 3758bcb0991SDimitry Andric // Check validity of info_kind as clang did not check this. 3768bcb0991SDimitry Andric uint64_t InfoKind = getConstant(Call->getArgOperand(1)); 3775f757f3fSDimitry Andric if (InfoKind >= BTF::MAX_FIELD_RELOC_KIND) 3788bcb0991SDimitry Andric report_fatal_error("Incorrect info_kind for llvm.bpf.preserve.field.info intrinsic"); 3798bcb0991SDimitry Andric CInfo.AccessIndex = InfoKind; 3800b57cec5SDimitry Andric return true; 3810b57cec5SDimitry Andric } 3825f757f3fSDimitry Andric if (GV->getName().starts_with("llvm.bpf.preserve.type.info")) { 383e8d8bef9SDimitry Andric CInfo.Kind = BPFPreserveFieldInfoAI; 384e8d8bef9SDimitry Andric CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index); 385e8d8bef9SDimitry Andric if (!CInfo.Metadata) 386e8d8bef9SDimitry Andric report_fatal_error("Missing metadata for llvm.preserve.type.info intrinsic"); 387e8d8bef9SDimitry Andric uint64_t Flag = getConstant(Call->getArgOperand(1)); 388e8d8bef9SDimitry Andric if (Flag >= BPFCoreSharedInfo::MAX_PRESERVE_TYPE_INFO_FLAG) 389e8d8bef9SDimitry Andric report_fatal_error("Incorrect flag for llvm.bpf.preserve.type.info intrinsic"); 390e8d8bef9SDimitry Andric if (Flag == BPFCoreSharedInfo::PRESERVE_TYPE_INFO_EXISTENCE) 3915f757f3fSDimitry Andric CInfo.AccessIndex = BTF::TYPE_EXISTENCE; 39281ad6265SDimitry Andric else if (Flag == BPFCoreSharedInfo::PRESERVE_TYPE_INFO_MATCH) 3935f757f3fSDimitry Andric CInfo.AccessIndex = BTF::TYPE_MATCH; 394e8d8bef9SDimitry Andric else 3955f757f3fSDimitry Andric CInfo.AccessIndex = BTF::TYPE_SIZE; 396e8d8bef9SDimitry Andric return true; 397e8d8bef9SDimitry Andric } 3985f757f3fSDimitry Andric if (GV->getName().starts_with("llvm.bpf.preserve.enum.value")) { 399e8d8bef9SDimitry Andric CInfo.Kind = BPFPreserveFieldInfoAI; 400e8d8bef9SDimitry Andric CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index); 401e8d8bef9SDimitry Andric if (!CInfo.Metadata) 402e8d8bef9SDimitry Andric report_fatal_error("Missing metadata for llvm.preserve.enum.value intrinsic"); 403e8d8bef9SDimitry Andric uint64_t Flag = getConstant(Call->getArgOperand(2)); 404e8d8bef9SDimitry Andric if (Flag >= BPFCoreSharedInfo::MAX_PRESERVE_ENUM_VALUE_FLAG) 405e8d8bef9SDimitry Andric report_fatal_error("Incorrect flag for llvm.bpf.preserve.enum.value intrinsic"); 406e8d8bef9SDimitry Andric if (Flag == BPFCoreSharedInfo::PRESERVE_ENUM_VALUE_EXISTENCE) 4075f757f3fSDimitry Andric CInfo.AccessIndex = BTF::ENUM_VALUE_EXISTENCE; 408e8d8bef9SDimitry Andric else 4095f757f3fSDimitry Andric CInfo.AccessIndex = BTF::ENUM_VALUE; 410e8d8bef9SDimitry Andric return true; 411e8d8bef9SDimitry Andric } 4120b57cec5SDimitry Andric 4130b57cec5SDimitry Andric return false; 4140b57cec5SDimitry Andric } 4150b57cec5SDimitry Andric 4165f757f3fSDimitry Andric static void replaceWithGEP(CallInst *Call, uint32_t DimensionIndex, 4170b57cec5SDimitry Andric uint32_t GEPIndex) { 4180b57cec5SDimitry Andric uint32_t Dimension = 1; 4190b57cec5SDimitry Andric if (DimensionIndex > 0) 4208bcb0991SDimitry Andric Dimension = getConstant(Call->getArgOperand(DimensionIndex)); 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric Constant *Zero = 4230b57cec5SDimitry Andric ConstantInt::get(Type::getInt32Ty(Call->getParent()->getContext()), 0); 4240b57cec5SDimitry Andric SmallVector<Value *, 4> IdxList; 4250b57cec5SDimitry Andric for (unsigned I = 0; I < Dimension; ++I) 4260b57cec5SDimitry Andric IdxList.push_back(Zero); 4270b57cec5SDimitry Andric IdxList.push_back(Call->getArgOperand(GEPIndex)); 4280b57cec5SDimitry Andric 429*0fca6ea1SDimitry Andric auto *GEP = GetElementPtrInst::CreateInBounds(getBaseElementType(Call), 430*0fca6ea1SDimitry Andric Call->getArgOperand(0), IdxList, 431*0fca6ea1SDimitry Andric "", Call->getIterator()); 4320b57cec5SDimitry Andric Call->replaceAllUsesWith(GEP); 4330b57cec5SDimitry Andric Call->eraseFromParent(); 4340b57cec5SDimitry Andric } 4355f757f3fSDimitry Andric 4365f757f3fSDimitry Andric void BPFCoreSharedInfo::removeArrayAccessCall(CallInst *Call) { 4375f757f3fSDimitry Andric replaceWithGEP(Call, 1, 2); 4385f757f3fSDimitry Andric } 4395f757f3fSDimitry Andric 4405f757f3fSDimitry Andric void BPFCoreSharedInfo::removeStructAccessCall(CallInst *Call) { 4415f757f3fSDimitry Andric replaceWithGEP(Call, 0, 1); 4425f757f3fSDimitry Andric } 4435f757f3fSDimitry Andric 4445f757f3fSDimitry Andric void BPFCoreSharedInfo::removeUnionAccessCall(CallInst *Call) { 4455f757f3fSDimitry Andric Call->replaceAllUsesWith(Call->getArgOperand(0)); 4465f757f3fSDimitry Andric Call->eraseFromParent(); 4470b57cec5SDimitry Andric } 4480b57cec5SDimitry Andric 449e8d8bef9SDimitry Andric bool BPFAbstractMemberAccess::removePreserveAccessIndexIntrinsic(Function &F) { 4500b57cec5SDimitry Andric std::vector<CallInst *> PreserveArrayIndexCalls; 4510b57cec5SDimitry Andric std::vector<CallInst *> PreserveUnionIndexCalls; 4520b57cec5SDimitry Andric std::vector<CallInst *> PreserveStructIndexCalls; 4530b57cec5SDimitry Andric bool Found = false; 4540b57cec5SDimitry Andric 4550b57cec5SDimitry Andric for (auto &BB : F) 4560b57cec5SDimitry Andric for (auto &I : BB) { 4570b57cec5SDimitry Andric auto *Call = dyn_cast<CallInst>(&I); 4588bcb0991SDimitry Andric CallInfo CInfo; 4598bcb0991SDimitry Andric if (!IsPreserveDIAccessIndexCall(Call, CInfo)) 4600b57cec5SDimitry Andric continue; 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric Found = true; 4638bcb0991SDimitry Andric if (CInfo.Kind == BPFPreserveArrayAI) 4640b57cec5SDimitry Andric PreserveArrayIndexCalls.push_back(Call); 4658bcb0991SDimitry Andric else if (CInfo.Kind == BPFPreserveUnionAI) 4660b57cec5SDimitry Andric PreserveUnionIndexCalls.push_back(Call); 4670b57cec5SDimitry Andric else 4680b57cec5SDimitry Andric PreserveStructIndexCalls.push_back(Call); 4690b57cec5SDimitry Andric } 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric // do the following transformation: 4720b57cec5SDimitry Andric // . addr = preserve_array_access_index(base, dimension, index) 4730b57cec5SDimitry Andric // is transformed to 4740b57cec5SDimitry Andric // addr = GEP(base, dimenion's zero's, index) 4750b57cec5SDimitry Andric // . addr = preserve_union_access_index(base, di_index) 4760b57cec5SDimitry Andric // is transformed to 4770b57cec5SDimitry Andric // addr = base, i.e., all usages of "addr" are replaced by "base". 4780b57cec5SDimitry Andric // . addr = preserve_struct_access_index(base, gep_index, di_index) 4790b57cec5SDimitry Andric // is transformed to 4800b57cec5SDimitry Andric // addr = GEP(base, 0, gep_index) 4815f757f3fSDimitry Andric for (CallInst *Call : PreserveArrayIndexCalls) 4825f757f3fSDimitry Andric BPFCoreSharedInfo::removeArrayAccessCall(Call); 4835f757f3fSDimitry Andric for (CallInst *Call : PreserveStructIndexCalls) 4845f757f3fSDimitry Andric BPFCoreSharedInfo::removeStructAccessCall(Call); 4855f757f3fSDimitry Andric for (CallInst *Call : PreserveUnionIndexCalls) 4865f757f3fSDimitry Andric BPFCoreSharedInfo::removeUnionAccessCall(Call); 4870b57cec5SDimitry Andric 4880b57cec5SDimitry Andric return Found; 4890b57cec5SDimitry Andric } 4900b57cec5SDimitry Andric 4918bcb0991SDimitry Andric /// Check whether the access index chain is valid. We check 4928bcb0991SDimitry Andric /// here because there may be type casts between two 4938bcb0991SDimitry Andric /// access indexes. We want to ensure memory access still valid. 4948bcb0991SDimitry Andric bool BPFAbstractMemberAccess::IsValidAIChain(const MDNode *ParentType, 4958bcb0991SDimitry Andric uint32_t ParentAI, 4968bcb0991SDimitry Andric const MDNode *ChildType) { 4978bcb0991SDimitry Andric if (!ChildType) 4988bcb0991SDimitry Andric return true; // preserve_field_info, no type comparison needed. 4998bcb0991SDimitry Andric 5008bcb0991SDimitry Andric const DIType *PType = stripQualifiers(cast<DIType>(ParentType)); 5018bcb0991SDimitry Andric const DIType *CType = stripQualifiers(cast<DIType>(ChildType)); 5028bcb0991SDimitry Andric 5038bcb0991SDimitry Andric // Child is a derived/pointer type, which is due to type casting. 5048bcb0991SDimitry Andric // Pointer type cannot be in the middle of chain. 5058bcb0991SDimitry Andric if (isa<DIDerivedType>(CType)) 5068bcb0991SDimitry Andric return false; 5078bcb0991SDimitry Andric 5088bcb0991SDimitry Andric // Parent is a pointer type. 5098bcb0991SDimitry Andric if (const auto *PtrTy = dyn_cast<DIDerivedType>(PType)) { 5108bcb0991SDimitry Andric if (PtrTy->getTag() != dwarf::DW_TAG_pointer_type) 5118bcb0991SDimitry Andric return false; 5128bcb0991SDimitry Andric return stripQualifiers(PtrTy->getBaseType()) == CType; 5138bcb0991SDimitry Andric } 5148bcb0991SDimitry Andric 5158bcb0991SDimitry Andric // Otherwise, struct/union/array types 5168bcb0991SDimitry Andric const auto *PTy = dyn_cast<DICompositeType>(PType); 5178bcb0991SDimitry Andric const auto *CTy = dyn_cast<DICompositeType>(CType); 5188bcb0991SDimitry Andric assert(PTy && CTy && "ParentType or ChildType is null or not composite"); 5198bcb0991SDimitry Andric 5208bcb0991SDimitry Andric uint32_t PTyTag = PTy->getTag(); 5218bcb0991SDimitry Andric assert(PTyTag == dwarf::DW_TAG_array_type || 5228bcb0991SDimitry Andric PTyTag == dwarf::DW_TAG_structure_type || 5238bcb0991SDimitry Andric PTyTag == dwarf::DW_TAG_union_type); 5248bcb0991SDimitry Andric 5258bcb0991SDimitry Andric uint32_t CTyTag = CTy->getTag(); 5268bcb0991SDimitry Andric assert(CTyTag == dwarf::DW_TAG_array_type || 5278bcb0991SDimitry Andric CTyTag == dwarf::DW_TAG_structure_type || 5288bcb0991SDimitry Andric CTyTag == dwarf::DW_TAG_union_type); 5298bcb0991SDimitry Andric 5308bcb0991SDimitry Andric // Multi dimensional arrays, base element should be the same 5318bcb0991SDimitry Andric if (PTyTag == dwarf::DW_TAG_array_type && PTyTag == CTyTag) 5328bcb0991SDimitry Andric return PTy->getBaseType() == CTy->getBaseType(); 5338bcb0991SDimitry Andric 5348bcb0991SDimitry Andric DIType *Ty; 5358bcb0991SDimitry Andric if (PTyTag == dwarf::DW_TAG_array_type) 5368bcb0991SDimitry Andric Ty = PTy->getBaseType(); 5378bcb0991SDimitry Andric else 5388bcb0991SDimitry Andric Ty = dyn_cast<DIType>(PTy->getElements()[ParentAI]); 5398bcb0991SDimitry Andric 5408bcb0991SDimitry Andric return dyn_cast<DICompositeType>(stripQualifiers(Ty)) == CTy; 5418bcb0991SDimitry Andric } 5428bcb0991SDimitry Andric 5438bcb0991SDimitry Andric void BPFAbstractMemberAccess::traceAICall(CallInst *Call, 5448bcb0991SDimitry Andric CallInfo &ParentInfo) { 5450b57cec5SDimitry Andric for (User *U : Call->users()) { 5460b57cec5SDimitry Andric Instruction *Inst = dyn_cast<Instruction>(U); 5470b57cec5SDimitry Andric if (!Inst) 5480b57cec5SDimitry Andric continue; 5490b57cec5SDimitry Andric 5500b57cec5SDimitry Andric if (auto *BI = dyn_cast<BitCastInst>(Inst)) { 5518bcb0991SDimitry Andric traceBitCast(BI, Call, ParentInfo); 5520b57cec5SDimitry Andric } else if (auto *CI = dyn_cast<CallInst>(Inst)) { 5538bcb0991SDimitry Andric CallInfo ChildInfo; 5548bcb0991SDimitry Andric 5558bcb0991SDimitry Andric if (IsPreserveDIAccessIndexCall(CI, ChildInfo) && 5568bcb0991SDimitry Andric IsValidAIChain(ParentInfo.Metadata, ParentInfo.AccessIndex, 5578bcb0991SDimitry Andric ChildInfo.Metadata)) { 5588bcb0991SDimitry Andric AIChain[CI] = std::make_pair(Call, ParentInfo); 5598bcb0991SDimitry Andric traceAICall(CI, ChildInfo); 5600b57cec5SDimitry Andric } else { 5618bcb0991SDimitry Andric BaseAICalls[Call] = ParentInfo; 5620b57cec5SDimitry Andric } 5630b57cec5SDimitry Andric } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) { 5640b57cec5SDimitry Andric if (GI->hasAllZeroIndices()) 5658bcb0991SDimitry Andric traceGEP(GI, Call, ParentInfo); 5660b57cec5SDimitry Andric else 5678bcb0991SDimitry Andric BaseAICalls[Call] = ParentInfo; 5688bcb0991SDimitry Andric } else { 5698bcb0991SDimitry Andric BaseAICalls[Call] = ParentInfo; 5700b57cec5SDimitry Andric } 5710b57cec5SDimitry Andric } 5720b57cec5SDimitry Andric } 5730b57cec5SDimitry Andric 5740b57cec5SDimitry Andric void BPFAbstractMemberAccess::traceBitCast(BitCastInst *BitCast, 5758bcb0991SDimitry Andric CallInst *Parent, 5768bcb0991SDimitry Andric CallInfo &ParentInfo) { 5770b57cec5SDimitry Andric for (User *U : BitCast->users()) { 5780b57cec5SDimitry Andric Instruction *Inst = dyn_cast<Instruction>(U); 5790b57cec5SDimitry Andric if (!Inst) 5800b57cec5SDimitry Andric continue; 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric if (auto *BI = dyn_cast<BitCastInst>(Inst)) { 5838bcb0991SDimitry Andric traceBitCast(BI, Parent, ParentInfo); 5840b57cec5SDimitry Andric } else if (auto *CI = dyn_cast<CallInst>(Inst)) { 5858bcb0991SDimitry Andric CallInfo ChildInfo; 5868bcb0991SDimitry Andric if (IsPreserveDIAccessIndexCall(CI, ChildInfo) && 5878bcb0991SDimitry Andric IsValidAIChain(ParentInfo.Metadata, ParentInfo.AccessIndex, 5888bcb0991SDimitry Andric ChildInfo.Metadata)) { 5898bcb0991SDimitry Andric AIChain[CI] = std::make_pair(Parent, ParentInfo); 5908bcb0991SDimitry Andric traceAICall(CI, ChildInfo); 5910b57cec5SDimitry Andric } else { 5928bcb0991SDimitry Andric BaseAICalls[Parent] = ParentInfo; 5930b57cec5SDimitry Andric } 5940b57cec5SDimitry Andric } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) { 5950b57cec5SDimitry Andric if (GI->hasAllZeroIndices()) 5968bcb0991SDimitry Andric traceGEP(GI, Parent, ParentInfo); 5970b57cec5SDimitry Andric else 5988bcb0991SDimitry Andric BaseAICalls[Parent] = ParentInfo; 5998bcb0991SDimitry Andric } else { 6008bcb0991SDimitry Andric BaseAICalls[Parent] = ParentInfo; 6010b57cec5SDimitry Andric } 6020b57cec5SDimitry Andric } 6030b57cec5SDimitry Andric } 6040b57cec5SDimitry Andric 6050b57cec5SDimitry Andric void BPFAbstractMemberAccess::traceGEP(GetElementPtrInst *GEP, CallInst *Parent, 6068bcb0991SDimitry Andric CallInfo &ParentInfo) { 6070b57cec5SDimitry Andric for (User *U : GEP->users()) { 6080b57cec5SDimitry Andric Instruction *Inst = dyn_cast<Instruction>(U); 6090b57cec5SDimitry Andric if (!Inst) 6100b57cec5SDimitry Andric continue; 6110b57cec5SDimitry Andric 6120b57cec5SDimitry Andric if (auto *BI = dyn_cast<BitCastInst>(Inst)) { 6138bcb0991SDimitry Andric traceBitCast(BI, Parent, ParentInfo); 6140b57cec5SDimitry Andric } else if (auto *CI = dyn_cast<CallInst>(Inst)) { 6158bcb0991SDimitry Andric CallInfo ChildInfo; 6168bcb0991SDimitry Andric if (IsPreserveDIAccessIndexCall(CI, ChildInfo) && 6178bcb0991SDimitry Andric IsValidAIChain(ParentInfo.Metadata, ParentInfo.AccessIndex, 6188bcb0991SDimitry Andric ChildInfo.Metadata)) { 6198bcb0991SDimitry Andric AIChain[CI] = std::make_pair(Parent, ParentInfo); 6208bcb0991SDimitry Andric traceAICall(CI, ChildInfo); 6210b57cec5SDimitry Andric } else { 6228bcb0991SDimitry Andric BaseAICalls[Parent] = ParentInfo; 6230b57cec5SDimitry Andric } 6240b57cec5SDimitry Andric } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) { 6250b57cec5SDimitry Andric if (GI->hasAllZeroIndices()) 6268bcb0991SDimitry Andric traceGEP(GI, Parent, ParentInfo); 6270b57cec5SDimitry Andric else 6288bcb0991SDimitry Andric BaseAICalls[Parent] = ParentInfo; 6298bcb0991SDimitry Andric } else { 6308bcb0991SDimitry Andric BaseAICalls[Parent] = ParentInfo; 6310b57cec5SDimitry Andric } 6320b57cec5SDimitry Andric } 6330b57cec5SDimitry Andric } 6340b57cec5SDimitry Andric 635e8d8bef9SDimitry Andric void BPFAbstractMemberAccess::collectAICallChains(Function &F) { 6360b57cec5SDimitry Andric AIChain.clear(); 6370b57cec5SDimitry Andric BaseAICalls.clear(); 6380b57cec5SDimitry Andric 6390b57cec5SDimitry Andric for (auto &BB : F) 6400b57cec5SDimitry Andric for (auto &I : BB) { 6418bcb0991SDimitry Andric CallInfo CInfo; 6420b57cec5SDimitry Andric auto *Call = dyn_cast<CallInst>(&I); 6438bcb0991SDimitry Andric if (!IsPreserveDIAccessIndexCall(Call, CInfo) || 6440b57cec5SDimitry Andric AIChain.find(Call) != AIChain.end()) 6450b57cec5SDimitry Andric continue; 6460b57cec5SDimitry Andric 6478bcb0991SDimitry Andric traceAICall(Call, CInfo); 6480b57cec5SDimitry Andric } 6490b57cec5SDimitry Andric } 6500b57cec5SDimitry Andric 6518bcb0991SDimitry Andric /// Get the start and the end of storage offset for \p MemberTy. 652480093f4SDimitry Andric void BPFAbstractMemberAccess::GetStorageBitRange(DIDerivedType *MemberTy, 6535ffd83dbSDimitry Andric Align RecordAlignment, 6548bcb0991SDimitry Andric uint32_t &StartBitOffset, 6558bcb0991SDimitry Andric uint32_t &EndBitOffset) { 656480093f4SDimitry Andric uint32_t MemberBitSize = MemberTy->getSizeInBits(); 657480093f4SDimitry Andric uint32_t MemberBitOffset = MemberTy->getOffsetInBits(); 65881ad6265SDimitry Andric 65981ad6265SDimitry Andric if (RecordAlignment > 8) { 66081ad6265SDimitry Andric // If the Bits are within an aligned 8-byte, set the RecordAlignment 66181ad6265SDimitry Andric // to 8, other report the fatal error. 66281ad6265SDimitry Andric if (MemberBitOffset / 64 != (MemberBitOffset + MemberBitSize) / 64) 663480093f4SDimitry Andric report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info, " 664480093f4SDimitry Andric "requiring too big alignment"); 66581ad6265SDimitry Andric RecordAlignment = Align(8); 66681ad6265SDimitry Andric } 66781ad6265SDimitry Andric 66881ad6265SDimitry Andric uint32_t AlignBits = RecordAlignment.value() * 8; 66981ad6265SDimitry Andric if (MemberBitSize > AlignBits) 67081ad6265SDimitry Andric report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info, " 67181ad6265SDimitry Andric "bitfield size greater than record alignment"); 6728bcb0991SDimitry Andric 673480093f4SDimitry Andric StartBitOffset = MemberBitOffset & ~(AlignBits - 1); 674480093f4SDimitry Andric if ((StartBitOffset + AlignBits) < (MemberBitOffset + MemberBitSize)) 675480093f4SDimitry Andric report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info, " 676480093f4SDimitry Andric "cross alignment boundary"); 677480093f4SDimitry Andric EndBitOffset = StartBitOffset + AlignBits; 6788bcb0991SDimitry Andric } 6798bcb0991SDimitry Andric 6808bcb0991SDimitry Andric uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind, 6818bcb0991SDimitry Andric DICompositeType *CTy, 6828bcb0991SDimitry Andric uint32_t AccessIndex, 683480093f4SDimitry Andric uint32_t PatchImm, 68481ad6265SDimitry Andric MaybeAlign RecordAlignment) { 6855f757f3fSDimitry Andric if (InfoKind == BTF::FIELD_EXISTENCE) 6868bcb0991SDimitry Andric return 1; 6878bcb0991SDimitry Andric 6888bcb0991SDimitry Andric uint32_t Tag = CTy->getTag(); 6895f757f3fSDimitry Andric if (InfoKind == BTF::FIELD_BYTE_OFFSET) { 6908bcb0991SDimitry Andric if (Tag == dwarf::DW_TAG_array_type) { 6918bcb0991SDimitry Andric auto *EltTy = stripQualifiers(CTy->getBaseType()); 6928bcb0991SDimitry Andric PatchImm += AccessIndex * calcArraySize(CTy, 1) * 6938bcb0991SDimitry Andric (EltTy->getSizeInBits() >> 3); 6948bcb0991SDimitry Andric } else if (Tag == dwarf::DW_TAG_structure_type) { 6958bcb0991SDimitry Andric auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]); 6968bcb0991SDimitry Andric if (!MemberTy->isBitField()) { 6978bcb0991SDimitry Andric PatchImm += MemberTy->getOffsetInBits() >> 3; 6988bcb0991SDimitry Andric } else { 699480093f4SDimitry Andric unsigned SBitOffset, NextSBitOffset; 70081ad6265SDimitry Andric GetStorageBitRange(MemberTy, *RecordAlignment, SBitOffset, 701480093f4SDimitry Andric NextSBitOffset); 702480093f4SDimitry Andric PatchImm += SBitOffset >> 3; 7038bcb0991SDimitry Andric } 7048bcb0991SDimitry Andric } 7058bcb0991SDimitry Andric return PatchImm; 7068bcb0991SDimitry Andric } 7078bcb0991SDimitry Andric 7085f757f3fSDimitry Andric if (InfoKind == BTF::FIELD_BYTE_SIZE) { 7098bcb0991SDimitry Andric if (Tag == dwarf::DW_TAG_array_type) { 7108bcb0991SDimitry Andric auto *EltTy = stripQualifiers(CTy->getBaseType()); 7118bcb0991SDimitry Andric return calcArraySize(CTy, 1) * (EltTy->getSizeInBits() >> 3); 7128bcb0991SDimitry Andric } else { 7138bcb0991SDimitry Andric auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]); 7148bcb0991SDimitry Andric uint32_t SizeInBits = MemberTy->getSizeInBits(); 7158bcb0991SDimitry Andric if (!MemberTy->isBitField()) 7168bcb0991SDimitry Andric return SizeInBits >> 3; 7178bcb0991SDimitry Andric 7188bcb0991SDimitry Andric unsigned SBitOffset, NextSBitOffset; 71981ad6265SDimitry Andric GetStorageBitRange(MemberTy, *RecordAlignment, SBitOffset, 72081ad6265SDimitry Andric NextSBitOffset); 7218bcb0991SDimitry Andric SizeInBits = NextSBitOffset - SBitOffset; 7228bcb0991SDimitry Andric if (SizeInBits & (SizeInBits - 1)) 7238bcb0991SDimitry Andric report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info"); 7248bcb0991SDimitry Andric return SizeInBits >> 3; 7258bcb0991SDimitry Andric } 7268bcb0991SDimitry Andric } 7278bcb0991SDimitry Andric 7285f757f3fSDimitry Andric if (InfoKind == BTF::FIELD_SIGNEDNESS) { 7298bcb0991SDimitry Andric const DIType *BaseTy; 7308bcb0991SDimitry Andric if (Tag == dwarf::DW_TAG_array_type) { 7318bcb0991SDimitry Andric // Signedness only checked when final array elements are accessed. 7328bcb0991SDimitry Andric if (CTy->getElements().size() != 1) 7338bcb0991SDimitry Andric report_fatal_error("Invalid array expression for llvm.bpf.preserve.field.info"); 7348bcb0991SDimitry Andric BaseTy = stripQualifiers(CTy->getBaseType()); 7358bcb0991SDimitry Andric } else { 7368bcb0991SDimitry Andric auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]); 7378bcb0991SDimitry Andric BaseTy = stripQualifiers(MemberTy->getBaseType()); 7388bcb0991SDimitry Andric } 7398bcb0991SDimitry Andric 7408bcb0991SDimitry Andric // Only basic types and enum types have signedness. 7418bcb0991SDimitry Andric const auto *BTy = dyn_cast<DIBasicType>(BaseTy); 7428bcb0991SDimitry Andric while (!BTy) { 7438bcb0991SDimitry Andric const auto *CompTy = dyn_cast<DICompositeType>(BaseTy); 7448bcb0991SDimitry Andric // Report an error if the field expression does not have signedness. 7458bcb0991SDimitry Andric if (!CompTy || CompTy->getTag() != dwarf::DW_TAG_enumeration_type) 7468bcb0991SDimitry Andric report_fatal_error("Invalid field expression for llvm.bpf.preserve.field.info"); 7478bcb0991SDimitry Andric BaseTy = stripQualifiers(CompTy->getBaseType()); 7488bcb0991SDimitry Andric BTy = dyn_cast<DIBasicType>(BaseTy); 7498bcb0991SDimitry Andric } 7508bcb0991SDimitry Andric uint32_t Encoding = BTy->getEncoding(); 7518bcb0991SDimitry Andric return (Encoding == dwarf::DW_ATE_signed || Encoding == dwarf::DW_ATE_signed_char); 7528bcb0991SDimitry Andric } 7538bcb0991SDimitry Andric 7545f757f3fSDimitry Andric if (InfoKind == BTF::FIELD_LSHIFT_U64) { 7558bcb0991SDimitry Andric // The value is loaded into a value with FIELD_BYTE_SIZE size, 7568bcb0991SDimitry Andric // and then zero or sign extended to U64. 7578bcb0991SDimitry Andric // FIELD_LSHIFT_U64 and FIELD_RSHIFT_U64 are operations 7588bcb0991SDimitry Andric // to extract the original value. 7598bcb0991SDimitry Andric const Triple &Triple = TM->getTargetTriple(); 7608bcb0991SDimitry Andric DIDerivedType *MemberTy = nullptr; 7618bcb0991SDimitry Andric bool IsBitField = false; 7628bcb0991SDimitry Andric uint32_t SizeInBits; 7638bcb0991SDimitry Andric 7648bcb0991SDimitry Andric if (Tag == dwarf::DW_TAG_array_type) { 7658bcb0991SDimitry Andric auto *EltTy = stripQualifiers(CTy->getBaseType()); 7668bcb0991SDimitry Andric SizeInBits = calcArraySize(CTy, 1) * EltTy->getSizeInBits(); 7678bcb0991SDimitry Andric } else { 7688bcb0991SDimitry Andric MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]); 7698bcb0991SDimitry Andric SizeInBits = MemberTy->getSizeInBits(); 7708bcb0991SDimitry Andric IsBitField = MemberTy->isBitField(); 7718bcb0991SDimitry Andric } 7728bcb0991SDimitry Andric 7738bcb0991SDimitry Andric if (!IsBitField) { 7748bcb0991SDimitry Andric if (SizeInBits > 64) 7758bcb0991SDimitry Andric report_fatal_error("too big field size for llvm.bpf.preserve.field.info"); 7768bcb0991SDimitry Andric return 64 - SizeInBits; 7778bcb0991SDimitry Andric } 7788bcb0991SDimitry Andric 7798bcb0991SDimitry Andric unsigned SBitOffset, NextSBitOffset; 78081ad6265SDimitry Andric GetStorageBitRange(MemberTy, *RecordAlignment, SBitOffset, NextSBitOffset); 7818bcb0991SDimitry Andric if (NextSBitOffset - SBitOffset > 64) 7828bcb0991SDimitry Andric report_fatal_error("too big field size for llvm.bpf.preserve.field.info"); 7838bcb0991SDimitry Andric 7848bcb0991SDimitry Andric unsigned OffsetInBits = MemberTy->getOffsetInBits(); 7858bcb0991SDimitry Andric if (Triple.getArch() == Triple::bpfel) 7868bcb0991SDimitry Andric return SBitOffset + 64 - OffsetInBits - SizeInBits; 7878bcb0991SDimitry Andric else 7888bcb0991SDimitry Andric return OffsetInBits + 64 - NextSBitOffset; 7898bcb0991SDimitry Andric } 7908bcb0991SDimitry Andric 7915f757f3fSDimitry Andric if (InfoKind == BTF::FIELD_RSHIFT_U64) { 7928bcb0991SDimitry Andric DIDerivedType *MemberTy = nullptr; 7938bcb0991SDimitry Andric bool IsBitField = false; 7948bcb0991SDimitry Andric uint32_t SizeInBits; 7958bcb0991SDimitry Andric if (Tag == dwarf::DW_TAG_array_type) { 7968bcb0991SDimitry Andric auto *EltTy = stripQualifiers(CTy->getBaseType()); 7978bcb0991SDimitry Andric SizeInBits = calcArraySize(CTy, 1) * EltTy->getSizeInBits(); 7988bcb0991SDimitry Andric } else { 7998bcb0991SDimitry Andric MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]); 8008bcb0991SDimitry Andric SizeInBits = MemberTy->getSizeInBits(); 8018bcb0991SDimitry Andric IsBitField = MemberTy->isBitField(); 8028bcb0991SDimitry Andric } 8038bcb0991SDimitry Andric 8048bcb0991SDimitry Andric if (!IsBitField) { 8058bcb0991SDimitry Andric if (SizeInBits > 64) 8068bcb0991SDimitry Andric report_fatal_error("too big field size for llvm.bpf.preserve.field.info"); 8078bcb0991SDimitry Andric return 64 - SizeInBits; 8088bcb0991SDimitry Andric } 8098bcb0991SDimitry Andric 8108bcb0991SDimitry Andric unsigned SBitOffset, NextSBitOffset; 81181ad6265SDimitry Andric GetStorageBitRange(MemberTy, *RecordAlignment, SBitOffset, NextSBitOffset); 8128bcb0991SDimitry Andric if (NextSBitOffset - SBitOffset > 64) 8138bcb0991SDimitry Andric report_fatal_error("too big field size for llvm.bpf.preserve.field.info"); 8148bcb0991SDimitry Andric 8158bcb0991SDimitry Andric return 64 - SizeInBits; 8168bcb0991SDimitry Andric } 8178bcb0991SDimitry Andric 8188bcb0991SDimitry Andric llvm_unreachable("Unknown llvm.bpf.preserve.field.info info kind"); 8198bcb0991SDimitry Andric } 8208bcb0991SDimitry Andric 8218bcb0991SDimitry Andric bool BPFAbstractMemberAccess::HasPreserveFieldInfoCall(CallInfoStack &CallStack) { 8228bcb0991SDimitry Andric // This is called in error return path, no need to maintain CallStack. 8238bcb0991SDimitry Andric while (CallStack.size()) { 8248bcb0991SDimitry Andric auto StackElem = CallStack.top(); 8258bcb0991SDimitry Andric if (StackElem.second.Kind == BPFPreserveFieldInfoAI) 8268bcb0991SDimitry Andric return true; 8278bcb0991SDimitry Andric CallStack.pop(); 8288bcb0991SDimitry Andric } 8298bcb0991SDimitry Andric return false; 8308bcb0991SDimitry Andric } 8318bcb0991SDimitry Andric 8328bcb0991SDimitry Andric /// Compute the base of the whole preserve_* intrinsics chains, i.e., the base 8330b57cec5SDimitry Andric /// pointer of the first preserve_*_access_index call, and construct the access 8340b57cec5SDimitry Andric /// string, which will be the name of a global variable. 8350b57cec5SDimitry Andric Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call, 8368bcb0991SDimitry Andric CallInfo &CInfo, 8370b57cec5SDimitry Andric std::string &AccessKey, 8380b57cec5SDimitry Andric MDNode *&TypeMeta) { 8390b57cec5SDimitry Andric Value *Base = nullptr; 8400b57cec5SDimitry Andric std::string TypeName; 8418bcb0991SDimitry Andric CallInfoStack CallStack; 8420b57cec5SDimitry Andric 8438bcb0991SDimitry Andric // Put the access chain into a stack with the top as the head of the chain. 8448bcb0991SDimitry Andric while (Call) { 8458bcb0991SDimitry Andric CallStack.push(std::make_pair(Call, CInfo)); 8468bcb0991SDimitry Andric CInfo = AIChain[Call].second; 8470b57cec5SDimitry Andric Call = AIChain[Call].first; 8480b57cec5SDimitry Andric } 8490b57cec5SDimitry Andric 8508bcb0991SDimitry Andric // The access offset from the base of the head of chain is also 8518bcb0991SDimitry Andric // calculated here as all debuginfo types are available. 8528bcb0991SDimitry Andric 8538bcb0991SDimitry Andric // Get type name and calculate the first index. 8545ffd83dbSDimitry Andric // We only want to get type name from typedef, structure or union. 8558bcb0991SDimitry Andric // If user wants a relocation like 8568bcb0991SDimitry Andric // int *p; ... __builtin_preserve_access_index(&p[4]) ... 8578bcb0991SDimitry Andric // or 8588bcb0991SDimitry Andric // int a[10][20]; ... __builtin_preserve_access_index(&a[2][3]) ... 8598bcb0991SDimitry Andric // we will skip them. 8608bcb0991SDimitry Andric uint32_t FirstIndex = 0; 8618bcb0991SDimitry Andric uint32_t PatchImm = 0; // AccessOffset or the requested field info 8625f757f3fSDimitry Andric uint32_t InfoKind = BTF::FIELD_BYTE_OFFSET; 8638bcb0991SDimitry Andric while (CallStack.size()) { 8648bcb0991SDimitry Andric auto StackElem = CallStack.top(); 8658bcb0991SDimitry Andric Call = StackElem.first; 8668bcb0991SDimitry Andric CInfo = StackElem.second; 8678bcb0991SDimitry Andric 8688bcb0991SDimitry Andric if (!Base) 8698bcb0991SDimitry Andric Base = CInfo.Base; 8708bcb0991SDimitry Andric 8715ffd83dbSDimitry Andric DIType *PossibleTypeDef = stripQualifiers(cast<DIType>(CInfo.Metadata), 8725ffd83dbSDimitry Andric false); 8735ffd83dbSDimitry Andric DIType *Ty = stripQualifiers(PossibleTypeDef); 8748bcb0991SDimitry Andric if (CInfo.Kind == BPFPreserveUnionAI || 8758bcb0991SDimitry Andric CInfo.Kind == BPFPreserveStructAI) { 8765ffd83dbSDimitry Andric // struct or union type. If the typedef is in the metadata, always 8775ffd83dbSDimitry Andric // use the typedef. 8785ffd83dbSDimitry Andric TypeName = std::string(PossibleTypeDef->getName()); 8795ffd83dbSDimitry Andric TypeMeta = PossibleTypeDef; 8808bcb0991SDimitry Andric PatchImm += FirstIndex * (Ty->getSizeInBits() >> 3); 8818bcb0991SDimitry Andric break; 8828bcb0991SDimitry Andric } 8838bcb0991SDimitry Andric 8848bcb0991SDimitry Andric assert(CInfo.Kind == BPFPreserveArrayAI); 8858bcb0991SDimitry Andric 8868bcb0991SDimitry Andric // Array entries will always be consumed for accumulative initial index. 8878bcb0991SDimitry Andric CallStack.pop(); 8888bcb0991SDimitry Andric 8898bcb0991SDimitry Andric // BPFPreserveArrayAI 8908bcb0991SDimitry Andric uint64_t AccessIndex = CInfo.AccessIndex; 8918bcb0991SDimitry Andric 8928bcb0991SDimitry Andric DIType *BaseTy = nullptr; 8938bcb0991SDimitry Andric bool CheckElemType = false; 8948bcb0991SDimitry Andric if (const auto *CTy = dyn_cast<DICompositeType>(Ty)) { 8958bcb0991SDimitry Andric // array type 8968bcb0991SDimitry Andric assert(CTy->getTag() == dwarf::DW_TAG_array_type); 8978bcb0991SDimitry Andric 8988bcb0991SDimitry Andric 8998bcb0991SDimitry Andric FirstIndex += AccessIndex * calcArraySize(CTy, 1); 9008bcb0991SDimitry Andric BaseTy = stripQualifiers(CTy->getBaseType()); 9018bcb0991SDimitry Andric CheckElemType = CTy->getElements().size() == 1; 9028bcb0991SDimitry Andric } else { 9038bcb0991SDimitry Andric // pointer type 9048bcb0991SDimitry Andric auto *DTy = cast<DIDerivedType>(Ty); 9058bcb0991SDimitry Andric assert(DTy->getTag() == dwarf::DW_TAG_pointer_type); 9068bcb0991SDimitry Andric 9078bcb0991SDimitry Andric BaseTy = stripQualifiers(DTy->getBaseType()); 9088bcb0991SDimitry Andric CTy = dyn_cast<DICompositeType>(BaseTy); 9098bcb0991SDimitry Andric if (!CTy) { 9108bcb0991SDimitry Andric CheckElemType = true; 9118bcb0991SDimitry Andric } else if (CTy->getTag() != dwarf::DW_TAG_array_type) { 9128bcb0991SDimitry Andric FirstIndex += AccessIndex; 9138bcb0991SDimitry Andric CheckElemType = true; 9148bcb0991SDimitry Andric } else { 9158bcb0991SDimitry Andric FirstIndex += AccessIndex * calcArraySize(CTy, 0); 9168bcb0991SDimitry Andric } 9178bcb0991SDimitry Andric } 9188bcb0991SDimitry Andric 9198bcb0991SDimitry Andric if (CheckElemType) { 9208bcb0991SDimitry Andric auto *CTy = dyn_cast<DICompositeType>(BaseTy); 9218bcb0991SDimitry Andric if (!CTy) { 9228bcb0991SDimitry Andric if (HasPreserveFieldInfoCall(CallStack)) 9238bcb0991SDimitry Andric report_fatal_error("Invalid field access for llvm.preserve.field.info intrinsic"); 9240b57cec5SDimitry Andric return nullptr; 9258bcb0991SDimitry Andric } 9260b57cec5SDimitry Andric 9278bcb0991SDimitry Andric unsigned CTag = CTy->getTag(); 9288bcb0991SDimitry Andric if (CTag == dwarf::DW_TAG_structure_type || CTag == dwarf::DW_TAG_union_type) { 9295ffd83dbSDimitry Andric TypeName = std::string(CTy->getName()); 9308bcb0991SDimitry Andric } else { 9318bcb0991SDimitry Andric if (HasPreserveFieldInfoCall(CallStack)) 9328bcb0991SDimitry Andric report_fatal_error("Invalid field access for llvm.preserve.field.info intrinsic"); 9338bcb0991SDimitry Andric return nullptr; 9348bcb0991SDimitry Andric } 9358bcb0991SDimitry Andric TypeMeta = CTy; 9368bcb0991SDimitry Andric PatchImm += FirstIndex * (CTy->getSizeInBits() >> 3); 9378bcb0991SDimitry Andric break; 9388bcb0991SDimitry Andric } 9398bcb0991SDimitry Andric } 9408bcb0991SDimitry Andric assert(TypeName.size()); 9418bcb0991SDimitry Andric AccessKey += std::to_string(FirstIndex); 9420b57cec5SDimitry Andric 9438bcb0991SDimitry Andric // Traverse the rest of access chain to complete offset calculation 9448bcb0991SDimitry Andric // and access key construction. 9458bcb0991SDimitry Andric while (CallStack.size()) { 9468bcb0991SDimitry Andric auto StackElem = CallStack.top(); 9478bcb0991SDimitry Andric CInfo = StackElem.second; 9488bcb0991SDimitry Andric CallStack.pop(); 9490b57cec5SDimitry Andric 9505ffd83dbSDimitry Andric if (CInfo.Kind == BPFPreserveFieldInfoAI) { 9515ffd83dbSDimitry Andric InfoKind = CInfo.AccessIndex; 9525f757f3fSDimitry Andric if (InfoKind == BTF::FIELD_EXISTENCE) 953fe6060f1SDimitry Andric PatchImm = 1; 9548bcb0991SDimitry Andric break; 9555ffd83dbSDimitry Andric } 9568bcb0991SDimitry Andric 9578bcb0991SDimitry Andric // If the next Call (the top of the stack) is a BPFPreserveFieldInfoAI, 9588bcb0991SDimitry Andric // the action will be extracting field info. 9598bcb0991SDimitry Andric if (CallStack.size()) { 9608bcb0991SDimitry Andric auto StackElem2 = CallStack.top(); 9618bcb0991SDimitry Andric CallInfo CInfo2 = StackElem2.second; 9628bcb0991SDimitry Andric if (CInfo2.Kind == BPFPreserveFieldInfoAI) { 9638bcb0991SDimitry Andric InfoKind = CInfo2.AccessIndex; 9648bcb0991SDimitry Andric assert(CallStack.size() == 1); 9658bcb0991SDimitry Andric } 9668bcb0991SDimitry Andric } 9678bcb0991SDimitry Andric 9688bcb0991SDimitry Andric // Access Index 9698bcb0991SDimitry Andric uint64_t AccessIndex = CInfo.AccessIndex; 9708bcb0991SDimitry Andric AccessKey += ":" + std::to_string(AccessIndex); 9718bcb0991SDimitry Andric 9728bcb0991SDimitry Andric MDNode *MDN = CInfo.Metadata; 9738bcb0991SDimitry Andric // At this stage, it cannot be pointer type. 9748bcb0991SDimitry Andric auto *CTy = cast<DICompositeType>(stripQualifiers(cast<DIType>(MDN))); 975480093f4SDimitry Andric PatchImm = GetFieldInfo(InfoKind, CTy, AccessIndex, PatchImm, 9765ffd83dbSDimitry Andric CInfo.RecordAlignment); 9778bcb0991SDimitry Andric } 9788bcb0991SDimitry Andric 979480093f4SDimitry Andric // Access key is the 980480093f4SDimitry Andric // "llvm." + type name + ":" + reloc type + ":" + patched imm + "$" + 981480093f4SDimitry Andric // access string, 9828bcb0991SDimitry Andric // uniquely identifying one relocation. 983480093f4SDimitry Andric // The prefix "llvm." indicates this is a temporary global, which should 984480093f4SDimitry Andric // not be emitted to ELF file. 985480093f4SDimitry Andric AccessKey = "llvm." + TypeName + ":" + std::to_string(InfoKind) + ":" + 9868bcb0991SDimitry Andric std::to_string(PatchImm) + "$" + AccessKey; 9870b57cec5SDimitry Andric 9880b57cec5SDimitry Andric return Base; 9890b57cec5SDimitry Andric } 9900b57cec5SDimitry Andric 991e8d8bef9SDimitry Andric MDNode *BPFAbstractMemberAccess::computeAccessKey(CallInst *Call, 992e8d8bef9SDimitry Andric CallInfo &CInfo, 993e8d8bef9SDimitry Andric std::string &AccessKey, 994e8d8bef9SDimitry Andric bool &IsInt32Ret) { 995e8d8bef9SDimitry Andric DIType *Ty = stripQualifiers(cast<DIType>(CInfo.Metadata), false); 996e8d8bef9SDimitry Andric assert(!Ty->getName().empty()); 997e8d8bef9SDimitry Andric 998e8d8bef9SDimitry Andric int64_t PatchImm; 999e8d8bef9SDimitry Andric std::string AccessStr("0"); 10005f757f3fSDimitry Andric if (CInfo.AccessIndex == BTF::TYPE_EXISTENCE || 10015f757f3fSDimitry Andric CInfo.AccessIndex == BTF::TYPE_MATCH) { 1002e8d8bef9SDimitry Andric PatchImm = 1; 10035f757f3fSDimitry Andric } else if (CInfo.AccessIndex == BTF::TYPE_SIZE) { 1004e8d8bef9SDimitry Andric // typedef debuginfo type has size 0, get the eventual base type. 1005e8d8bef9SDimitry Andric DIType *BaseTy = stripQualifiers(Ty, true); 1006e8d8bef9SDimitry Andric PatchImm = BaseTy->getSizeInBits() / 8; 1007e8d8bef9SDimitry Andric } else { 1008e8d8bef9SDimitry Andric // ENUM_VALUE_EXISTENCE and ENUM_VALUE 1009e8d8bef9SDimitry Andric IsInt32Ret = false; 1010e8d8bef9SDimitry Andric 101181ad6265SDimitry Andric // The argument could be a global variable or a getelementptr with base to 101281ad6265SDimitry Andric // a global variable depending on whether the clang option `opaque-options` 101381ad6265SDimitry Andric // is set or not. 101481ad6265SDimitry Andric const GlobalVariable *GV = 101581ad6265SDimitry Andric cast<GlobalVariable>(Call->getArgOperand(1)->stripPointerCasts()); 1016e8d8bef9SDimitry Andric assert(GV->hasInitializer()); 1017e8d8bef9SDimitry Andric const ConstantDataArray *DA = cast<ConstantDataArray>(GV->getInitializer()); 1018e8d8bef9SDimitry Andric assert(DA->isString()); 1019e8d8bef9SDimitry Andric StringRef ValueStr = DA->getAsString(); 1020e8d8bef9SDimitry Andric 1021e8d8bef9SDimitry Andric // ValueStr format: <EnumeratorStr>:<Value> 1022e8d8bef9SDimitry Andric size_t Separator = ValueStr.find_first_of(':'); 1023e8d8bef9SDimitry Andric StringRef EnumeratorStr = ValueStr.substr(0, Separator); 1024e8d8bef9SDimitry Andric 1025e8d8bef9SDimitry Andric // Find enumerator index in the debuginfo 1026e8d8bef9SDimitry Andric DIType *BaseTy = stripQualifiers(Ty, true); 1027e8d8bef9SDimitry Andric const auto *CTy = cast<DICompositeType>(BaseTy); 1028e8d8bef9SDimitry Andric assert(CTy->getTag() == dwarf::DW_TAG_enumeration_type); 1029e8d8bef9SDimitry Andric int EnumIndex = 0; 1030e8d8bef9SDimitry Andric for (const auto Element : CTy->getElements()) { 1031e8d8bef9SDimitry Andric const auto *Enum = cast<DIEnumerator>(Element); 1032e8d8bef9SDimitry Andric if (Enum->getName() == EnumeratorStr) { 1033e8d8bef9SDimitry Andric AccessStr = std::to_string(EnumIndex); 1034e8d8bef9SDimitry Andric break; 1035e8d8bef9SDimitry Andric } 1036e8d8bef9SDimitry Andric EnumIndex++; 1037e8d8bef9SDimitry Andric } 1038e8d8bef9SDimitry Andric 10395f757f3fSDimitry Andric if (CInfo.AccessIndex == BTF::ENUM_VALUE) { 1040e8d8bef9SDimitry Andric StringRef EValueStr = ValueStr.substr(Separator + 1); 1041e8d8bef9SDimitry Andric PatchImm = std::stoll(std::string(EValueStr)); 1042e8d8bef9SDimitry Andric } else { 1043e8d8bef9SDimitry Andric PatchImm = 1; 1044e8d8bef9SDimitry Andric } 1045e8d8bef9SDimitry Andric } 1046e8d8bef9SDimitry Andric 1047e8d8bef9SDimitry Andric AccessKey = "llvm." + Ty->getName().str() + ":" + 1048e8d8bef9SDimitry Andric std::to_string(CInfo.AccessIndex) + std::string(":") + 1049e8d8bef9SDimitry Andric std::to_string(PatchImm) + std::string("$") + AccessStr; 1050e8d8bef9SDimitry Andric 1051e8d8bef9SDimitry Andric return Ty; 1052e8d8bef9SDimitry Andric } 1053e8d8bef9SDimitry Andric 10540b57cec5SDimitry Andric /// Call/Kind is the base preserve_*_access_index() call. Attempts to do 10550b57cec5SDimitry Andric /// transformation to a chain of relocable GEPs. 1056e8d8bef9SDimitry Andric bool BPFAbstractMemberAccess::transformGEPChain(CallInst *Call, 10578bcb0991SDimitry Andric CallInfo &CInfo) { 10580b57cec5SDimitry Andric std::string AccessKey; 10598bcb0991SDimitry Andric MDNode *TypeMeta; 1060e8d8bef9SDimitry Andric Value *Base = nullptr; 1061e8d8bef9SDimitry Andric bool IsInt32Ret; 1062e8d8bef9SDimitry Andric 1063e8d8bef9SDimitry Andric IsInt32Ret = CInfo.Kind == BPFPreserveFieldInfoAI; 1064e8d8bef9SDimitry Andric if (CInfo.Kind == BPFPreserveFieldInfoAI && CInfo.Metadata) { 1065e8d8bef9SDimitry Andric TypeMeta = computeAccessKey(Call, CInfo, AccessKey, IsInt32Ret); 1066e8d8bef9SDimitry Andric } else { 1067e8d8bef9SDimitry Andric Base = computeBaseAndAccessKey(Call, CInfo, AccessKey, TypeMeta); 10680b57cec5SDimitry Andric if (!Base) 10690b57cec5SDimitry Andric return false; 1070e8d8bef9SDimitry Andric } 10710b57cec5SDimitry Andric 10720b57cec5SDimitry Andric BasicBlock *BB = Call->getParent(); 10730b57cec5SDimitry Andric GlobalVariable *GV; 10740b57cec5SDimitry Andric 10750b57cec5SDimitry Andric if (GEPGlobals.find(AccessKey) == GEPGlobals.end()) { 10768bcb0991SDimitry Andric IntegerType *VarType; 1077e8d8bef9SDimitry Andric if (IsInt32Ret) 10788bcb0991SDimitry Andric VarType = Type::getInt32Ty(BB->getContext()); // 32bit return value 10798bcb0991SDimitry Andric else 1080e8d8bef9SDimitry Andric VarType = Type::getInt64Ty(BB->getContext()); // 64bit ptr or enum value 10818bcb0991SDimitry Andric 1082e8d8bef9SDimitry Andric GV = new GlobalVariable(*M, VarType, false, GlobalVariable::ExternalLinkage, 108304eeddc0SDimitry Andric nullptr, AccessKey); 10840b57cec5SDimitry Andric GV->addAttribute(BPFCoreSharedInfo::AmaAttr); 10850b57cec5SDimitry Andric GV->setMetadata(LLVMContext::MD_preserve_access_index, TypeMeta); 10860b57cec5SDimitry Andric GEPGlobals[AccessKey] = GV; 10870b57cec5SDimitry Andric } else { 10880b57cec5SDimitry Andric GV = GEPGlobals[AccessKey]; 10890b57cec5SDimitry Andric } 10900b57cec5SDimitry Andric 10918bcb0991SDimitry Andric if (CInfo.Kind == BPFPreserveFieldInfoAI) { 10928bcb0991SDimitry Andric // Load the global variable which represents the returned field info. 1093e8d8bef9SDimitry Andric LoadInst *LDInst; 1094e8d8bef9SDimitry Andric if (IsInt32Ret) 1095*0fca6ea1SDimitry Andric LDInst = new LoadInst(Type::getInt32Ty(BB->getContext()), GV, "", 1096*0fca6ea1SDimitry Andric Call->getIterator()); 1097e8d8bef9SDimitry Andric else 1098*0fca6ea1SDimitry Andric LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV, "", 1099*0fca6ea1SDimitry Andric Call->getIterator()); 1100e8d8bef9SDimitry Andric 1101e8d8bef9SDimitry Andric Instruction *PassThroughInst = 1102e8d8bef9SDimitry Andric BPFCoreSharedInfo::insertPassThrough(M, BB, LDInst, Call); 1103e8d8bef9SDimitry Andric Call->replaceAllUsesWith(PassThroughInst); 11048bcb0991SDimitry Andric Call->eraseFromParent(); 11058bcb0991SDimitry Andric return true; 11068bcb0991SDimitry Andric } 11078bcb0991SDimitry Andric 11088bcb0991SDimitry Andric // For any original GEP Call and Base %2 like 11098bcb0991SDimitry Andric // %4 = bitcast %struct.net_device** %dev1 to i64* 11108bcb0991SDimitry Andric // it is transformed to: 1111e8d8bef9SDimitry Andric // %6 = load llvm.sk_buff:0:50$0:0:0:2:0 11128bcb0991SDimitry Andric // %7 = bitcast %struct.sk_buff* %2 to i8* 11138bcb0991SDimitry Andric // %8 = getelementptr i8, i8* %7, %6 11148bcb0991SDimitry Andric // %9 = bitcast i8* %8 to i64* 11158bcb0991SDimitry Andric // using %9 instead of %4 11168bcb0991SDimitry Andric // The original Call inst is removed. 11178bcb0991SDimitry Andric 11180b57cec5SDimitry Andric // Load the global variable. 1119*0fca6ea1SDimitry Andric auto *LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV, "", 1120*0fca6ea1SDimitry Andric Call->getIterator()); 11210b57cec5SDimitry Andric 11220b57cec5SDimitry Andric // Generate a BitCast 11235f757f3fSDimitry Andric auto *BCInst = 11245f757f3fSDimitry Andric new BitCastInst(Base, PointerType::getUnqual(BB->getContext())); 1125bdd1243dSDimitry Andric BCInst->insertBefore(Call); 11260b57cec5SDimitry Andric 11270b57cec5SDimitry Andric // Generate a GetElementPtr 11280b57cec5SDimitry Andric auto *GEP = GetElementPtrInst::Create(Type::getInt8Ty(BB->getContext()), 11290b57cec5SDimitry Andric BCInst, LDInst); 1130bdd1243dSDimitry Andric GEP->insertBefore(Call); 11310b57cec5SDimitry Andric 11320b57cec5SDimitry Andric // Generate a BitCast 11330b57cec5SDimitry Andric auto *BCInst2 = new BitCastInst(GEP, Call->getType()); 1134bdd1243dSDimitry Andric BCInst2->insertBefore(Call); 11350b57cec5SDimitry Andric 1136e8d8bef9SDimitry Andric // For the following code, 1137e8d8bef9SDimitry Andric // Block0: 1138e8d8bef9SDimitry Andric // ... 1139e8d8bef9SDimitry Andric // if (...) goto Block1 else ... 1140e8d8bef9SDimitry Andric // Block1: 1141e8d8bef9SDimitry Andric // %6 = load llvm.sk_buff:0:50$0:0:0:2:0 1142e8d8bef9SDimitry Andric // %7 = bitcast %struct.sk_buff* %2 to i8* 1143e8d8bef9SDimitry Andric // %8 = getelementptr i8, i8* %7, %6 1144e8d8bef9SDimitry Andric // ... 1145e8d8bef9SDimitry Andric // goto CommonExit 1146e8d8bef9SDimitry Andric // Block2: 1147e8d8bef9SDimitry Andric // ... 1148e8d8bef9SDimitry Andric // if (...) goto Block3 else ... 1149e8d8bef9SDimitry Andric // Block3: 1150e8d8bef9SDimitry Andric // %6 = load llvm.bpf_map:0:40$0:0:0:2:0 1151e8d8bef9SDimitry Andric // %7 = bitcast %struct.sk_buff* %2 to i8* 1152e8d8bef9SDimitry Andric // %8 = getelementptr i8, i8* %7, %6 1153e8d8bef9SDimitry Andric // ... 1154e8d8bef9SDimitry Andric // goto CommonExit 1155e8d8bef9SDimitry Andric // CommonExit 1156e8d8bef9SDimitry Andric // SimplifyCFG may generate: 1157e8d8bef9SDimitry Andric // Block0: 1158e8d8bef9SDimitry Andric // ... 1159e8d8bef9SDimitry Andric // if (...) goto Block_Common else ... 1160e8d8bef9SDimitry Andric // Block2: 1161e8d8bef9SDimitry Andric // ... 1162e8d8bef9SDimitry Andric // if (...) goto Block_Common else ... 1163e8d8bef9SDimitry Andric // Block_Common: 1164e8d8bef9SDimitry Andric // PHI = [llvm.sk_buff:0:50$0:0:0:2:0, llvm.bpf_map:0:40$0:0:0:2:0] 1165e8d8bef9SDimitry Andric // %6 = load PHI 1166e8d8bef9SDimitry Andric // %7 = bitcast %struct.sk_buff* %2 to i8* 1167e8d8bef9SDimitry Andric // %8 = getelementptr i8, i8* %7, %6 1168e8d8bef9SDimitry Andric // ... 1169e8d8bef9SDimitry Andric // goto CommonExit 1170e8d8bef9SDimitry Andric // For the above code, we cannot perform proper relocation since 1171e8d8bef9SDimitry Andric // "load PHI" has two possible relocations. 1172e8d8bef9SDimitry Andric // 1173e8d8bef9SDimitry Andric // To prevent above tail merging, we use __builtin_bpf_passthrough() 1174e8d8bef9SDimitry Andric // where one of its parameters is a seq_num. Since two 1175e8d8bef9SDimitry Andric // __builtin_bpf_passthrough() funcs will always have different seq_num, 1176e8d8bef9SDimitry Andric // tail merging cannot happen. The __builtin_bpf_passthrough() will be 1177e8d8bef9SDimitry Andric // removed in the beginning of Target IR passes. 1178e8d8bef9SDimitry Andric // 1179e8d8bef9SDimitry Andric // This approach is also used in other places when global var 1180e8d8bef9SDimitry Andric // representing a relocation is used. 1181e8d8bef9SDimitry Andric Instruction *PassThroughInst = 1182e8d8bef9SDimitry Andric BPFCoreSharedInfo::insertPassThrough(M, BB, BCInst2, Call); 1183e8d8bef9SDimitry Andric Call->replaceAllUsesWith(PassThroughInst); 11840b57cec5SDimitry Andric Call->eraseFromParent(); 11850b57cec5SDimitry Andric 11860b57cec5SDimitry Andric return true; 11870b57cec5SDimitry Andric } 11880b57cec5SDimitry Andric 1189e8d8bef9SDimitry Andric bool BPFAbstractMemberAccess::doTransformation(Function &F) { 11900b57cec5SDimitry Andric bool Transformed = false; 11910b57cec5SDimitry Andric 11920b57cec5SDimitry Andric // Collect PreserveDIAccessIndex Intrinsic call chains. 11930b57cec5SDimitry Andric // The call chains will be used to generate the access 11940b57cec5SDimitry Andric // patterns similar to GEP. 1195e8d8bef9SDimitry Andric collectAICallChains(F); 11960b57cec5SDimitry Andric 11970b57cec5SDimitry Andric for (auto &C : BaseAICalls) 1198e8d8bef9SDimitry Andric Transformed = transformGEPChain(C.first, C.second) || Transformed; 1199e8d8bef9SDimitry Andric 1200e8d8bef9SDimitry Andric return removePreserveAccessIndexIntrinsic(F) || Transformed; 12010b57cec5SDimitry Andric } 12020b57cec5SDimitry Andric 1203e8d8bef9SDimitry Andric PreservedAnalyses 1204e8d8bef9SDimitry Andric BPFAbstractMemberAccessPass::run(Function &F, FunctionAnalysisManager &AM) { 1205e8d8bef9SDimitry Andric return BPFAbstractMemberAccess(TM).run(F) ? PreservedAnalyses::none() 1206e8d8bef9SDimitry Andric : PreservedAnalyses::all(); 12070b57cec5SDimitry Andric } 1208