xref: /freebsd/contrib/llvm-project/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
insertPassThrough(Module * M,BasicBlock * BB,Instruction * Input,Instruction * Before)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:
BPFAbstractMemberAccess(BPFTargetMachine * TM)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 
run(Function & F)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 
ResetMetadata(struct CallInfo & CInfo)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 
CheckCompositeType(DIDerivedType * ParentTy,DICompositeType * CTy)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 
CheckDerivedType(DIDerivedType * ParentTy,DIDerivedType * DTy)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 
CheckAnonRecordType(DIDerivedType * ParentTy,DIType * Ty)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 
SkipDIDerivedTag(unsigned Tag,bool skipTypedef)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 
stripQualifiers(DIType * Ty,bool skipTypedef=true)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 
stripQualifiers(const DIType * Ty)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 
calcArraySize(const DICompositeType * CTy,uint32_t StartDim)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 
getBaseElementType(const CallInst * Call)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 
getConstant(const Value * IndexValue)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.
IsPreserveDIAccessIndexCall(const CallInst * Call,CallInfo & CInfo)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 
replaceWithGEP(CallInst * Call,uint32_t DimensionIndex,uint32_t GEPIndex)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 
removeArrayAccessCall(CallInst * Call)4365f757f3fSDimitry Andric void BPFCoreSharedInfo::removeArrayAccessCall(CallInst *Call) {
4375f757f3fSDimitry Andric   replaceWithGEP(Call, 1, 2);
4385f757f3fSDimitry Andric }
4395f757f3fSDimitry Andric 
removeStructAccessCall(CallInst * Call)4405f757f3fSDimitry Andric void BPFCoreSharedInfo::removeStructAccessCall(CallInst *Call) {
4415f757f3fSDimitry Andric   replaceWithGEP(Call, 0, 1);
4425f757f3fSDimitry Andric }
4435f757f3fSDimitry Andric 
removeUnionAccessCall(CallInst * Call)4445f757f3fSDimitry Andric void BPFCoreSharedInfo::removeUnionAccessCall(CallInst *Call) {
4455f757f3fSDimitry Andric   Call->replaceAllUsesWith(Call->getArgOperand(0));
4465f757f3fSDimitry Andric   Call->eraseFromParent();
4470b57cec5SDimitry Andric }
4480b57cec5SDimitry Andric 
removePreserveAccessIndexIntrinsic(Function & F)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.
IsValidAIChain(const MDNode * ParentType,uint32_t ParentAI,const MDNode * ChildType)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 
traceAICall(CallInst * Call,CallInfo & ParentInfo)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 
traceBitCast(BitCastInst * BitCast,CallInst * Parent,CallInfo & ParentInfo)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 
traceGEP(GetElementPtrInst * GEP,CallInst * Parent,CallInfo & ParentInfo)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 
collectAICallChains(Function & F)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.
GetStorageBitRange(DIDerivedType * MemberTy,Align RecordAlignment,uint32_t & StartBitOffset,uint32_t & EndBitOffset)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 
GetFieldInfo(uint32_t InfoKind,DICompositeType * CTy,uint32_t AccessIndex,uint32_t PatchImm,MaybeAlign RecordAlignment)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 
HasPreserveFieldInfoCall(CallInfoStack & CallStack)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.
computeBaseAndAccessKey(CallInst * Call,CallInfo & CInfo,std::string & AccessKey,MDNode * & TypeMeta)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 
computeAccessKey(CallInst * Call,CallInfo & CInfo,std::string & AccessKey,bool & IsInt32Ret)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.
transformGEPChain(CallInst * Call,CallInfo & CInfo)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 
doTransformation(Function & F)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
run(Function & F,FunctionAnalysisManager & AM)1204e8d8bef9SDimitry Andric BPFAbstractMemberAccessPass::run(Function &F, FunctionAnalysisManager &AM) {
1205e8d8bef9SDimitry Andric   return BPFAbstractMemberAccess(TM).run(F) ? PreservedAnalyses::none()
1206e8d8bef9SDimitry Andric                                             : PreservedAnalyses::all();
12070b57cec5SDimitry Andric }
1208