aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp323
1 files changed, 254 insertions, 69 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
index 16708c4d1ce6..cd994a9c8365 100644
--- a/contrib/llvm-project/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
+++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
@@ -81,7 +81,9 @@
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicsBPF.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/User.h"
#include "llvm/IR/Value.h"
@@ -93,26 +95,30 @@
namespace llvm {
constexpr StringRef BPFCoreSharedInfo::AmaAttr;
+uint32_t BPFCoreSharedInfo::SeqNum;
+
+Instruction *BPFCoreSharedInfo::insertPassThrough(Module *M, BasicBlock *BB,
+ Instruction *Input,
+ Instruction *Before) {
+ Function *Fn = Intrinsic::getDeclaration(
+ M, Intrinsic::bpf_passthrough, {Input->getType(), Input->getType()});
+ Constant *SeqNumVal = ConstantInt::get(Type::getInt32Ty(BB->getContext()),
+ BPFCoreSharedInfo::SeqNum++);
+
+ auto *NewInst = CallInst::Create(Fn, {SeqNumVal, Input});
+ BB->getInstList().insert(Before->getIterator(), NewInst);
+ return NewInst;
+}
} // namespace llvm
using namespace llvm;
namespace {
-
-class BPFAbstractMemberAccess final : public ModulePass {
- StringRef getPassName() const override {
- return "BPF Abstract Member Access";
- }
-
- bool runOnModule(Module &M) override;
-
+class BPFAbstractMemberAccess final {
public:
- static char ID;
- TargetMachine *TM;
- // Add optional BPFTargetMachine parameter so that BPF backend can add the phase
- // with target machine to find out the endianness. The default constructor (without
- // parameters) is used by the pass manager for managing purposes.
- BPFAbstractMemberAccess(BPFTargetMachine *TM = nullptr) : ModulePass(ID), TM(TM) {}
+ BPFAbstractMemberAccess(BPFTargetMachine *TM) : TM(TM) {}
+
+ bool run(Function &F);
struct CallInfo {
uint32_t Kind;
@@ -131,9 +137,11 @@ private:
BPFPreserveFieldInfoAI = 4,
};
+ TargetMachine *TM;
const DataLayout *DL = nullptr;
+ Module *M = nullptr;
- std::map<std::string, GlobalVariable *> GEPGlobals;
+ static std::map<std::string, GlobalVariable *> GEPGlobals;
// A map to link preserve_*_access_index instrinsic calls.
std::map<CallInst *, std::pair<CallInst *, CallInfo>> AIChain;
// A map to hold all the base preserve_*_access_index instrinsic calls.
@@ -141,19 +149,19 @@ private:
// intrinsics.
std::map<CallInst *, CallInfo> BaseAICalls;
- bool doTransformation(Module &M);
+ bool doTransformation(Function &F);
void traceAICall(CallInst *Call, CallInfo &ParentInfo);
void traceBitCast(BitCastInst *BitCast, CallInst *Parent,
CallInfo &ParentInfo);
void traceGEP(GetElementPtrInst *GEP, CallInst *Parent,
CallInfo &ParentInfo);
- void collectAICallChains(Module &M, Function &F);
+ void collectAICallChains(Function &F);
bool IsPreserveDIAccessIndexCall(const CallInst *Call, CallInfo &Cinfo);
bool IsValidAIChain(const MDNode *ParentMeta, uint32_t ParentAI,
const MDNode *ChildMeta);
- bool removePreserveAccessIndexIntrinsic(Module &M);
+ bool removePreserveAccessIndexIntrinsic(Function &F);
void replaceWithGEP(std::vector<CallInst *> &CallList,
uint32_t NumOfZerosIndex, uint32_t DIIndex);
bool HasPreserveFieldInfoCall(CallInfoStack &CallStack);
@@ -165,28 +173,55 @@ private:
Value *computeBaseAndAccessKey(CallInst *Call, CallInfo &CInfo,
std::string &AccessKey, MDNode *&BaseMeta);
+ MDNode *computeAccessKey(CallInst *Call, CallInfo &CInfo,
+ std::string &AccessKey, bool &IsInt32Ret);
uint64_t getConstant(const Value *IndexValue);
- bool transformGEPChain(Module &M, CallInst *Call, CallInfo &CInfo);
+ bool transformGEPChain(CallInst *Call, CallInfo &CInfo);
};
+
+std::map<std::string, GlobalVariable *> BPFAbstractMemberAccess::GEPGlobals;
+
+class BPFAbstractMemberAccessLegacyPass final : public FunctionPass {
+ BPFTargetMachine *TM;
+
+ bool runOnFunction(Function &F) override {
+ return BPFAbstractMemberAccess(TM).run(F);
+ }
+
+public:
+ static char ID;
+
+ // Add optional BPFTargetMachine parameter so that BPF backend can add the
+ // phase with target machine to find out the endianness. The default
+ // constructor (without parameters) is used by the pass manager for managing
+ // purposes.
+ BPFAbstractMemberAccessLegacyPass(BPFTargetMachine *TM = nullptr)
+ : FunctionPass(ID), TM(TM) {}
+};
+
} // End anonymous namespace
-char BPFAbstractMemberAccess::ID = 0;
-INITIALIZE_PASS(BPFAbstractMemberAccess, DEBUG_TYPE,
- "abstracting struct/union member accessees", false, false)
+char BPFAbstractMemberAccessLegacyPass::ID = 0;
+INITIALIZE_PASS(BPFAbstractMemberAccessLegacyPass, DEBUG_TYPE,
+ "BPF Abstract Member Access", false, false)
-ModulePass *llvm::createBPFAbstractMemberAccess(BPFTargetMachine *TM) {
- return new BPFAbstractMemberAccess(TM);
+FunctionPass *llvm::createBPFAbstractMemberAccess(BPFTargetMachine *TM) {
+ return new BPFAbstractMemberAccessLegacyPass(TM);
}
-bool BPFAbstractMemberAccess::runOnModule(Module &M) {
+bool BPFAbstractMemberAccess::run(Function &F) {
LLVM_DEBUG(dbgs() << "********** Abstract Member Accesses **********\n");
+ M = F.getParent();
+ if (!M)
+ return false;
+
// Bail out if no debug info.
- if (M.debug_compile_units().empty())
+ if (M->debug_compile_units().empty())
return false;
- DL = &M.getDataLayout();
- return doTransformation(M);
+ DL = &M->getDataLayout();
+ return doTransformation(F);
}
static bool SkipDIDerivedTag(unsigned Tag, bool skipTypedef) {
@@ -285,6 +320,34 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
CInfo.AccessIndex = InfoKind;
return true;
}
+ if (GV->getName().startswith("llvm.bpf.preserve.type.info")) {
+ CInfo.Kind = BPFPreserveFieldInfoAI;
+ CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index);
+ if (!CInfo.Metadata)
+ report_fatal_error("Missing metadata for llvm.preserve.type.info intrinsic");
+ uint64_t Flag = getConstant(Call->getArgOperand(1));
+ if (Flag >= BPFCoreSharedInfo::MAX_PRESERVE_TYPE_INFO_FLAG)
+ report_fatal_error("Incorrect flag for llvm.bpf.preserve.type.info intrinsic");
+ if (Flag == BPFCoreSharedInfo::PRESERVE_TYPE_INFO_EXISTENCE)
+ CInfo.AccessIndex = BPFCoreSharedInfo::TYPE_EXISTENCE;
+ else
+ CInfo.AccessIndex = BPFCoreSharedInfo::TYPE_SIZE;
+ return true;
+ }
+ if (GV->getName().startswith("llvm.bpf.preserve.enum.value")) {
+ CInfo.Kind = BPFPreserveFieldInfoAI;
+ CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index);
+ if (!CInfo.Metadata)
+ report_fatal_error("Missing metadata for llvm.preserve.enum.value intrinsic");
+ uint64_t Flag = getConstant(Call->getArgOperand(2));
+ if (Flag >= BPFCoreSharedInfo::MAX_PRESERVE_ENUM_VALUE_FLAG)
+ report_fatal_error("Incorrect flag for llvm.bpf.preserve.enum.value intrinsic");
+ if (Flag == BPFCoreSharedInfo::PRESERVE_ENUM_VALUE_EXISTENCE)
+ CInfo.AccessIndex = BPFCoreSharedInfo::ENUM_VALUE_EXISTENCE;
+ else
+ CInfo.AccessIndex = BPFCoreSharedInfo::ENUM_VALUE;
+ return true;
+ }
return false;
}
@@ -311,28 +374,27 @@ void BPFAbstractMemberAccess::replaceWithGEP(std::vector<CallInst *> &CallList,
}
}
-bool BPFAbstractMemberAccess::removePreserveAccessIndexIntrinsic(Module &M) {
+bool BPFAbstractMemberAccess::removePreserveAccessIndexIntrinsic(Function &F) {
std::vector<CallInst *> PreserveArrayIndexCalls;
std::vector<CallInst *> PreserveUnionIndexCalls;
std::vector<CallInst *> PreserveStructIndexCalls;
bool Found = false;
- for (Function &F : M)
- for (auto &BB : F)
- for (auto &I : BB) {
- auto *Call = dyn_cast<CallInst>(&I);
- CallInfo CInfo;
- if (!IsPreserveDIAccessIndexCall(Call, CInfo))
- continue;
-
- Found = true;
- if (CInfo.Kind == BPFPreserveArrayAI)
- PreserveArrayIndexCalls.push_back(Call);
- else if (CInfo.Kind == BPFPreserveUnionAI)
- PreserveUnionIndexCalls.push_back(Call);
- else
- PreserveStructIndexCalls.push_back(Call);
- }
+ for (auto &BB : F)
+ for (auto &I : BB) {
+ auto *Call = dyn_cast<CallInst>(&I);
+ CallInfo CInfo;
+ if (!IsPreserveDIAccessIndexCall(Call, CInfo))
+ continue;
+
+ Found = true;
+ if (CInfo.Kind == BPFPreserveArrayAI)
+ PreserveArrayIndexCalls.push_back(Call);
+ else if (CInfo.Kind == BPFPreserveUnionAI)
+ PreserveUnionIndexCalls.push_back(Call);
+ else
+ PreserveStructIndexCalls.push_back(Call);
+ }
// do the following transformation:
// . addr = preserve_array_access_index(base, dimension, index)
@@ -498,7 +560,7 @@ void BPFAbstractMemberAccess::traceGEP(GetElementPtrInst *GEP, CallInst *Parent,
}
}
-void BPFAbstractMemberAccess::collectAICallChains(Module &M, Function &F) {
+void BPFAbstractMemberAccess::collectAICallChains(Function &F) {
AIChain.clear();
BaseAICalls.clear();
@@ -847,28 +909,94 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
return Base;
}
+MDNode *BPFAbstractMemberAccess::computeAccessKey(CallInst *Call,
+ CallInfo &CInfo,
+ std::string &AccessKey,
+ bool &IsInt32Ret) {
+ DIType *Ty = stripQualifiers(cast<DIType>(CInfo.Metadata), false);
+ assert(!Ty->getName().empty());
+
+ int64_t PatchImm;
+ std::string AccessStr("0");
+ if (CInfo.AccessIndex == BPFCoreSharedInfo::TYPE_EXISTENCE) {
+ PatchImm = 1;
+ } else if (CInfo.AccessIndex == BPFCoreSharedInfo::TYPE_SIZE) {
+ // typedef debuginfo type has size 0, get the eventual base type.
+ DIType *BaseTy = stripQualifiers(Ty, true);
+ PatchImm = BaseTy->getSizeInBits() / 8;
+ } else {
+ // ENUM_VALUE_EXISTENCE and ENUM_VALUE
+ IsInt32Ret = false;
+
+ const auto *CE = cast<ConstantExpr>(Call->getArgOperand(1));
+ const GlobalVariable *GV = cast<GlobalVariable>(CE->getOperand(0));
+ assert(GV->hasInitializer());
+ const ConstantDataArray *DA = cast<ConstantDataArray>(GV->getInitializer());
+ assert(DA->isString());
+ StringRef ValueStr = DA->getAsString();
+
+ // ValueStr format: <EnumeratorStr>:<Value>
+ size_t Separator = ValueStr.find_first_of(':');
+ StringRef EnumeratorStr = ValueStr.substr(0, Separator);
+
+ // Find enumerator index in the debuginfo
+ DIType *BaseTy = stripQualifiers(Ty, true);
+ const auto *CTy = cast<DICompositeType>(BaseTy);
+ assert(CTy->getTag() == dwarf::DW_TAG_enumeration_type);
+ int EnumIndex = 0;
+ for (const auto Element : CTy->getElements()) {
+ const auto *Enum = cast<DIEnumerator>(Element);
+ if (Enum->getName() == EnumeratorStr) {
+ AccessStr = std::to_string(EnumIndex);
+ break;
+ }
+ EnumIndex++;
+ }
+
+ if (CInfo.AccessIndex == BPFCoreSharedInfo::ENUM_VALUE) {
+ StringRef EValueStr = ValueStr.substr(Separator + 1);
+ PatchImm = std::stoll(std::string(EValueStr));
+ } else {
+ PatchImm = 1;
+ }
+ }
+
+ AccessKey = "llvm." + Ty->getName().str() + ":" +
+ std::to_string(CInfo.AccessIndex) + std::string(":") +
+ std::to_string(PatchImm) + std::string("$") + AccessStr;
+
+ return Ty;
+}
+
/// Call/Kind is the base preserve_*_access_index() call. Attempts to do
/// transformation to a chain of relocable GEPs.
-bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call,
+bool BPFAbstractMemberAccess::transformGEPChain(CallInst *Call,
CallInfo &CInfo) {
std::string AccessKey;
MDNode *TypeMeta;
- Value *Base =
- computeBaseAndAccessKey(Call, CInfo, AccessKey, TypeMeta);
- if (!Base)
- return false;
+ Value *Base = nullptr;
+ bool IsInt32Ret;
+
+ IsInt32Ret = CInfo.Kind == BPFPreserveFieldInfoAI;
+ if (CInfo.Kind == BPFPreserveFieldInfoAI && CInfo.Metadata) {
+ TypeMeta = computeAccessKey(Call, CInfo, AccessKey, IsInt32Ret);
+ } else {
+ Base = computeBaseAndAccessKey(Call, CInfo, AccessKey, TypeMeta);
+ if (!Base)
+ return false;
+ }
BasicBlock *BB = Call->getParent();
GlobalVariable *GV;
if (GEPGlobals.find(AccessKey) == GEPGlobals.end()) {
IntegerType *VarType;
- if (CInfo.Kind == BPFPreserveFieldInfoAI)
+ if (IsInt32Ret)
VarType = Type::getInt32Ty(BB->getContext()); // 32bit return value
else
- VarType = Type::getInt64Ty(BB->getContext()); // 64bit ptr arith
+ VarType = Type::getInt64Ty(BB->getContext()); // 64bit ptr or enum value
- GV = new GlobalVariable(M, VarType, false, GlobalVariable::ExternalLinkage,
+ GV = new GlobalVariable(*M, VarType, false, GlobalVariable::ExternalLinkage,
NULL, AccessKey);
GV->addAttribute(BPFCoreSharedInfo::AmaAttr);
GV->setMetadata(LLVMContext::MD_preserve_access_index, TypeMeta);
@@ -879,9 +1007,15 @@ bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call,
if (CInfo.Kind == BPFPreserveFieldInfoAI) {
// Load the global variable which represents the returned field info.
- auto *LDInst = new LoadInst(Type::getInt32Ty(BB->getContext()), GV, "",
- Call);
- Call->replaceAllUsesWith(LDInst);
+ LoadInst *LDInst;
+ if (IsInt32Ret)
+ LDInst = new LoadInst(Type::getInt32Ty(BB->getContext()), GV, "", Call);
+ else
+ LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV, "", Call);
+
+ Instruction *PassThroughInst =
+ BPFCoreSharedInfo::insertPassThrough(M, BB, LDInst, Call);
+ Call->replaceAllUsesWith(PassThroughInst);
Call->eraseFromParent();
return true;
}
@@ -889,7 +1023,7 @@ bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call,
// For any original GEP Call and Base %2 like
// %4 = bitcast %struct.net_device** %dev1 to i64*
// it is transformed to:
- // %6 = load sk_buff:50:$0:0:0:2:0
+ // %6 = load llvm.sk_buff:0:50$0:0:0:2:0
// %7 = bitcast %struct.sk_buff* %2 to i8*
// %8 = getelementptr i8, i8* %7, %6
// %9 = bitcast i8* %8 to i64*
@@ -912,24 +1046,75 @@ bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call,
auto *BCInst2 = new BitCastInst(GEP, Call->getType());
BB->getInstList().insert(Call->getIterator(), BCInst2);
- Call->replaceAllUsesWith(BCInst2);
+ // For the following code,
+ // Block0:
+ // ...
+ // if (...) goto Block1 else ...
+ // Block1:
+ // %6 = load llvm.sk_buff:0:50$0:0:0:2:0
+ // %7 = bitcast %struct.sk_buff* %2 to i8*
+ // %8 = getelementptr i8, i8* %7, %6
+ // ...
+ // goto CommonExit
+ // Block2:
+ // ...
+ // if (...) goto Block3 else ...
+ // Block3:
+ // %6 = load llvm.bpf_map:0:40$0:0:0:2:0
+ // %7 = bitcast %struct.sk_buff* %2 to i8*
+ // %8 = getelementptr i8, i8* %7, %6
+ // ...
+ // goto CommonExit
+ // CommonExit
+ // SimplifyCFG may generate:
+ // Block0:
+ // ...
+ // if (...) goto Block_Common else ...
+ // Block2:
+ // ...
+ // if (...) goto Block_Common else ...
+ // Block_Common:
+ // PHI = [llvm.sk_buff:0:50$0:0:0:2:0, llvm.bpf_map:0:40$0:0:0:2:0]
+ // %6 = load PHI
+ // %7 = bitcast %struct.sk_buff* %2 to i8*
+ // %8 = getelementptr i8, i8* %7, %6
+ // ...
+ // goto CommonExit
+ // For the above code, we cannot perform proper relocation since
+ // "load PHI" has two possible relocations.
+ //
+ // To prevent above tail merging, we use __builtin_bpf_passthrough()
+ // where one of its parameters is a seq_num. Since two
+ // __builtin_bpf_passthrough() funcs will always have different seq_num,
+ // tail merging cannot happen. The __builtin_bpf_passthrough() will be
+ // removed in the beginning of Target IR passes.
+ //
+ // This approach is also used in other places when global var
+ // representing a relocation is used.
+ Instruction *PassThroughInst =
+ BPFCoreSharedInfo::insertPassThrough(M, BB, BCInst2, Call);
+ Call->replaceAllUsesWith(PassThroughInst);
Call->eraseFromParent();
return true;
}
-bool BPFAbstractMemberAccess::doTransformation(Module &M) {
+bool BPFAbstractMemberAccess::doTransformation(Function &F) {
bool Transformed = false;
- for (Function &F : M) {
- // Collect PreserveDIAccessIndex Intrinsic call chains.
- // The call chains will be used to generate the access
- // patterns similar to GEP.
- collectAICallChains(M, F);
+ // Collect PreserveDIAccessIndex Intrinsic call chains.
+ // The call chains will be used to generate the access
+ // patterns similar to GEP.
+ collectAICallChains(F);
- for (auto &C : BaseAICalls)
- Transformed = transformGEPChain(M, C.first, C.second) || Transformed;
- }
+ for (auto &C : BaseAICalls)
+ Transformed = transformGEPChain(C.first, C.second) || Transformed;
+
+ return removePreserveAccessIndexIntrinsic(F) || Transformed;
+}
- return removePreserveAccessIndexIntrinsic(M) || Transformed;
+PreservedAnalyses
+BPFAbstractMemberAccessPass::run(Function &F, FunctionAnalysisManager &AM) {
+ return BPFAbstractMemberAccess(TM).run(F) ? PreservedAnalyses::none()
+ : PreservedAnalyses::all();
}