1a1b2a27aSYonghong Song //===------ BPFAbstractMemberAccess.cpp - Abstracting Member Accesses -----===//
2a1b2a27aSYonghong Song //
3a1b2a27aSYonghong Song // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a1b2a27aSYonghong Song // See https://llvm.org/LICENSE.txt for license information.
5a1b2a27aSYonghong Song // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a1b2a27aSYonghong Song //
7a1b2a27aSYonghong Song //===----------------------------------------------------------------------===//
8a1b2a27aSYonghong Song //
9a1b2a27aSYonghong Song // This pass abstracted struct/union member accesses in order to support
10a1b2a27aSYonghong Song // compile-once run-everywhere (CO-RE). The CO-RE intends to compile the program
11a1b2a27aSYonghong Song // which can run on different kernels. In particular, if bpf program tries to
12a1b2a27aSYonghong Song // access a particular kernel data structure member, the details of the
13a1b2a27aSYonghong Song // intermediate member access will be remembered so bpf loader can do
14a1b2a27aSYonghong Song // necessary adjustment right before program loading.
15a1b2a27aSYonghong Song //
16a1b2a27aSYonghong Song // For example,
17a1b2a27aSYonghong Song //
18a1b2a27aSYonghong Song //   struct s {
19a1b2a27aSYonghong Song //     int a;
20a1b2a27aSYonghong Song //     int b;
21a1b2a27aSYonghong Song //   };
22a1b2a27aSYonghong Song //   struct t {
23a1b2a27aSYonghong Song //     struct s c;
24a1b2a27aSYonghong Song //     int d;
25a1b2a27aSYonghong Song //   };
26a1b2a27aSYonghong Song //   struct t e;
27a1b2a27aSYonghong Song //
28a1b2a27aSYonghong Song // For the member access e.c.b, the compiler will generate code
29a1b2a27aSYonghong Song //   &e + 4
30a1b2a27aSYonghong Song //
31a1b2a27aSYonghong Song // The compile-once run-everywhere instead generates the following code
32a1b2a27aSYonghong Song //   r = 4
33a1b2a27aSYonghong Song //   &e + r
34a1b2a27aSYonghong Song // The "4" in "r = 4" can be changed based on a particular kernel version.
35a1b2a27aSYonghong Song // For example, on a particular kernel version, if struct s is changed to
36a1b2a27aSYonghong Song //
37a1b2a27aSYonghong Song //   struct s {
38a1b2a27aSYonghong Song //     int new_field;
39a1b2a27aSYonghong Song //     int a;
40a1b2a27aSYonghong Song //     int b;
41a1b2a27aSYonghong Song //   }
42a1b2a27aSYonghong Song //
43a1b2a27aSYonghong Song // By repeating the member access on the host, the bpf loader can
44a1b2a27aSYonghong Song // adjust "r = 4" as "r = 8".
45a1b2a27aSYonghong Song //
46a1b2a27aSYonghong Song // This feature relies on the following three intrinsic calls:
47a1b2a27aSYonghong Song //   addr = preserve_array_access_index(base, dimension, index)
48a1b2a27aSYonghong Song //   addr = preserve_union_access_index(base, di_index)
49a1b2a27aSYonghong Song //          !llvm.preserve.access.index <union_ditype>
50a1b2a27aSYonghong Song //   addr = preserve_struct_access_index(base, gep_index, di_index)
51a1b2a27aSYonghong Song //          !llvm.preserve.access.index <struct_ditype>
52a1b2a27aSYonghong Song //
5305e46979SYonghong Song // Bitfield member access needs special attention. User cannot take the
5405e46979SYonghong Song // address of a bitfield acceess. To facilitate kernel verifier
5505e46979SYonghong Song // for easy bitfield code optimization, a new clang intrinsic is introduced:
5605e46979SYonghong Song //   uint32_t __builtin_preserve_field_info(member_access, info_kind)
5705e46979SYonghong Song // In IR, a chain with two (or more) intrinsic calls will be generated:
5805e46979SYonghong Song //   ...
5905e46979SYonghong Song //   addr = preserve_struct_access_index(base, 1, 1) !struct s
6005e46979SYonghong Song //   uint32_t result = bpf_preserve_field_info(addr, info_kind)
6105e46979SYonghong Song //
6205e46979SYonghong Song // Suppose the info_kind is FIELD_SIGNEDNESS,
6305e46979SYonghong Song // The above two IR intrinsics will be replaced with
6405e46979SYonghong Song // a relocatable insn:
6505e46979SYonghong Song //   signness = /* signness of member_access */
6605e46979SYonghong Song // and signness can be changed by bpf loader based on the
6705e46979SYonghong Song // types on the host.
6805e46979SYonghong Song //
6905e46979SYonghong Song // User can also test whether a field exists or not with
7005e46979SYonghong Song //   uint32_t result = bpf_preserve_field_info(member_access, FIELD_EXISTENCE)
7105e46979SYonghong Song // The field will be always available (result = 1) during initial
7205e46979SYonghong Song // compilation, but bpf loader can patch with the correct value
7305e46979SYonghong Song // on the target host where the member_access may or may not be available
7405e46979SYonghong Song //
75a1b2a27aSYonghong Song //===----------------------------------------------------------------------===//
76a1b2a27aSYonghong Song 
77a1b2a27aSYonghong Song #include "BPF.h"
78a1b2a27aSYonghong Song #include "BPFCORE.h"
79a1b2a27aSYonghong Song #include "BPFTargetMachine.h"
80ffe8720aSserge-sans-paille #include "llvm/BinaryFormat/Dwarf.h"
81a1b2a27aSYonghong Song #include "llvm/IR/DebugInfoMetadata.h"
82a1b2a27aSYonghong Song #include "llvm/IR/GlobalVariable.h"
83a1b2a27aSYonghong Song #include "llvm/IR/Instruction.h"
84a1b2a27aSYonghong Song #include "llvm/IR/Instructions.h"
8554d9f743SYonghong Song #include "llvm/IR/IntrinsicsBPF.h"
86a1b2a27aSYonghong Song #include "llvm/IR/Module.h"
8740251feeSArthur Eubanks #include "llvm/IR/PassManager.h"
88a1b2a27aSYonghong Song #include "llvm/IR/Type.h"
89a1b2a27aSYonghong Song #include "llvm/IR/User.h"
90a1b2a27aSYonghong Song #include "llvm/IR/Value.h"
91a1b2a27aSYonghong Song #include "llvm/Pass.h"
92a1b2a27aSYonghong Song #include "llvm/Transforms/Utils/BasicBlockUtils.h"
9337d24a69SYonghong Song #include <stack>
94a1b2a27aSYonghong Song 
95a1b2a27aSYonghong Song #define DEBUG_TYPE "bpf-abstract-member-access"
96a1b2a27aSYonghong Song 
97a1b2a27aSYonghong Song namespace llvm {
98df9a51daSBenjamin Kramer constexpr StringRef BPFCoreSharedInfo::AmaAttr;
9954d9f743SYonghong Song uint32_t BPFCoreSharedInfo::SeqNum;
10054d9f743SYonghong Song 
insertPassThrough(Module * M,BasicBlock * BB,Instruction * Input,Instruction * Before)10154d9f743SYonghong Song Instruction *BPFCoreSharedInfo::insertPassThrough(Module *M, BasicBlock *BB,
10254d9f743SYonghong Song                                                   Instruction *Input,
10354d9f743SYonghong Song                                                   Instruction *Before) {
10454d9f743SYonghong Song   Function *Fn = Intrinsic::getDeclaration(
10554d9f743SYonghong Song       M, Intrinsic::bpf_passthrough, {Input->getType(), Input->getType()});
10654d9f743SYonghong Song   Constant *SeqNumVal = ConstantInt::get(Type::getInt32Ty(BB->getContext()),
10754d9f743SYonghong Song                                          BPFCoreSharedInfo::SeqNum++);
10854d9f743SYonghong Song 
10954d9f743SYonghong Song   auto *NewInst = CallInst::Create(Fn, {SeqNumVal, Input});
11054d9f743SYonghong Song   BB->getInstList().insert(Before->getIterator(), NewInst);
11154d9f743SYonghong Song   return NewInst;
11254d9f743SYonghong Song }
113a1b2a27aSYonghong Song } // namespace llvm
114a1b2a27aSYonghong Song 
115a1b2a27aSYonghong Song using namespace llvm;
116a1b2a27aSYonghong Song 
117a1b2a27aSYonghong Song namespace {
11840251feeSArthur Eubanks class BPFAbstractMemberAccess final {
119a1b2a27aSYonghong Song public:
BPFAbstractMemberAccess(BPFTargetMachine * TM)12040251feeSArthur Eubanks   BPFAbstractMemberAccess(BPFTargetMachine *TM) : TM(TM) {}
12140251feeSArthur Eubanks 
12240251feeSArthur Eubanks   bool run(Function &F);
123a1b2a27aSYonghong Song 
12402ac7509SYonghong Song   struct CallInfo {
12502ac7509SYonghong Song     uint32_t Kind;
12602ac7509SYonghong Song     uint32_t AccessIndex;
127c48b4641SNikita Popov     MaybeAlign RecordAlignment;
12802ac7509SYonghong Song     MDNode *Metadata;
12902ac7509SYonghong Song     Value *Base;
13002ac7509SYonghong Song   };
13105e46979SYonghong Song   typedef std::stack<std::pair<CallInst *, CallInfo>> CallInfoStack;
13202ac7509SYonghong Song 
133a1b2a27aSYonghong Song private:
134a1b2a27aSYonghong Song   enum : uint32_t {
135a1b2a27aSYonghong Song     BPFPreserveArrayAI = 1,
136a1b2a27aSYonghong Song     BPFPreserveUnionAI = 2,
137a1b2a27aSYonghong Song     BPFPreserveStructAI = 3,
13805e46979SYonghong Song     BPFPreserveFieldInfoAI = 4,
139a1b2a27aSYonghong Song   };
140a1b2a27aSYonghong Song 
14140251feeSArthur Eubanks   TargetMachine *TM;
142f784ad8fSSimon Pilgrim   const DataLayout *DL = nullptr;
14354d9f743SYonghong Song   Module *M = nullptr;
144fff27212SYonghong Song 
145edd71db3SYonghong Song   static std::map<std::string, GlobalVariable *> GEPGlobals;
1469727c77dSDavid Green   // A map to link preserve_*_access_index intrinsic calls.
14702ac7509SYonghong Song   std::map<CallInst *, std::pair<CallInst *, CallInfo>> AIChain;
1489727c77dSDavid Green   // A map to hold all the base preserve_*_access_index intrinsic calls.
14905e46979SYonghong Song   // The base call is not an input of any other preserve_*
150a1b2a27aSYonghong Song   // intrinsics.
15102ac7509SYonghong Song   std::map<CallInst *, CallInfo> BaseAICalls;
152*6e6c1efeSYonghong Song   // A map to hold <AnonRecord, TypeDef> relationships
153*6e6c1efeSYonghong Song   std::map<DICompositeType *, DIDerivedType *> AnonRecords;
154*6e6c1efeSYonghong Song 
155*6e6c1efeSYonghong Song   void CheckAnonRecordType(DIDerivedType *ParentTy, DIType *Ty);
156*6e6c1efeSYonghong Song   void CheckCompositeType(DIDerivedType *ParentTy, DICompositeType *CTy);
157*6e6c1efeSYonghong Song   void CheckDerivedType(DIDerivedType *ParentTy, DIDerivedType *DTy);
158*6e6c1efeSYonghong Song   void ResetMetadata(struct CallInfo &CInfo);
159a1b2a27aSYonghong Song 
16054d9f743SYonghong Song   bool doTransformation(Function &F);
161a1b2a27aSYonghong Song 
16202ac7509SYonghong Song   void traceAICall(CallInst *Call, CallInfo &ParentInfo);
16302ac7509SYonghong Song   void traceBitCast(BitCastInst *BitCast, CallInst *Parent,
16402ac7509SYonghong Song                     CallInfo &ParentInfo);
16502ac7509SYonghong Song   void traceGEP(GetElementPtrInst *GEP, CallInst *Parent,
16602ac7509SYonghong Song                 CallInfo &ParentInfo);
16754d9f743SYonghong Song   void collectAICallChains(Function &F);
168a1b2a27aSYonghong Song 
16902ac7509SYonghong Song   bool IsPreserveDIAccessIndexCall(const CallInst *Call, CallInfo &Cinfo);
17037d24a69SYonghong Song   bool IsValidAIChain(const MDNode *ParentMeta, uint32_t ParentAI,
17137d24a69SYonghong Song                       const MDNode *ChildMeta);
17254d9f743SYonghong Song   bool removePreserveAccessIndexIntrinsic(Function &F);
173a1b2a27aSYonghong Song   void replaceWithGEP(std::vector<CallInst *> &CallList,
174a1b2a27aSYonghong Song                       uint32_t NumOfZerosIndex, uint32_t DIIndex);
17505e46979SYonghong Song   bool HasPreserveFieldInfoCall(CallInfoStack &CallStack);
1760f9d623bSGuillaume Chatelet   void GetStorageBitRange(DIDerivedType *MemberTy, Align RecordAlignment,
177fff27212SYonghong Song                           uint32_t &StartBitOffset, uint32_t &EndBitOffset);
17805e46979SYonghong Song   uint32_t GetFieldInfo(uint32_t InfoKind, DICompositeType *CTy,
179fff27212SYonghong Song                         uint32_t AccessIndex, uint32_t PatchImm,
180c48b4641SNikita Popov                         MaybeAlign RecordAlignment);
181a1b2a27aSYonghong Song 
18202ac7509SYonghong Song   Value *computeBaseAndAccessKey(CallInst *Call, CallInfo &CInfo,
18302ac7509SYonghong Song                                  std::string &AccessKey, MDNode *&BaseMeta);
1846d218b4aSYonghong Song   MDNode *computeAccessKey(CallInst *Call, CallInfo &CInfo,
1856d218b4aSYonghong Song                            std::string &AccessKey, bool &IsInt32Ret);
18602ac7509SYonghong Song   uint64_t getConstant(const Value *IndexValue);
18754d9f743SYonghong Song   bool transformGEPChain(CallInst *Call, CallInfo &CInfo);
188a1b2a27aSYonghong Song };
18940251feeSArthur Eubanks 
190edd71db3SYonghong Song std::map<std::string, GlobalVariable *> BPFAbstractMemberAccess::GEPGlobals;
191edd71db3SYonghong Song 
19240251feeSArthur Eubanks class BPFAbstractMemberAccessLegacyPass final : public FunctionPass {
19340251feeSArthur Eubanks   BPFTargetMachine *TM;
19440251feeSArthur Eubanks 
runOnFunction(Function & F)19540251feeSArthur Eubanks   bool runOnFunction(Function &F) override {
19640251feeSArthur Eubanks     return BPFAbstractMemberAccess(TM).run(F);
19740251feeSArthur Eubanks   }
19840251feeSArthur Eubanks 
19940251feeSArthur Eubanks public:
20040251feeSArthur Eubanks   static char ID;
20140251feeSArthur Eubanks 
20240251feeSArthur Eubanks   // Add optional BPFTargetMachine parameter so that BPF backend can add the
20340251feeSArthur Eubanks   // phase with target machine to find out the endianness. The default
20440251feeSArthur Eubanks   // constructor (without parameters) is used by the pass manager for managing
20540251feeSArthur Eubanks   // purposes.
BPFAbstractMemberAccessLegacyPass(BPFTargetMachine * TM=nullptr)20640251feeSArthur Eubanks   BPFAbstractMemberAccessLegacyPass(BPFTargetMachine *TM = nullptr)
20740251feeSArthur Eubanks       : FunctionPass(ID), TM(TM) {}
20840251feeSArthur Eubanks };
20940251feeSArthur Eubanks 
210a1b2a27aSYonghong Song } // End anonymous namespace
211a1b2a27aSYonghong Song 
21240251feeSArthur Eubanks char BPFAbstractMemberAccessLegacyPass::ID = 0;
21340251feeSArthur Eubanks INITIALIZE_PASS(BPFAbstractMemberAccessLegacyPass, DEBUG_TYPE,
21454d9f743SYonghong Song                 "BPF Abstract Member Access", false, false)
215a1b2a27aSYonghong Song 
createBPFAbstractMemberAccess(BPFTargetMachine * TM)21654d9f743SYonghong Song FunctionPass *llvm::createBPFAbstractMemberAccess(BPFTargetMachine *TM) {
21740251feeSArthur Eubanks   return new BPFAbstractMemberAccessLegacyPass(TM);
218a1b2a27aSYonghong Song }
219a1b2a27aSYonghong Song 
run(Function & F)22040251feeSArthur Eubanks bool BPFAbstractMemberAccess::run(Function &F) {
221a1b2a27aSYonghong Song   LLVM_DEBUG(dbgs() << "********** Abstract Member Accesses **********\n");
222a1b2a27aSYonghong Song 
22354d9f743SYonghong Song   M = F.getParent();
22454d9f743SYonghong Song   if (!M)
225a1b2a27aSYonghong Song     return false;
226a1b2a27aSYonghong Song 
22754d9f743SYonghong Song   // Bail out if no debug info.
22854d9f743SYonghong Song   if (M->debug_compile_units().empty())
22954d9f743SYonghong Song     return false;
23054d9f743SYonghong Song 
231*6e6c1efeSYonghong Song   // For each argument/return/local_variable type, trace the type
232*6e6c1efeSYonghong Song   // pattern like '[derived_type]* [composite_type]' to check
233*6e6c1efeSYonghong Song   // and remember (anon record -> typedef) relations where the
234*6e6c1efeSYonghong Song   // anon record is defined as
235*6e6c1efeSYonghong Song   //   typedef [const/volatile/restrict]* [anon record]
236*6e6c1efeSYonghong Song   DISubprogram *SP = F.getSubprogram();
237*6e6c1efeSYonghong Song   if (SP && SP->isDefinition()) {
238*6e6c1efeSYonghong Song     for (DIType *Ty: SP->getType()->getTypeArray())
239*6e6c1efeSYonghong Song       CheckAnonRecordType(nullptr, Ty);
240*6e6c1efeSYonghong Song     for (const DINode *DN : SP->getRetainedNodes()) {
241*6e6c1efeSYonghong Song       if (const auto *DV = dyn_cast<DILocalVariable>(DN))
242*6e6c1efeSYonghong Song         CheckAnonRecordType(nullptr, DV->getType());
243*6e6c1efeSYonghong Song     }
244*6e6c1efeSYonghong Song   }
245*6e6c1efeSYonghong Song 
24654d9f743SYonghong Song   DL = &M->getDataLayout();
24754d9f743SYonghong Song   return doTransformation(F);
248a1b2a27aSYonghong Song }
249a1b2a27aSYonghong Song 
ResetMetadata(struct CallInfo & CInfo)250*6e6c1efeSYonghong Song void BPFAbstractMemberAccess::ResetMetadata(struct CallInfo &CInfo) {
251*6e6c1efeSYonghong Song   if (auto Ty = dyn_cast<DICompositeType>(CInfo.Metadata)) {
252*6e6c1efeSYonghong Song     if (AnonRecords.find(Ty) != AnonRecords.end()) {
253*6e6c1efeSYonghong Song       if (AnonRecords[Ty] != nullptr)
254*6e6c1efeSYonghong Song         CInfo.Metadata = AnonRecords[Ty];
255*6e6c1efeSYonghong Song     }
256*6e6c1efeSYonghong Song   }
257*6e6c1efeSYonghong Song }
258*6e6c1efeSYonghong Song 
CheckCompositeType(DIDerivedType * ParentTy,DICompositeType * CTy)259*6e6c1efeSYonghong Song void BPFAbstractMemberAccess::CheckCompositeType(DIDerivedType *ParentTy,
260*6e6c1efeSYonghong Song                                                  DICompositeType *CTy) {
261*6e6c1efeSYonghong Song   if (!CTy->getName().empty() || !ParentTy ||
262*6e6c1efeSYonghong Song       ParentTy->getTag() != dwarf::DW_TAG_typedef)
263*6e6c1efeSYonghong Song     return;
264*6e6c1efeSYonghong Song 
265*6e6c1efeSYonghong Song   if (AnonRecords.find(CTy) == AnonRecords.end()) {
266*6e6c1efeSYonghong Song     AnonRecords[CTy] = ParentTy;
267*6e6c1efeSYonghong Song     return;
268*6e6c1efeSYonghong Song   }
269*6e6c1efeSYonghong Song 
270*6e6c1efeSYonghong Song   // Two or more typedef's may point to the same anon record.
271*6e6c1efeSYonghong Song   // If this is the case, set the typedef DIType to be nullptr
272*6e6c1efeSYonghong Song   // to indicate the duplication case.
273*6e6c1efeSYonghong Song   DIDerivedType *CurrTy = AnonRecords[CTy];
274*6e6c1efeSYonghong Song   if (CurrTy == ParentTy)
275*6e6c1efeSYonghong Song     return;
276*6e6c1efeSYonghong Song   AnonRecords[CTy] = nullptr;
277*6e6c1efeSYonghong Song }
278*6e6c1efeSYonghong Song 
CheckDerivedType(DIDerivedType * ParentTy,DIDerivedType * DTy)279*6e6c1efeSYonghong Song void BPFAbstractMemberAccess::CheckDerivedType(DIDerivedType *ParentTy,
280*6e6c1efeSYonghong Song                                                DIDerivedType *DTy) {
281*6e6c1efeSYonghong Song   DIType *BaseType = DTy->getBaseType();
282*6e6c1efeSYonghong Song   if (!BaseType)
283*6e6c1efeSYonghong Song     return;
284*6e6c1efeSYonghong Song 
285*6e6c1efeSYonghong Song   unsigned Tag = DTy->getTag();
286*6e6c1efeSYonghong Song   if (Tag == dwarf::DW_TAG_pointer_type)
287*6e6c1efeSYonghong Song     CheckAnonRecordType(nullptr, BaseType);
288*6e6c1efeSYonghong Song   else if (Tag == dwarf::DW_TAG_typedef)
289*6e6c1efeSYonghong Song     CheckAnonRecordType(DTy, BaseType);
290*6e6c1efeSYonghong Song   else
291*6e6c1efeSYonghong Song     CheckAnonRecordType(ParentTy, BaseType);
292*6e6c1efeSYonghong Song }
293*6e6c1efeSYonghong Song 
CheckAnonRecordType(DIDerivedType * ParentTy,DIType * Ty)294*6e6c1efeSYonghong Song void BPFAbstractMemberAccess::CheckAnonRecordType(DIDerivedType *ParentTy,
295*6e6c1efeSYonghong Song                                                   DIType *Ty) {
296*6e6c1efeSYonghong Song   if (!Ty)
297*6e6c1efeSYonghong Song     return;
298*6e6c1efeSYonghong Song 
299*6e6c1efeSYonghong Song   if (auto *CTy = dyn_cast<DICompositeType>(Ty))
300*6e6c1efeSYonghong Song     return CheckCompositeType(ParentTy, CTy);
301*6e6c1efeSYonghong Song   else if (auto *DTy = dyn_cast<DIDerivedType>(Ty))
302*6e6c1efeSYonghong Song     return CheckDerivedType(ParentTy, DTy);
303*6e6c1efeSYonghong Song }
304*6e6c1efeSYonghong Song 
SkipDIDerivedTag(unsigned Tag,bool skipTypedef)3056d07802dSYonghong Song static bool SkipDIDerivedTag(unsigned Tag, bool skipTypedef) {
30637d24a69SYonghong Song   if (Tag != dwarf::DW_TAG_typedef && Tag != dwarf::DW_TAG_const_type &&
30737d24a69SYonghong Song       Tag != dwarf::DW_TAG_volatile_type &&
30837d24a69SYonghong Song       Tag != dwarf::DW_TAG_restrict_type &&
30937d24a69SYonghong Song       Tag != dwarf::DW_TAG_member)
31037d24a69SYonghong Song     return false;
3116d07802dSYonghong Song   if (Tag == dwarf::DW_TAG_typedef && !skipTypedef)
3126d07802dSYonghong Song     return false;
31337d24a69SYonghong Song   return true;
31437d24a69SYonghong Song }
31537d24a69SYonghong Song 
stripQualifiers(DIType * Ty,bool skipTypedef=true)3166d07802dSYonghong Song static DIType * stripQualifiers(DIType *Ty, bool skipTypedef = true) {
31737d24a69SYonghong Song   while (auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
3186d07802dSYonghong Song     if (!SkipDIDerivedTag(DTy->getTag(), skipTypedef))
31937d24a69SYonghong Song       break;
32037d24a69SYonghong Song     Ty = DTy->getBaseType();
32137d24a69SYonghong Song   }
32237d24a69SYonghong Song   return Ty;
32337d24a69SYonghong Song }
32437d24a69SYonghong Song 
stripQualifiers(const DIType * Ty)32537d24a69SYonghong Song static const DIType * stripQualifiers(const DIType *Ty) {
32637d24a69SYonghong Song   while (auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
3276d07802dSYonghong Song     if (!SkipDIDerivedTag(DTy->getTag(), true))
32837d24a69SYonghong Song       break;
32937d24a69SYonghong Song     Ty = DTy->getBaseType();
33037d24a69SYonghong Song   }
33137d24a69SYonghong Song   return Ty;
33237d24a69SYonghong Song }
33337d24a69SYonghong Song 
calcArraySize(const DICompositeType * CTy,uint32_t StartDim)33437d24a69SYonghong Song static uint32_t calcArraySize(const DICompositeType *CTy, uint32_t StartDim) {
33537d24a69SYonghong Song   DINodeArray Elements = CTy->getElements();
33637d24a69SYonghong Song   uint32_t DimSize = 1;
33737d24a69SYonghong Song   for (uint32_t I = StartDim; I < Elements.size(); ++I) {
33837d24a69SYonghong Song     if (auto *Element = dyn_cast_or_null<DINode>(Elements[I]))
33937d24a69SYonghong Song       if (Element->getTag() == dwarf::DW_TAG_subrange_type) {
34037d24a69SYonghong Song         const DISubrange *SR = cast<DISubrange>(Element);
34137d24a69SYonghong Song         auto *CI = SR->getCount().dyn_cast<ConstantInt *>();
34237d24a69SYonghong Song         DimSize *= CI->getSExtValue();
34337d24a69SYonghong Song       }
34437d24a69SYonghong Song   }
34537d24a69SYonghong Song 
34637d24a69SYonghong Song   return DimSize;
34737d24a69SYonghong Song }
34837d24a69SYonghong Song 
getBaseElementType(const CallInst * Call)349be5af50eSNikita Popov static Type *getBaseElementType(const CallInst *Call) {
350be5af50eSNikita Popov   // Element type is stored in an elementtype() attribute on the first param.
35187ebd9a3SNikita Popov   return Call->getParamElementType(0);
352be5af50eSNikita Popov }
353be5af50eSNikita Popov 
354a1b2a27aSYonghong Song /// Check whether a call is a preserve_*_access_index intrinsic call or not.
IsPreserveDIAccessIndexCall(const CallInst * Call,CallInfo & CInfo)355a1b2a27aSYonghong Song bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
35602ac7509SYonghong Song                                                           CallInfo &CInfo) {
357a1b2a27aSYonghong Song   if (!Call)
358a1b2a27aSYonghong Song     return false;
359a1b2a27aSYonghong Song 
360a58b62b4SCraig Topper   const auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand());
361a1b2a27aSYonghong Song   if (!GV)
362a1b2a27aSYonghong Song     return false;
363a1b2a27aSYonghong Song   if (GV->getName().startswith("llvm.preserve.array.access.index")) {
36402ac7509SYonghong Song     CInfo.Kind = BPFPreserveArrayAI;
36502ac7509SYonghong Song     CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index);
36602ac7509SYonghong Song     if (!CInfo.Metadata)
36737d24a69SYonghong Song       report_fatal_error("Missing metadata for llvm.preserve.array.access.index intrinsic");
36802ac7509SYonghong Song     CInfo.AccessIndex = getConstant(Call->getArgOperand(2));
36902ac7509SYonghong Song     CInfo.Base = Call->getArgOperand(0);
370be5af50eSNikita Popov     CInfo.RecordAlignment = DL->getABITypeAlign(getBaseElementType(Call));
371a1b2a27aSYonghong Song     return true;
372a1b2a27aSYonghong Song   }
373a1b2a27aSYonghong Song   if (GV->getName().startswith("llvm.preserve.union.access.index")) {
37402ac7509SYonghong Song     CInfo.Kind = BPFPreserveUnionAI;
37502ac7509SYonghong Song     CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index);
37602ac7509SYonghong Song     if (!CInfo.Metadata)
37737d24a69SYonghong Song       report_fatal_error("Missing metadata for llvm.preserve.union.access.index intrinsic");
378*6e6c1efeSYonghong Song     ResetMetadata(CInfo);
37902ac7509SYonghong Song     CInfo.AccessIndex = getConstant(Call->getArgOperand(1));
38002ac7509SYonghong Song     CInfo.Base = Call->getArgOperand(0);
381a1b2a27aSYonghong Song     return true;
382a1b2a27aSYonghong Song   }
383a1b2a27aSYonghong Song   if (GV->getName().startswith("llvm.preserve.struct.access.index")) {
38402ac7509SYonghong Song     CInfo.Kind = BPFPreserveStructAI;
38502ac7509SYonghong Song     CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index);
38602ac7509SYonghong Song     if (!CInfo.Metadata)
38737d24a69SYonghong Song       report_fatal_error("Missing metadata for llvm.preserve.struct.access.index intrinsic");
388*6e6c1efeSYonghong Song     ResetMetadata(CInfo);
38902ac7509SYonghong Song     CInfo.AccessIndex = getConstant(Call->getArgOperand(2));
39002ac7509SYonghong Song     CInfo.Base = Call->getArgOperand(0);
391be5af50eSNikita Popov     CInfo.RecordAlignment = DL->getABITypeAlign(getBaseElementType(Call));
392a1b2a27aSYonghong Song     return true;
393a1b2a27aSYonghong Song   }
39405e46979SYonghong Song   if (GV->getName().startswith("llvm.bpf.preserve.field.info")) {
39505e46979SYonghong Song     CInfo.Kind = BPFPreserveFieldInfoAI;
39605e46979SYonghong Song     CInfo.Metadata = nullptr;
39705e46979SYonghong Song     // Check validity of info_kind as clang did not check this.
39805e46979SYonghong Song     uint64_t InfoKind = getConstant(Call->getArgOperand(1));
39905e46979SYonghong Song     if (InfoKind >= BPFCoreSharedInfo::MAX_FIELD_RELOC_KIND)
40005e46979SYonghong Song       report_fatal_error("Incorrect info_kind for llvm.bpf.preserve.field.info intrinsic");
40105e46979SYonghong Song     CInfo.AccessIndex = InfoKind;
40205e46979SYonghong Song     return true;
40305e46979SYonghong Song   }
4046d218b4aSYonghong Song   if (GV->getName().startswith("llvm.bpf.preserve.type.info")) {
4056d218b4aSYonghong Song     CInfo.Kind = BPFPreserveFieldInfoAI;
4066d218b4aSYonghong Song     CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index);
4076d218b4aSYonghong Song     if (!CInfo.Metadata)
4086d218b4aSYonghong Song       report_fatal_error("Missing metadata for llvm.preserve.type.info intrinsic");
4096d218b4aSYonghong Song     uint64_t Flag = getConstant(Call->getArgOperand(1));
4106d218b4aSYonghong Song     if (Flag >= BPFCoreSharedInfo::MAX_PRESERVE_TYPE_INFO_FLAG)
4116d218b4aSYonghong Song       report_fatal_error("Incorrect flag for llvm.bpf.preserve.type.info intrinsic");
4126d218b4aSYonghong Song     if (Flag == BPFCoreSharedInfo::PRESERVE_TYPE_INFO_EXISTENCE)
4136d218b4aSYonghong Song       CInfo.AccessIndex = BPFCoreSharedInfo::TYPE_EXISTENCE;
414d129ac27SDaniel Müller     else if (Flag == BPFCoreSharedInfo::PRESERVE_TYPE_INFO_MATCH)
415d129ac27SDaniel Müller       CInfo.AccessIndex = BPFCoreSharedInfo::TYPE_MATCH;
4166d218b4aSYonghong Song     else
4176d218b4aSYonghong Song       CInfo.AccessIndex = BPFCoreSharedInfo::TYPE_SIZE;
4186d218b4aSYonghong Song     return true;
4196d218b4aSYonghong Song   }
4206d218b4aSYonghong Song   if (GV->getName().startswith("llvm.bpf.preserve.enum.value")) {
4216d218b4aSYonghong Song     CInfo.Kind = BPFPreserveFieldInfoAI;
4226d218b4aSYonghong Song     CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index);
4236d218b4aSYonghong Song     if (!CInfo.Metadata)
4246d218b4aSYonghong Song       report_fatal_error("Missing metadata for llvm.preserve.enum.value intrinsic");
4256d218b4aSYonghong Song     uint64_t Flag = getConstant(Call->getArgOperand(2));
4266d218b4aSYonghong Song     if (Flag >= BPFCoreSharedInfo::MAX_PRESERVE_ENUM_VALUE_FLAG)
4276d218b4aSYonghong Song       report_fatal_error("Incorrect flag for llvm.bpf.preserve.enum.value intrinsic");
4286d218b4aSYonghong Song     if (Flag == BPFCoreSharedInfo::PRESERVE_ENUM_VALUE_EXISTENCE)
4296d218b4aSYonghong Song       CInfo.AccessIndex = BPFCoreSharedInfo::ENUM_VALUE_EXISTENCE;
4306d218b4aSYonghong Song     else
4316d218b4aSYonghong Song       CInfo.AccessIndex = BPFCoreSharedInfo::ENUM_VALUE;
4326d218b4aSYonghong Song     return true;
4336d218b4aSYonghong Song   }
434a1b2a27aSYonghong Song 
435a1b2a27aSYonghong Song   return false;
436a1b2a27aSYonghong Song }
437a1b2a27aSYonghong Song 
replaceWithGEP(std::vector<CallInst * > & CallList,uint32_t DimensionIndex,uint32_t GEPIndex)438a1b2a27aSYonghong Song void BPFAbstractMemberAccess::replaceWithGEP(std::vector<CallInst *> &CallList,
439a1b2a27aSYonghong Song                                              uint32_t DimensionIndex,
440a1b2a27aSYonghong Song                                              uint32_t GEPIndex) {
441a1b2a27aSYonghong Song   for (auto Call : CallList) {
442a1b2a27aSYonghong Song     uint32_t Dimension = 1;
443a1b2a27aSYonghong Song     if (DimensionIndex > 0)
44402ac7509SYonghong Song       Dimension = getConstant(Call->getArgOperand(DimensionIndex));
445a1b2a27aSYonghong Song 
446a1b2a27aSYonghong Song     Constant *Zero =
447a1b2a27aSYonghong Song         ConstantInt::get(Type::getInt32Ty(Call->getParent()->getContext()), 0);
448a1b2a27aSYonghong Song     SmallVector<Value *, 4> IdxList;
449a1b2a27aSYonghong Song     for (unsigned I = 0; I < Dimension; ++I)
450a1b2a27aSYonghong Song       IdxList.push_back(Zero);
451a1b2a27aSYonghong Song     IdxList.push_back(Call->getArgOperand(GEPIndex));
452a1b2a27aSYonghong Song 
453a213f735SNikita Popov     auto *GEP = GetElementPtrInst::CreateInBounds(
454be5af50eSNikita Popov         getBaseElementType(Call), Call->getArgOperand(0), IdxList, "", Call);
455a1b2a27aSYonghong Song     Call->replaceAllUsesWith(GEP);
456a1b2a27aSYonghong Song     Call->eraseFromParent();
457a1b2a27aSYonghong Song   }
458a1b2a27aSYonghong Song }
459a1b2a27aSYonghong Song 
removePreserveAccessIndexIntrinsic(Function & F)46054d9f743SYonghong Song bool BPFAbstractMemberAccess::removePreserveAccessIndexIntrinsic(Function &F) {
461a1b2a27aSYonghong Song   std::vector<CallInst *> PreserveArrayIndexCalls;
462a1b2a27aSYonghong Song   std::vector<CallInst *> PreserveUnionIndexCalls;
463a1b2a27aSYonghong Song   std::vector<CallInst *> PreserveStructIndexCalls;
464a1b2a27aSYonghong Song   bool Found = false;
465a1b2a27aSYonghong Song 
466a1b2a27aSYonghong Song   for (auto &BB : F)
467a1b2a27aSYonghong Song     for (auto &I : BB) {
468a1b2a27aSYonghong Song       auto *Call = dyn_cast<CallInst>(&I);
46902ac7509SYonghong Song       CallInfo CInfo;
47002ac7509SYonghong Song       if (!IsPreserveDIAccessIndexCall(Call, CInfo))
471a1b2a27aSYonghong Song         continue;
472a1b2a27aSYonghong Song 
473a1b2a27aSYonghong Song       Found = true;
47402ac7509SYonghong Song       if (CInfo.Kind == BPFPreserveArrayAI)
475a1b2a27aSYonghong Song         PreserveArrayIndexCalls.push_back(Call);
47602ac7509SYonghong Song       else if (CInfo.Kind == BPFPreserveUnionAI)
477a1b2a27aSYonghong Song         PreserveUnionIndexCalls.push_back(Call);
478a1b2a27aSYonghong Song       else
479a1b2a27aSYonghong Song         PreserveStructIndexCalls.push_back(Call);
480a1b2a27aSYonghong Song     }
481a1b2a27aSYonghong Song 
482a1b2a27aSYonghong Song   // do the following transformation:
483a1b2a27aSYonghong Song   // . addr = preserve_array_access_index(base, dimension, index)
484a1b2a27aSYonghong Song   //   is transformed to
485a1b2a27aSYonghong Song   //     addr = GEP(base, dimenion's zero's, index)
486a1b2a27aSYonghong Song   // . addr = preserve_union_access_index(base, di_index)
487a1b2a27aSYonghong Song   //   is transformed to
488a1b2a27aSYonghong Song   //     addr = base, i.e., all usages of "addr" are replaced by "base".
489a1b2a27aSYonghong Song   // . addr = preserve_struct_access_index(base, gep_index, di_index)
490a1b2a27aSYonghong Song   //   is transformed to
491a1b2a27aSYonghong Song   //     addr = GEP(base, 0, gep_index)
492a1b2a27aSYonghong Song   replaceWithGEP(PreserveArrayIndexCalls, 1, 2);
493a1b2a27aSYonghong Song   replaceWithGEP(PreserveStructIndexCalls, 0, 1);
494a1b2a27aSYonghong Song   for (auto Call : PreserveUnionIndexCalls) {
495a1b2a27aSYonghong Song     Call->replaceAllUsesWith(Call->getArgOperand(0));
496a1b2a27aSYonghong Song     Call->eraseFromParent();
497a1b2a27aSYonghong Song   }
498a1b2a27aSYonghong Song 
499a1b2a27aSYonghong Song   return Found;
500a1b2a27aSYonghong Song }
501a1b2a27aSYonghong Song 
50237d24a69SYonghong Song /// Check whether the access index chain is valid. We check
50337d24a69SYonghong Song /// here because there may be type casts between two
50437d24a69SYonghong Song /// access indexes. We want to ensure memory access still valid.
IsValidAIChain(const MDNode * ParentType,uint32_t ParentAI,const MDNode * ChildType)50537d24a69SYonghong Song bool BPFAbstractMemberAccess::IsValidAIChain(const MDNode *ParentType,
50637d24a69SYonghong Song                                              uint32_t ParentAI,
50737d24a69SYonghong Song                                              const MDNode *ChildType) {
50805e46979SYonghong Song   if (!ChildType)
50905e46979SYonghong Song     return true; // preserve_field_info, no type comparison needed.
51005e46979SYonghong Song 
51137d24a69SYonghong Song   const DIType *PType = stripQualifiers(cast<DIType>(ParentType));
51237d24a69SYonghong Song   const DIType *CType = stripQualifiers(cast<DIType>(ChildType));
51337d24a69SYonghong Song 
51437d24a69SYonghong Song   // Child is a derived/pointer type, which is due to type casting.
51537d24a69SYonghong Song   // Pointer type cannot be in the middle of chain.
516ebc2cf9cSBill Wendling   if (isa<DIDerivedType>(CType))
51737d24a69SYonghong Song     return false;
51837d24a69SYonghong Song 
51937d24a69SYonghong Song   // Parent is a pointer type.
52037d24a69SYonghong Song   if (const auto *PtrTy = dyn_cast<DIDerivedType>(PType)) {
52137d24a69SYonghong Song     if (PtrTy->getTag() != dwarf::DW_TAG_pointer_type)
52237d24a69SYonghong Song       return false;
52337d24a69SYonghong Song     return stripQualifiers(PtrTy->getBaseType()) == CType;
52437d24a69SYonghong Song   }
52537d24a69SYonghong Song 
52637d24a69SYonghong Song   // Otherwise, struct/union/array types
52737d24a69SYonghong Song   const auto *PTy = dyn_cast<DICompositeType>(PType);
52837d24a69SYonghong Song   const auto *CTy = dyn_cast<DICompositeType>(CType);
52937d24a69SYonghong Song   assert(PTy && CTy && "ParentType or ChildType is null or not composite");
53037d24a69SYonghong Song 
53137d24a69SYonghong Song   uint32_t PTyTag = PTy->getTag();
53237d24a69SYonghong Song   assert(PTyTag == dwarf::DW_TAG_array_type ||
53337d24a69SYonghong Song          PTyTag == dwarf::DW_TAG_structure_type ||
53437d24a69SYonghong Song          PTyTag == dwarf::DW_TAG_union_type);
53537d24a69SYonghong Song 
53637d24a69SYonghong Song   uint32_t CTyTag = CTy->getTag();
53737d24a69SYonghong Song   assert(CTyTag == dwarf::DW_TAG_array_type ||
53837d24a69SYonghong Song          CTyTag == dwarf::DW_TAG_structure_type ||
53937d24a69SYonghong Song          CTyTag == dwarf::DW_TAG_union_type);
54037d24a69SYonghong Song 
54137d24a69SYonghong Song   // Multi dimensional arrays, base element should be the same
54237d24a69SYonghong Song   if (PTyTag == dwarf::DW_TAG_array_type && PTyTag == CTyTag)
54337d24a69SYonghong Song     return PTy->getBaseType() == CTy->getBaseType();
54437d24a69SYonghong Song 
54537d24a69SYonghong Song   DIType *Ty;
54637d24a69SYonghong Song   if (PTyTag == dwarf::DW_TAG_array_type)
54737d24a69SYonghong Song     Ty = PTy->getBaseType();
54837d24a69SYonghong Song   else
54937d24a69SYonghong Song     Ty = dyn_cast<DIType>(PTy->getElements()[ParentAI]);
55037d24a69SYonghong Song 
55137d24a69SYonghong Song   return dyn_cast<DICompositeType>(stripQualifiers(Ty)) == CTy;
55237d24a69SYonghong Song }
55337d24a69SYonghong Song 
traceAICall(CallInst * Call,CallInfo & ParentInfo)55402ac7509SYonghong Song void BPFAbstractMemberAccess::traceAICall(CallInst *Call,
55502ac7509SYonghong Song                                           CallInfo &ParentInfo) {
556a1b2a27aSYonghong Song   for (User *U : Call->users()) {
557a1b2a27aSYonghong Song     Instruction *Inst = dyn_cast<Instruction>(U);
558a1b2a27aSYonghong Song     if (!Inst)
559a1b2a27aSYonghong Song       continue;
560a1b2a27aSYonghong Song 
561a1b2a27aSYonghong Song     if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
56202ac7509SYonghong Song       traceBitCast(BI, Call, ParentInfo);
563a1b2a27aSYonghong Song     } else if (auto *CI = dyn_cast<CallInst>(Inst)) {
56402ac7509SYonghong Song       CallInfo ChildInfo;
56502ac7509SYonghong Song 
56602ac7509SYonghong Song       if (IsPreserveDIAccessIndexCall(CI, ChildInfo) &&
56702ac7509SYonghong Song           IsValidAIChain(ParentInfo.Metadata, ParentInfo.AccessIndex,
56802ac7509SYonghong Song                          ChildInfo.Metadata)) {
56902ac7509SYonghong Song         AIChain[CI] = std::make_pair(Call, ParentInfo);
57002ac7509SYonghong Song         traceAICall(CI, ChildInfo);
571a1b2a27aSYonghong Song       } else {
57202ac7509SYonghong Song         BaseAICalls[Call] = ParentInfo;
573a1b2a27aSYonghong Song       }
574a1b2a27aSYonghong Song     } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
575a1b2a27aSYonghong Song       if (GI->hasAllZeroIndices())
57602ac7509SYonghong Song         traceGEP(GI, Call, ParentInfo);
577a1b2a27aSYonghong Song       else
57802ac7509SYonghong Song         BaseAICalls[Call] = ParentInfo;
579c68ee0ceSYonghong Song     } else {
58002ac7509SYonghong Song       BaseAICalls[Call] = ParentInfo;
581a1b2a27aSYonghong Song     }
582a1b2a27aSYonghong Song   }
583a1b2a27aSYonghong Song }
584a1b2a27aSYonghong Song 
traceBitCast(BitCastInst * BitCast,CallInst * Parent,CallInfo & ParentInfo)585a1b2a27aSYonghong Song void BPFAbstractMemberAccess::traceBitCast(BitCastInst *BitCast,
58602ac7509SYonghong Song                                            CallInst *Parent,
58702ac7509SYonghong Song                                            CallInfo &ParentInfo) {
588a1b2a27aSYonghong Song   for (User *U : BitCast->users()) {
589a1b2a27aSYonghong Song     Instruction *Inst = dyn_cast<Instruction>(U);
590a1b2a27aSYonghong Song     if (!Inst)
591a1b2a27aSYonghong Song       continue;
592a1b2a27aSYonghong Song 
593a1b2a27aSYonghong Song     if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
59402ac7509SYonghong Song       traceBitCast(BI, Parent, ParentInfo);
595a1b2a27aSYonghong Song     } else if (auto *CI = dyn_cast<CallInst>(Inst)) {
59602ac7509SYonghong Song       CallInfo ChildInfo;
59702ac7509SYonghong Song       if (IsPreserveDIAccessIndexCall(CI, ChildInfo) &&
59802ac7509SYonghong Song           IsValidAIChain(ParentInfo.Metadata, ParentInfo.AccessIndex,
59902ac7509SYonghong Song                          ChildInfo.Metadata)) {
60002ac7509SYonghong Song         AIChain[CI] = std::make_pair(Parent, ParentInfo);
60102ac7509SYonghong Song         traceAICall(CI, ChildInfo);
602a1b2a27aSYonghong Song       } else {
60302ac7509SYonghong Song         BaseAICalls[Parent] = ParentInfo;
604a1b2a27aSYonghong Song       }
605a1b2a27aSYonghong Song     } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
606a1b2a27aSYonghong Song       if (GI->hasAllZeroIndices())
60702ac7509SYonghong Song         traceGEP(GI, Parent, ParentInfo);
608a1b2a27aSYonghong Song       else
60902ac7509SYonghong Song         BaseAICalls[Parent] = ParentInfo;
610c68ee0ceSYonghong Song     } else {
61102ac7509SYonghong Song       BaseAICalls[Parent] = ParentInfo;
612a1b2a27aSYonghong Song     }
613a1b2a27aSYonghong Song   }
614a1b2a27aSYonghong Song }
615a1b2a27aSYonghong Song 
traceGEP(GetElementPtrInst * GEP,CallInst * Parent,CallInfo & ParentInfo)616a1b2a27aSYonghong Song void BPFAbstractMemberAccess::traceGEP(GetElementPtrInst *GEP, CallInst *Parent,
61702ac7509SYonghong Song                                        CallInfo &ParentInfo) {
618a1b2a27aSYonghong Song   for (User *U : GEP->users()) {
619a1b2a27aSYonghong Song     Instruction *Inst = dyn_cast<Instruction>(U);
620a1b2a27aSYonghong Song     if (!Inst)
621a1b2a27aSYonghong Song       continue;
622a1b2a27aSYonghong Song 
623a1b2a27aSYonghong Song     if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
62402ac7509SYonghong Song       traceBitCast(BI, Parent, ParentInfo);
625a1b2a27aSYonghong Song     } else if (auto *CI = dyn_cast<CallInst>(Inst)) {
62602ac7509SYonghong Song       CallInfo ChildInfo;
62702ac7509SYonghong Song       if (IsPreserveDIAccessIndexCall(CI, ChildInfo) &&
62802ac7509SYonghong Song           IsValidAIChain(ParentInfo.Metadata, ParentInfo.AccessIndex,
62902ac7509SYonghong Song                          ChildInfo.Metadata)) {
63002ac7509SYonghong Song         AIChain[CI] = std::make_pair(Parent, ParentInfo);
63102ac7509SYonghong Song         traceAICall(CI, ChildInfo);
632a1b2a27aSYonghong Song       } else {
63302ac7509SYonghong Song         BaseAICalls[Parent] = ParentInfo;
634a1b2a27aSYonghong Song       }
635a1b2a27aSYonghong Song     } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
636a1b2a27aSYonghong Song       if (GI->hasAllZeroIndices())
63702ac7509SYonghong Song         traceGEP(GI, Parent, ParentInfo);
638a1b2a27aSYonghong Song       else
63902ac7509SYonghong Song         BaseAICalls[Parent] = ParentInfo;
640c68ee0ceSYonghong Song     } else {
64102ac7509SYonghong Song       BaseAICalls[Parent] = ParentInfo;
642a1b2a27aSYonghong Song     }
643a1b2a27aSYonghong Song   }
644a1b2a27aSYonghong Song }
645a1b2a27aSYonghong Song 
collectAICallChains(Function & F)64654d9f743SYonghong Song void BPFAbstractMemberAccess::collectAICallChains(Function &F) {
647a1b2a27aSYonghong Song   AIChain.clear();
648a1b2a27aSYonghong Song   BaseAICalls.clear();
649a1b2a27aSYonghong Song 
650a1b2a27aSYonghong Song   for (auto &BB : F)
651a1b2a27aSYonghong Song     for (auto &I : BB) {
65202ac7509SYonghong Song       CallInfo CInfo;
653a1b2a27aSYonghong Song       auto *Call = dyn_cast<CallInst>(&I);
65402ac7509SYonghong Song       if (!IsPreserveDIAccessIndexCall(Call, CInfo) ||
655a1b2a27aSYonghong Song           AIChain.find(Call) != AIChain.end())
656a1b2a27aSYonghong Song         continue;
657a1b2a27aSYonghong Song 
65802ac7509SYonghong Song       traceAICall(Call, CInfo);
659a1b2a27aSYonghong Song     }
660a1b2a27aSYonghong Song }
661a1b2a27aSYonghong Song 
getConstant(const Value * IndexValue)66202ac7509SYonghong Song uint64_t BPFAbstractMemberAccess::getConstant(const Value *IndexValue) {
663a1b2a27aSYonghong Song   const ConstantInt *CV = dyn_cast<ConstantInt>(IndexValue);
66402ac7509SYonghong Song   assert(CV);
66502ac7509SYonghong Song   return CV->getValue().getZExtValue();
666a1b2a27aSYonghong Song }
667a1b2a27aSYonghong Song 
66805e46979SYonghong Song /// Get the start and the end of storage offset for \p MemberTy.
GetStorageBitRange(DIDerivedType * MemberTy,Align RecordAlignment,uint32_t & StartBitOffset,uint32_t & EndBitOffset)669fff27212SYonghong Song void BPFAbstractMemberAccess::GetStorageBitRange(DIDerivedType *MemberTy,
6700f9d623bSGuillaume Chatelet                                                  Align RecordAlignment,
67105e46979SYonghong Song                                                  uint32_t &StartBitOffset,
67205e46979SYonghong Song                                                  uint32_t &EndBitOffset) {
673fff27212SYonghong Song   uint32_t MemberBitSize = MemberTy->getSizeInBits();
674fff27212SYonghong Song   uint32_t MemberBitOffset = MemberTy->getOffsetInBits();
67598e22744SYonghong Song 
67698e22744SYonghong Song   if (RecordAlignment > 8) {
67798e22744SYonghong Song     // If the Bits are within an aligned 8-byte, set the RecordAlignment
67898e22744SYonghong Song     // to 8, other report the fatal error.
67998e22744SYonghong Song     if (MemberBitOffset / 64 != (MemberBitOffset + MemberBitSize) / 64)
680fff27212SYonghong Song       report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info, "
681fff27212SYonghong Song                          "requiring too big alignment");
68298e22744SYonghong Song     RecordAlignment = Align(8);
68398e22744SYonghong Song   }
68498e22744SYonghong Song 
68598e22744SYonghong Song   uint32_t AlignBits = RecordAlignment.value() * 8;
68698e22744SYonghong Song   if (MemberBitSize > AlignBits)
68798e22744SYonghong Song     report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info, "
68898e22744SYonghong Song                        "bitfield size greater than record alignment");
68905e46979SYonghong Song 
690fff27212SYonghong Song   StartBitOffset = MemberBitOffset & ~(AlignBits - 1);
691fff27212SYonghong Song   if ((StartBitOffset + AlignBits) < (MemberBitOffset + MemberBitSize))
692fff27212SYonghong Song     report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info, "
693fff27212SYonghong Song                        "cross alignment boundary");
694fff27212SYonghong Song   EndBitOffset = StartBitOffset + AlignBits;
69505e46979SYonghong Song }
69605e46979SYonghong Song 
GetFieldInfo(uint32_t InfoKind,DICompositeType * CTy,uint32_t AccessIndex,uint32_t PatchImm,MaybeAlign RecordAlignment)69705e46979SYonghong Song uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind,
69805e46979SYonghong Song                                                DICompositeType *CTy,
69905e46979SYonghong Song                                                uint32_t AccessIndex,
700fff27212SYonghong Song                                                uint32_t PatchImm,
701c48b4641SNikita Popov                                                MaybeAlign RecordAlignment) {
70205e46979SYonghong Song   if (InfoKind == BPFCoreSharedInfo::FIELD_EXISTENCE)
70305e46979SYonghong Song       return 1;
70405e46979SYonghong Song 
70505e46979SYonghong Song   uint32_t Tag = CTy->getTag();
70605e46979SYonghong Song   if (InfoKind == BPFCoreSharedInfo::FIELD_BYTE_OFFSET) {
70705e46979SYonghong Song     if (Tag == dwarf::DW_TAG_array_type) {
70805e46979SYonghong Song       auto *EltTy = stripQualifiers(CTy->getBaseType());
70905e46979SYonghong Song       PatchImm += AccessIndex * calcArraySize(CTy, 1) *
71005e46979SYonghong Song                   (EltTy->getSizeInBits() >> 3);
71105e46979SYonghong Song     } else if (Tag == dwarf::DW_TAG_structure_type) {
71205e46979SYonghong Song       auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
71305e46979SYonghong Song       if (!MemberTy->isBitField()) {
71405e46979SYonghong Song         PatchImm += MemberTy->getOffsetInBits() >> 3;
71505e46979SYonghong Song       } else {
716fff27212SYonghong Song         unsigned SBitOffset, NextSBitOffset;
717c48b4641SNikita Popov         GetStorageBitRange(MemberTy, *RecordAlignment, SBitOffset,
718fff27212SYonghong Song                            NextSBitOffset);
719fff27212SYonghong Song         PatchImm += SBitOffset >> 3;
72005e46979SYonghong Song       }
72105e46979SYonghong Song     }
72205e46979SYonghong Song     return PatchImm;
72305e46979SYonghong Song   }
72405e46979SYonghong Song 
72505e46979SYonghong Song   if (InfoKind == BPFCoreSharedInfo::FIELD_BYTE_SIZE) {
72605e46979SYonghong Song     if (Tag == dwarf::DW_TAG_array_type) {
72705e46979SYonghong Song       auto *EltTy = stripQualifiers(CTy->getBaseType());
72805e46979SYonghong Song       return calcArraySize(CTy, 1) * (EltTy->getSizeInBits() >> 3);
72905e46979SYonghong Song     } else {
73005e46979SYonghong Song       auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
73105e46979SYonghong Song       uint32_t SizeInBits = MemberTy->getSizeInBits();
73205e46979SYonghong Song       if (!MemberTy->isBitField())
73305e46979SYonghong Song         return SizeInBits >> 3;
73405e46979SYonghong Song 
73505e46979SYonghong Song       unsigned SBitOffset, NextSBitOffset;
736c48b4641SNikita Popov       GetStorageBitRange(MemberTy, *RecordAlignment, SBitOffset,
737c48b4641SNikita Popov                          NextSBitOffset);
73805e46979SYonghong Song       SizeInBits = NextSBitOffset - SBitOffset;
73905e46979SYonghong Song       if (SizeInBits & (SizeInBits - 1))
74005e46979SYonghong Song         report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info");
74105e46979SYonghong Song       return SizeInBits >> 3;
74205e46979SYonghong Song     }
74305e46979SYonghong Song   }
74405e46979SYonghong Song 
74505e46979SYonghong Song   if (InfoKind == BPFCoreSharedInfo::FIELD_SIGNEDNESS) {
74605e46979SYonghong Song     const DIType *BaseTy;
74705e46979SYonghong Song     if (Tag == dwarf::DW_TAG_array_type) {
74805e46979SYonghong Song       // Signedness only checked when final array elements are accessed.
74905e46979SYonghong Song       if (CTy->getElements().size() != 1)
75005e46979SYonghong Song         report_fatal_error("Invalid array expression for llvm.bpf.preserve.field.info");
75105e46979SYonghong Song       BaseTy = stripQualifiers(CTy->getBaseType());
75205e46979SYonghong Song     } else {
75305e46979SYonghong Song       auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
75405e46979SYonghong Song       BaseTy = stripQualifiers(MemberTy->getBaseType());
75505e46979SYonghong Song     }
75605e46979SYonghong Song 
75705e46979SYonghong Song     // Only basic types and enum types have signedness.
75805e46979SYonghong Song     const auto *BTy = dyn_cast<DIBasicType>(BaseTy);
75905e46979SYonghong Song     while (!BTy) {
76005e46979SYonghong Song       const auto *CompTy = dyn_cast<DICompositeType>(BaseTy);
76105e46979SYonghong Song       // Report an error if the field expression does not have signedness.
76205e46979SYonghong Song       if (!CompTy || CompTy->getTag() != dwarf::DW_TAG_enumeration_type)
76305e46979SYonghong Song         report_fatal_error("Invalid field expression for llvm.bpf.preserve.field.info");
76405e46979SYonghong Song       BaseTy = stripQualifiers(CompTy->getBaseType());
76505e46979SYonghong Song       BTy = dyn_cast<DIBasicType>(BaseTy);
76605e46979SYonghong Song     }
76705e46979SYonghong Song     uint32_t Encoding = BTy->getEncoding();
76805e46979SYonghong Song     return (Encoding == dwarf::DW_ATE_signed || Encoding == dwarf::DW_ATE_signed_char);
76905e46979SYonghong Song   }
77005e46979SYonghong Song 
77105e46979SYonghong Song   if (InfoKind == BPFCoreSharedInfo::FIELD_LSHIFT_U64) {
77205e46979SYonghong Song     // The value is loaded into a value with FIELD_BYTE_SIZE size,
77305e46979SYonghong Song     // and then zero or sign extended to U64.
77405e46979SYonghong Song     // FIELD_LSHIFT_U64 and FIELD_RSHIFT_U64 are operations
77505e46979SYonghong Song     // to extract the original value.
77605e46979SYonghong Song     const Triple &Triple = TM->getTargetTriple();
77705e46979SYonghong Song     DIDerivedType *MemberTy = nullptr;
77805e46979SYonghong Song     bool IsBitField = false;
77905e46979SYonghong Song     uint32_t SizeInBits;
78005e46979SYonghong Song 
78105e46979SYonghong Song     if (Tag == dwarf::DW_TAG_array_type) {
78205e46979SYonghong Song       auto *EltTy = stripQualifiers(CTy->getBaseType());
78305e46979SYonghong Song       SizeInBits = calcArraySize(CTy, 1) * EltTy->getSizeInBits();
78405e46979SYonghong Song     } else {
78505e46979SYonghong Song       MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
78605e46979SYonghong Song       SizeInBits = MemberTy->getSizeInBits();
78705e46979SYonghong Song       IsBitField = MemberTy->isBitField();
78805e46979SYonghong Song     }
78905e46979SYonghong Song 
79005e46979SYonghong Song     if (!IsBitField) {
79105e46979SYonghong Song       if (SizeInBits > 64)
79205e46979SYonghong Song         report_fatal_error("too big field size for llvm.bpf.preserve.field.info");
79305e46979SYonghong Song       return 64 - SizeInBits;
79405e46979SYonghong Song     }
79505e46979SYonghong Song 
79605e46979SYonghong Song     unsigned SBitOffset, NextSBitOffset;
797c48b4641SNikita Popov     GetStorageBitRange(MemberTy, *RecordAlignment, SBitOffset, NextSBitOffset);
79805e46979SYonghong Song     if (NextSBitOffset - SBitOffset > 64)
79905e46979SYonghong Song       report_fatal_error("too big field size for llvm.bpf.preserve.field.info");
80005e46979SYonghong Song 
80105e46979SYonghong Song     unsigned OffsetInBits = MemberTy->getOffsetInBits();
80205e46979SYonghong Song     if (Triple.getArch() == Triple::bpfel)
80305e46979SYonghong Song       return SBitOffset + 64 - OffsetInBits - SizeInBits;
80405e46979SYonghong Song     else
80505e46979SYonghong Song       return OffsetInBits + 64 - NextSBitOffset;
80605e46979SYonghong Song   }
80705e46979SYonghong Song 
80805e46979SYonghong Song   if (InfoKind == BPFCoreSharedInfo::FIELD_RSHIFT_U64) {
80905e46979SYonghong Song     DIDerivedType *MemberTy = nullptr;
81005e46979SYonghong Song     bool IsBitField = false;
81105e46979SYonghong Song     uint32_t SizeInBits;
81205e46979SYonghong Song     if (Tag == dwarf::DW_TAG_array_type) {
81305e46979SYonghong Song       auto *EltTy = stripQualifiers(CTy->getBaseType());
81405e46979SYonghong Song       SizeInBits = calcArraySize(CTy, 1) * EltTy->getSizeInBits();
81505e46979SYonghong Song     } else {
81605e46979SYonghong Song       MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
81705e46979SYonghong Song       SizeInBits = MemberTy->getSizeInBits();
81805e46979SYonghong Song       IsBitField = MemberTy->isBitField();
81905e46979SYonghong Song     }
82005e46979SYonghong Song 
82105e46979SYonghong Song     if (!IsBitField) {
82205e46979SYonghong Song       if (SizeInBits > 64)
82305e46979SYonghong Song         report_fatal_error("too big field size for llvm.bpf.preserve.field.info");
82405e46979SYonghong Song       return 64 - SizeInBits;
82505e46979SYonghong Song     }
82605e46979SYonghong Song 
82705e46979SYonghong Song     unsigned SBitOffset, NextSBitOffset;
828c48b4641SNikita Popov     GetStorageBitRange(MemberTy, *RecordAlignment, SBitOffset, NextSBitOffset);
82905e46979SYonghong Song     if (NextSBitOffset - SBitOffset > 64)
83005e46979SYonghong Song       report_fatal_error("too big field size for llvm.bpf.preserve.field.info");
83105e46979SYonghong Song 
83205e46979SYonghong Song     return 64 - SizeInBits;
83305e46979SYonghong Song   }
83405e46979SYonghong Song 
83505e46979SYonghong Song   llvm_unreachable("Unknown llvm.bpf.preserve.field.info info kind");
83605e46979SYonghong Song }
83705e46979SYonghong Song 
HasPreserveFieldInfoCall(CallInfoStack & CallStack)83805e46979SYonghong Song bool BPFAbstractMemberAccess::HasPreserveFieldInfoCall(CallInfoStack &CallStack) {
83905e46979SYonghong Song   // This is called in error return path, no need to maintain CallStack.
84005e46979SYonghong Song   while (CallStack.size()) {
84105e46979SYonghong Song     auto StackElem = CallStack.top();
84205e46979SYonghong Song     if (StackElem.second.Kind == BPFPreserveFieldInfoAI)
84305e46979SYonghong Song       return true;
84405e46979SYonghong Song     CallStack.pop();
84505e46979SYonghong Song   }
84605e46979SYonghong Song   return false;
84705e46979SYonghong Song }
84805e46979SYonghong Song 
84905e46979SYonghong Song /// Compute the base of the whole preserve_* intrinsics chains, i.e., the base
850a1b2a27aSYonghong Song /// pointer of the first preserve_*_access_index call, and construct the access
851a1b2a27aSYonghong Song /// string, which will be the name of a global variable.
computeBaseAndAccessKey(CallInst * Call,CallInfo & CInfo,std::string & AccessKey,MDNode * & TypeMeta)852d8efec97SYonghong Song Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
85302ac7509SYonghong Song                                                         CallInfo &CInfo,
854a1b2a27aSYonghong Song                                                         std::string &AccessKey,
855a1b2a27aSYonghong Song                                                         MDNode *&TypeMeta) {
856a1b2a27aSYonghong Song   Value *Base = nullptr;
85737d24a69SYonghong Song   std::string TypeName;
85805e46979SYonghong Song   CallInfoStack CallStack;
859a1b2a27aSYonghong Song 
86037d24a69SYonghong Song   // Put the access chain into a stack with the top as the head of the chain.
861a1b2a27aSYonghong Song   while (Call) {
86202ac7509SYonghong Song     CallStack.push(std::make_pair(Call, CInfo));
86302ac7509SYonghong Song     CInfo = AIChain[Call].second;
86437d24a69SYonghong Song     Call = AIChain[Call].first;
86537d24a69SYonghong Song   }
86637d24a69SYonghong Song 
86737d24a69SYonghong Song   // The access offset from the base of the head of chain is also
86837d24a69SYonghong Song   // calculated here as all debuginfo types are available.
86937d24a69SYonghong Song 
87037d24a69SYonghong Song   // Get type name and calculate the first index.
8716d07802dSYonghong Song   // We only want to get type name from typedef, structure or union.
87237d24a69SYonghong Song   // If user wants a relocation like
87337d24a69SYonghong Song   //    int *p; ... __builtin_preserve_access_index(&p[4]) ...
87437d24a69SYonghong Song   // or
87537d24a69SYonghong Song   //    int a[10][20]; ... __builtin_preserve_access_index(&a[2][3]) ...
87637d24a69SYonghong Song   // we will skip them.
87737d24a69SYonghong Song   uint32_t FirstIndex = 0;
87805e46979SYonghong Song   uint32_t PatchImm = 0; // AccessOffset or the requested field info
87905e46979SYonghong Song   uint32_t InfoKind = BPFCoreSharedInfo::FIELD_BYTE_OFFSET;
88037d24a69SYonghong Song   while (CallStack.size()) {
88137d24a69SYonghong Song     auto StackElem = CallStack.top();
88237d24a69SYonghong Song     Call = StackElem.first;
88302ac7509SYonghong Song     CInfo = StackElem.second;
88437d24a69SYonghong Song 
88537d24a69SYonghong Song     if (!Base)
88602ac7509SYonghong Song       Base = CInfo.Base;
887a1b2a27aSYonghong Song 
8886d07802dSYonghong Song     DIType *PossibleTypeDef = stripQualifiers(cast<DIType>(CInfo.Metadata),
8896d07802dSYonghong Song                                               false);
8906d07802dSYonghong Song     DIType *Ty = stripQualifiers(PossibleTypeDef);
89102ac7509SYonghong Song     if (CInfo.Kind == BPFPreserveUnionAI ||
89202ac7509SYonghong Song         CInfo.Kind == BPFPreserveStructAI) {
8936d07802dSYonghong Song       // struct or union type. If the typedef is in the metadata, always
8946d07802dSYonghong Song       // use the typedef.
8956d07802dSYonghong Song       TypeName = std::string(PossibleTypeDef->getName());
8966d07802dSYonghong Song       TypeMeta = PossibleTypeDef;
89705e46979SYonghong Song       PatchImm += FirstIndex * (Ty->getSizeInBits() >> 3);
89837d24a69SYonghong Song       break;
899a1b2a27aSYonghong Song     }
900a1b2a27aSYonghong Song 
90105e46979SYonghong Song     assert(CInfo.Kind == BPFPreserveArrayAI);
90205e46979SYonghong Song 
90337d24a69SYonghong Song     // Array entries will always be consumed for accumulative initial index.
90437d24a69SYonghong Song     CallStack.pop();
90537d24a69SYonghong Song 
90637d24a69SYonghong Song     // BPFPreserveArrayAI
90702ac7509SYonghong Song     uint64_t AccessIndex = CInfo.AccessIndex;
90837d24a69SYonghong Song 
90937d24a69SYonghong Song     DIType *BaseTy = nullptr;
91037d24a69SYonghong Song     bool CheckElemType = false;
91137d24a69SYonghong Song     if (const auto *CTy = dyn_cast<DICompositeType>(Ty)) {
91237d24a69SYonghong Song       // array type
91337d24a69SYonghong Song       assert(CTy->getTag() == dwarf::DW_TAG_array_type);
91437d24a69SYonghong Song 
91537d24a69SYonghong Song 
91637d24a69SYonghong Song       FirstIndex += AccessIndex * calcArraySize(CTy, 1);
91737d24a69SYonghong Song       BaseTy = stripQualifiers(CTy->getBaseType());
91837d24a69SYonghong Song       CheckElemType = CTy->getElements().size() == 1;
91937d24a69SYonghong Song     } else {
92037d24a69SYonghong Song       // pointer type
92137d24a69SYonghong Song       auto *DTy = cast<DIDerivedType>(Ty);
92237d24a69SYonghong Song       assert(DTy->getTag() == dwarf::DW_TAG_pointer_type);
92337d24a69SYonghong Song 
92437d24a69SYonghong Song       BaseTy = stripQualifiers(DTy->getBaseType());
92537d24a69SYonghong Song       CTy = dyn_cast<DICompositeType>(BaseTy);
92637d24a69SYonghong Song       if (!CTy) {
92737d24a69SYonghong Song         CheckElemType = true;
92837d24a69SYonghong Song       } else if (CTy->getTag() != dwarf::DW_TAG_array_type) {
92937d24a69SYonghong Song         FirstIndex += AccessIndex;
93037d24a69SYonghong Song         CheckElemType = true;
93137d24a69SYonghong Song       } else {
93237d24a69SYonghong Song         FirstIndex += AccessIndex * calcArraySize(CTy, 0);
93337d24a69SYonghong Song       }
93437d24a69SYonghong Song     }
93537d24a69SYonghong Song 
93637d24a69SYonghong Song     if (CheckElemType) {
93737d24a69SYonghong Song       auto *CTy = dyn_cast<DICompositeType>(BaseTy);
93805e46979SYonghong Song       if (!CTy) {
93905e46979SYonghong Song         if (HasPreserveFieldInfoCall(CallStack))
94005e46979SYonghong Song           report_fatal_error("Invalid field access for llvm.preserve.field.info intrinsic");
94137d24a69SYonghong Song         return nullptr;
94205e46979SYonghong Song       }
94337d24a69SYonghong Song 
94437d24a69SYonghong Song       unsigned CTag = CTy->getTag();
94505e46979SYonghong Song       if (CTag == dwarf::DW_TAG_structure_type || CTag == dwarf::DW_TAG_union_type) {
946adcd0268SBenjamin Kramer         TypeName = std::string(CTy->getName());
94705e46979SYonghong Song       } else {
94805e46979SYonghong Song         if (HasPreserveFieldInfoCall(CallStack))
94905e46979SYonghong Song           report_fatal_error("Invalid field access for llvm.preserve.field.info intrinsic");
95005e46979SYonghong Song         return nullptr;
95105e46979SYonghong Song       }
95237d24a69SYonghong Song       TypeMeta = CTy;
95305e46979SYonghong Song       PatchImm += FirstIndex * (CTy->getSizeInBits() >> 3);
95437d24a69SYonghong Song       break;
95537d24a69SYonghong Song     }
95637d24a69SYonghong Song   }
95737d24a69SYonghong Song   assert(TypeName.size());
95837d24a69SYonghong Song   AccessKey += std::to_string(FirstIndex);
95937d24a69SYonghong Song 
96037d24a69SYonghong Song   // Traverse the rest of access chain to complete offset calculation
96137d24a69SYonghong Song   // and access key construction.
96237d24a69SYonghong Song   while (CallStack.size()) {
96337d24a69SYonghong Song     auto StackElem = CallStack.top();
96402ac7509SYonghong Song     CInfo = StackElem.second;
96537d24a69SYonghong Song     CallStack.pop();
96637d24a69SYonghong Song 
9677f6bc84aSYonghong Song     if (CInfo.Kind == BPFPreserveFieldInfoAI) {
9687f6bc84aSYonghong Song       InfoKind = CInfo.AccessIndex;
969605c811dSYonghong Song       if (InfoKind == BPFCoreSharedInfo::FIELD_EXISTENCE)
970605c811dSYonghong Song         PatchImm = 1;
97105e46979SYonghong Song       break;
9727f6bc84aSYonghong Song     }
97305e46979SYonghong Song 
97405e46979SYonghong Song     // If the next Call (the top of the stack) is a BPFPreserveFieldInfoAI,
97505e46979SYonghong Song     // the action will be extracting field info.
97605e46979SYonghong Song     if (CallStack.size()) {
97705e46979SYonghong Song       auto StackElem2 = CallStack.top();
97805e46979SYonghong Song       CallInfo CInfo2 = StackElem2.second;
97905e46979SYonghong Song       if (CInfo2.Kind == BPFPreserveFieldInfoAI) {
98005e46979SYonghong Song         InfoKind = CInfo2.AccessIndex;
98105e46979SYonghong Song         assert(CallStack.size() == 1);
98205e46979SYonghong Song       }
98305e46979SYonghong Song     }
98405e46979SYonghong Song 
985a1b2a27aSYonghong Song     // Access Index
98602ac7509SYonghong Song     uint64_t AccessIndex = CInfo.AccessIndex;
98737d24a69SYonghong Song     AccessKey += ":" + std::to_string(AccessIndex);
988a1b2a27aSYonghong Song 
98902ac7509SYonghong Song     MDNode *MDN = CInfo.Metadata;
99037d24a69SYonghong Song     // At this stage, it cannot be pointer type.
99137d24a69SYonghong Song     auto *CTy = cast<DICompositeType>(stripQualifiers(cast<DIType>(MDN)));
992fff27212SYonghong Song     PatchImm = GetFieldInfo(InfoKind, CTy, AccessIndex, PatchImm,
9930f9d623bSGuillaume Chatelet                             CInfo.RecordAlignment);
994a1b2a27aSYonghong Song   }
995a1b2a27aSYonghong Song 
9966db023b9SYonghong Song   // Access key is the
9976db023b9SYonghong Song   //   "llvm." + type name + ":" + reloc type + ":" + patched imm + "$" +
9986db023b9SYonghong Song   //   access string,
99905e46979SYonghong Song   // uniquely identifying one relocation.
10006db023b9SYonghong Song   // The prefix "llvm." indicates this is a temporary global, which should
10016db023b9SYonghong Song   // not be emitted to ELF file.
10026db023b9SYonghong Song   AccessKey = "llvm." + TypeName + ":" + std::to_string(InfoKind) + ":" +
100305e46979SYonghong Song               std::to_string(PatchImm) + "$" + AccessKey;
1004a1b2a27aSYonghong Song 
1005a1b2a27aSYonghong Song   return Base;
1006a1b2a27aSYonghong Song }
1007a1b2a27aSYonghong Song 
computeAccessKey(CallInst * Call,CallInfo & CInfo,std::string & AccessKey,bool & IsInt32Ret)10086d218b4aSYonghong Song MDNode *BPFAbstractMemberAccess::computeAccessKey(CallInst *Call,
10096d218b4aSYonghong Song                                                   CallInfo &CInfo,
10106d218b4aSYonghong Song                                                   std::string &AccessKey,
10116d218b4aSYonghong Song                                                   bool &IsInt32Ret) {
10126d218b4aSYonghong Song   DIType *Ty = stripQualifiers(cast<DIType>(CInfo.Metadata), false);
10136d218b4aSYonghong Song   assert(!Ty->getName().empty());
10146d218b4aSYonghong Song 
10156d218b4aSYonghong Song   int64_t PatchImm;
10166d218b4aSYonghong Song   std::string AccessStr("0");
1017d129ac27SDaniel Müller   if (CInfo.AccessIndex == BPFCoreSharedInfo::TYPE_EXISTENCE ||
1018d129ac27SDaniel Müller       CInfo.AccessIndex == BPFCoreSharedInfo::TYPE_MATCH) {
10196d218b4aSYonghong Song     PatchImm = 1;
10206d218b4aSYonghong Song   } else if (CInfo.AccessIndex == BPFCoreSharedInfo::TYPE_SIZE) {
10216d218b4aSYonghong Song     // typedef debuginfo type has size 0, get the eventual base type.
10226d218b4aSYonghong Song     DIType *BaseTy = stripQualifiers(Ty, true);
10236d218b4aSYonghong Song     PatchImm = BaseTy->getSizeInBits() / 8;
10246d218b4aSYonghong Song   } else {
10256d218b4aSYonghong Song     // ENUM_VALUE_EXISTENCE and ENUM_VALUE
10266d218b4aSYonghong Song     IsInt32Ret = false;
10276d218b4aSYonghong Song 
10286ee71e53SYonghong Song     // The argument could be a global variable or a getelementptr with base to
10296ee71e53SYonghong Song     // a global variable depending on whether the clang option `opaque-options`
10306ee71e53SYonghong Song     // is set or not.
10316ee71e53SYonghong Song     const GlobalVariable *GV =
10326ee71e53SYonghong Song         cast<GlobalVariable>(Call->getArgOperand(1)->stripPointerCasts());
10336d218b4aSYonghong Song     assert(GV->hasInitializer());
10346d218b4aSYonghong Song     const ConstantDataArray *DA = cast<ConstantDataArray>(GV->getInitializer());
10356d218b4aSYonghong Song     assert(DA->isString());
10366d218b4aSYonghong Song     StringRef ValueStr = DA->getAsString();
10376d218b4aSYonghong Song 
10386d218b4aSYonghong Song     // ValueStr format: <EnumeratorStr>:<Value>
10396d218b4aSYonghong Song     size_t Separator = ValueStr.find_first_of(':');
10406d218b4aSYonghong Song     StringRef EnumeratorStr = ValueStr.substr(0, Separator);
10416d218b4aSYonghong Song 
10426d218b4aSYonghong Song     // Find enumerator index in the debuginfo
10436d218b4aSYonghong Song     DIType *BaseTy = stripQualifiers(Ty, true);
10446d218b4aSYonghong Song     const auto *CTy = cast<DICompositeType>(BaseTy);
10456d218b4aSYonghong Song     assert(CTy->getTag() == dwarf::DW_TAG_enumeration_type);
10466d218b4aSYonghong Song     int EnumIndex = 0;
10476d218b4aSYonghong Song     for (const auto Element : CTy->getElements()) {
10486d218b4aSYonghong Song       const auto *Enum = cast<DIEnumerator>(Element);
10496d218b4aSYonghong Song       if (Enum->getName() == EnumeratorStr) {
10506d218b4aSYonghong Song         AccessStr = std::to_string(EnumIndex);
10516d218b4aSYonghong Song         break;
10526d218b4aSYonghong Song       }
10536d218b4aSYonghong Song       EnumIndex++;
10546d218b4aSYonghong Song     }
10556d218b4aSYonghong Song 
10566d218b4aSYonghong Song     if (CInfo.AccessIndex == BPFCoreSharedInfo::ENUM_VALUE) {
10576d218b4aSYonghong Song       StringRef EValueStr = ValueStr.substr(Separator + 1);
10586d218b4aSYonghong Song       PatchImm = std::stoll(std::string(EValueStr));
10596d218b4aSYonghong Song     } else {
10606d218b4aSYonghong Song       PatchImm = 1;
10616d218b4aSYonghong Song     }
10626d218b4aSYonghong Song   }
10636d218b4aSYonghong Song 
10646d218b4aSYonghong Song   AccessKey = "llvm." + Ty->getName().str() + ":" +
10656d218b4aSYonghong Song               std::to_string(CInfo.AccessIndex) + std::string(":") +
10666d218b4aSYonghong Song               std::to_string(PatchImm) + std::string("$") + AccessStr;
10676d218b4aSYonghong Song 
10686d218b4aSYonghong Song   return Ty;
10696d218b4aSYonghong Song }
10706d218b4aSYonghong Song 
1071a1b2a27aSYonghong Song /// Call/Kind is the base preserve_*_access_index() call. Attempts to do
1072a1b2a27aSYonghong Song /// transformation to a chain of relocable GEPs.
transformGEPChain(CallInst * Call,CallInfo & CInfo)107354d9f743SYonghong Song bool BPFAbstractMemberAccess::transformGEPChain(CallInst *Call,
107402ac7509SYonghong Song                                                 CallInfo &CInfo) {
1075d8efec97SYonghong Song   std::string AccessKey;
107637d24a69SYonghong Song   MDNode *TypeMeta;
10776d218b4aSYonghong Song   Value *Base = nullptr;
10786d218b4aSYonghong Song   bool IsInt32Ret;
10796d218b4aSYonghong Song 
10806d218b4aSYonghong Song   IsInt32Ret = CInfo.Kind == BPFPreserveFieldInfoAI;
10816d218b4aSYonghong Song   if (CInfo.Kind == BPFPreserveFieldInfoAI && CInfo.Metadata) {
10826d218b4aSYonghong Song     TypeMeta = computeAccessKey(Call, CInfo, AccessKey, IsInt32Ret);
10836d218b4aSYonghong Song   } else {
10846d218b4aSYonghong Song     Base = computeBaseAndAccessKey(Call, CInfo, AccessKey, TypeMeta);
1085a1b2a27aSYonghong Song     if (!Base)
1086a1b2a27aSYonghong Song       return false;
10876d218b4aSYonghong Song   }
1088a1b2a27aSYonghong Song 
108905e46979SYonghong Song   BasicBlock *BB = Call->getParent();
109005e46979SYonghong Song   GlobalVariable *GV;
109105e46979SYonghong Song 
109205e46979SYonghong Song   if (GEPGlobals.find(AccessKey) == GEPGlobals.end()) {
109305e46979SYonghong Song     IntegerType *VarType;
10946d218b4aSYonghong Song     if (IsInt32Ret)
109505e46979SYonghong Song       VarType = Type::getInt32Ty(BB->getContext()); // 32bit return value
109605e46979SYonghong Song     else
10976d218b4aSYonghong Song       VarType = Type::getInt64Ty(BB->getContext()); // 64bit ptr or enum value
109805e46979SYonghong Song 
109954d9f743SYonghong Song     GV = new GlobalVariable(*M, VarType, false, GlobalVariable::ExternalLinkage,
11005a667c0eSKazu Hirata                             nullptr, AccessKey);
110105e46979SYonghong Song     GV->addAttribute(BPFCoreSharedInfo::AmaAttr);
110205e46979SYonghong Song     GV->setMetadata(LLVMContext::MD_preserve_access_index, TypeMeta);
110305e46979SYonghong Song     GEPGlobals[AccessKey] = GV;
110405e46979SYonghong Song   } else {
110505e46979SYonghong Song     GV = GEPGlobals[AccessKey];
110605e46979SYonghong Song   }
110705e46979SYonghong Song 
110805e46979SYonghong Song   if (CInfo.Kind == BPFPreserveFieldInfoAI) {
110905e46979SYonghong Song     // Load the global variable which represents the returned field info.
11106d218b4aSYonghong Song     LoadInst *LDInst;
11116d218b4aSYonghong Song     if (IsInt32Ret)
11126d218b4aSYonghong Song       LDInst = new LoadInst(Type::getInt32Ty(BB->getContext()), GV, "", Call);
11136d218b4aSYonghong Song     else
11146d218b4aSYonghong Song       LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV, "", Call);
111554d9f743SYonghong Song 
111654d9f743SYonghong Song     Instruction *PassThroughInst =
111754d9f743SYonghong Song         BPFCoreSharedInfo::insertPassThrough(M, BB, LDInst, Call);
111854d9f743SYonghong Song     Call->replaceAllUsesWith(PassThroughInst);
111905e46979SYonghong Song     Call->eraseFromParent();
112005e46979SYonghong Song     return true;
112105e46979SYonghong Song   }
112205e46979SYonghong Song 
1123a1b2a27aSYonghong Song   // For any original GEP Call and Base %2 like
1124a1b2a27aSYonghong Song   //   %4 = bitcast %struct.net_device** %dev1 to i64*
1125a1b2a27aSYonghong Song   // it is transformed to:
112654d9f743SYonghong Song   //   %6 = load llvm.sk_buff:0:50$0:0:0:2:0
1127a1b2a27aSYonghong Song   //   %7 = bitcast %struct.sk_buff* %2 to i8*
1128a1b2a27aSYonghong Song   //   %8 = getelementptr i8, i8* %7, %6
1129a1b2a27aSYonghong Song   //   %9 = bitcast i8* %8 to i64*
1130a1b2a27aSYonghong Song   //   using %9 instead of %4
1131a1b2a27aSYonghong Song   // The original Call inst is removed.
1132a1b2a27aSYonghong Song 
1133a1b2a27aSYonghong Song   // Load the global variable.
1134565b56a7SEli Friedman   auto *LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV, "", Call);
1135a1b2a27aSYonghong Song 
1136a1b2a27aSYonghong Song   // Generate a BitCast
1137a1b2a27aSYonghong Song   auto *BCInst = new BitCastInst(Base, Type::getInt8PtrTy(BB->getContext()));
1138a1b2a27aSYonghong Song   BB->getInstList().insert(Call->getIterator(), BCInst);
1139a1b2a27aSYonghong Song 
1140a1b2a27aSYonghong Song   // Generate a GetElementPtr
1141a1b2a27aSYonghong Song   auto *GEP = GetElementPtrInst::Create(Type::getInt8Ty(BB->getContext()),
1142a1b2a27aSYonghong Song                                         BCInst, LDInst);
1143a1b2a27aSYonghong Song   BB->getInstList().insert(Call->getIterator(), GEP);
1144a1b2a27aSYonghong Song 
1145a1b2a27aSYonghong Song   // Generate a BitCast
1146a1b2a27aSYonghong Song   auto *BCInst2 = new BitCastInst(GEP, Call->getType());
1147a1b2a27aSYonghong Song   BB->getInstList().insert(Call->getIterator(), BCInst2);
1148a1b2a27aSYonghong Song 
114954d9f743SYonghong Song   // For the following code,
115054d9f743SYonghong Song   //    Block0:
115154d9f743SYonghong Song   //      ...
115254d9f743SYonghong Song   //      if (...) goto Block1 else ...
115354d9f743SYonghong Song   //    Block1:
115454d9f743SYonghong Song   //      %6 = load llvm.sk_buff:0:50$0:0:0:2:0
115554d9f743SYonghong Song   //      %7 = bitcast %struct.sk_buff* %2 to i8*
115654d9f743SYonghong Song   //      %8 = getelementptr i8, i8* %7, %6
115754d9f743SYonghong Song   //      ...
115854d9f743SYonghong Song   //      goto CommonExit
115954d9f743SYonghong Song   //    Block2:
116054d9f743SYonghong Song   //      ...
116154d9f743SYonghong Song   //      if (...) goto Block3 else ...
116254d9f743SYonghong Song   //    Block3:
116354d9f743SYonghong Song   //      %6 = load llvm.bpf_map:0:40$0:0:0:2:0
116454d9f743SYonghong Song   //      %7 = bitcast %struct.sk_buff* %2 to i8*
116554d9f743SYonghong Song   //      %8 = getelementptr i8, i8* %7, %6
116654d9f743SYonghong Song   //      ...
116754d9f743SYonghong Song   //      goto CommonExit
116854d9f743SYonghong Song   //    CommonExit
116954d9f743SYonghong Song   // SimplifyCFG may generate:
117054d9f743SYonghong Song   //    Block0:
117154d9f743SYonghong Song   //      ...
117254d9f743SYonghong Song   //      if (...) goto Block_Common else ...
117354d9f743SYonghong Song   //     Block2:
117454d9f743SYonghong Song   //       ...
117554d9f743SYonghong Song   //      if (...) goto Block_Common else ...
117654d9f743SYonghong Song   //    Block_Common:
117754d9f743SYonghong Song   //      PHI = [llvm.sk_buff:0:50$0:0:0:2:0, llvm.bpf_map:0:40$0:0:0:2:0]
117854d9f743SYonghong Song   //      %6 = load PHI
117954d9f743SYonghong Song   //      %7 = bitcast %struct.sk_buff* %2 to i8*
118054d9f743SYonghong Song   //      %8 = getelementptr i8, i8* %7, %6
118154d9f743SYonghong Song   //      ...
118254d9f743SYonghong Song   //      goto CommonExit
118354d9f743SYonghong Song   //  For the above code, we cannot perform proper relocation since
118454d9f743SYonghong Song   //  "load PHI" has two possible relocations.
118554d9f743SYonghong Song   //
118654d9f743SYonghong Song   // To prevent above tail merging, we use __builtin_bpf_passthrough()
118754d9f743SYonghong Song   // where one of its parameters is a seq_num. Since two
118854d9f743SYonghong Song   // __builtin_bpf_passthrough() funcs will always have different seq_num,
118954d9f743SYonghong Song   // tail merging cannot happen. The __builtin_bpf_passthrough() will be
119054d9f743SYonghong Song   // removed in the beginning of Target IR passes.
119154d9f743SYonghong Song   //
119254d9f743SYonghong Song   // This approach is also used in other places when global var
119354d9f743SYonghong Song   // representing a relocation is used.
119454d9f743SYonghong Song   Instruction *PassThroughInst =
119554d9f743SYonghong Song       BPFCoreSharedInfo::insertPassThrough(M, BB, BCInst2, Call);
119654d9f743SYonghong Song   Call->replaceAllUsesWith(PassThroughInst);
1197a1b2a27aSYonghong Song   Call->eraseFromParent();
1198a1b2a27aSYonghong Song 
1199a1b2a27aSYonghong Song   return true;
1200a1b2a27aSYonghong Song }
1201a1b2a27aSYonghong Song 
doTransformation(Function & F)120254d9f743SYonghong Song bool BPFAbstractMemberAccess::doTransformation(Function &F) {
1203a1b2a27aSYonghong Song   bool Transformed = false;
1204a1b2a27aSYonghong Song 
1205a1b2a27aSYonghong Song   // Collect PreserveDIAccessIndex Intrinsic call chains.
1206a1b2a27aSYonghong Song   // The call chains will be used to generate the access
1207a1b2a27aSYonghong Song   // patterns similar to GEP.
120854d9f743SYonghong Song   collectAICallChains(F);
1209a1b2a27aSYonghong Song 
1210a1b2a27aSYonghong Song   for (auto &C : BaseAICalls)
121154d9f743SYonghong Song     Transformed = transformGEPChain(C.first, C.second) || Transformed;
1212a1b2a27aSYonghong Song 
121354d9f743SYonghong Song   return removePreserveAccessIndexIntrinsic(F) || Transformed;
1214a1b2a27aSYonghong Song }
121540251feeSArthur Eubanks 
121640251feeSArthur Eubanks PreservedAnalyses
run(Function & F,FunctionAnalysisManager & AM)121740251feeSArthur Eubanks BPFAbstractMemberAccessPass::run(Function &F, FunctionAnalysisManager &AM) {
121840251feeSArthur Eubanks   return BPFAbstractMemberAccess(TM).run(F) ? PreservedAnalyses::none()
121940251feeSArthur Eubanks                                             : PreservedAnalyses::all();
122040251feeSArthur Eubanks }
1221