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