diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2021-06-13 19:31:46 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2021-07-31 18:56:55 +0000 |
commit | af732203b8f7f006927528db5497f5cbc4c4742a (patch) | |
tree | 596f112de3b76118552871dbb6114bb7e3e17f40 /contrib/llvm-project/llvm/lib/Target/BPF | |
parent | 83dea422ac8d4a8323e64203c2eadaa813768717 (diff) | |
download | src-af732203b8f7f006927528db5497f5cbc4c4742a.tar.gz src-af732203b8f7f006927528db5497f5cbc4c4742a.zip |
Merge llvm-project 12.0.1 release and follow-up fixes
Merge llvm-project main llvmorg-12-init-17869-g8e464dd76bef
This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and
openmp to llvmorg-12-init-17869-g8e464dd76bef, the last commit before the
upstream release/12.x branch was created.
PR: 255570
(cherry picked from commit e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
Merge llvm-project 12.0.0 release
This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and
openmp to llvmorg-12.0.0-0-gd28af7c654d8, a.k.a. 12.0.0 release.
PR: 255570
(cherry picked from commit d409305fa3838fb39b38c26fc085fb729b8766d5)
Disable strict-fp for powerpcspe, as it does not work properly yet
Merge commit 5c18d1136665 from llvm git (by Qiu Chaofan)
[SPE] Disable strict-fp for SPE by default
As discussed in PR50385, strict-fp on PowerPC SPE has not been
handled well. This patch disables it by default for SPE.
Reviewed By: nemanjai, vit9696, jhibbits
Differential Revision: https://reviews.llvm.org/D103235
PR: 255570
(cherry picked from commit 715df83abc049b23d9acddc81f2480bd4c056d64)
Apply upstream libc++ fix to allow building with devel/xxx-xtoolchain-gcc
Merge commit 52e9d80d5db2 from llvm git (by Jason Liu):
[libc++] add `inline` for __open's definition in ifstream and ofstream
Summary:
When building with gcc on AIX, it seems that gcc does not like the
`always_inline` without the `inline` keyword.
So adding the inline keywords in for __open in ifstream and ofstream.
That will also make it consistent with __open in basic_filebuf
(it seems we added `inline` there before for gcc build as well).
Differential Revision: https://reviews.llvm.org/D99422
PR: 255570
(cherry picked from commit d099db25464b826c5724cf2fb5b22292bbe15f6e)
Undefine HAVE_(DE)REGISTER_FRAME in llvm's config.h on arm
Otherwise, the lli tool (enable by WITH_CLANG_EXTRAS) won't link on arm,
stating that __register_frame is undefined. This function is normally
provided by libunwind, but explicitly not for the ARM Exception ABI.
Reported by: oh
PR: 255570
(cherry picked from commit f336b45e943c7f9a90ffcea1a6c4c7039e54c73c)
Merge llvm-project 12.0.1 rc2
This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and
openmp to llvmorg-12.0.1-rc2-0-ge7dac564cd0e, a.k.a. 12.0.1 rc2.
PR: 255570
(cherry picked from commit 23408297fbf3089f0388a8873b02fa75ab3f5bb9)
Revert libunwind change to fix backtrace segfault on aarch64
Revert commit 22b615a96593 from llvm git (by Daniel Kiss):
[libunwind] Support for leaf function unwinding.
Unwinding leaf function is useful in cases when the backtrace finds a
leaf function for example when it caused a signal.
This patch also add the support for the DW_CFA_undefined because it marks
the end of the frames.
Ryan Prichard provided code for the tests.
Reviewed By: #libunwind, mstorsjo
Differential Revision: https://reviews.llvm.org/D83573
Reland with limit the test to the x86_64-linux target.
Bisection has shown that this particular upstream commit causes programs
using backtrace(3) on aarch64 to segfault. This affects the lang/rust
port, for instance. Until we can upstream to fix this problem, revert
the commit for now.
Reported by: mikael
PR: 256864
(cherry picked from commit 5866c369e4fd917c0d456f0f10b92ee354b82279)
Merge llvm-project 12.0.1 release
This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and
openmp to llvmorg-12.0.1-0-gfed41342a82f, a.k.a. 12.0.1 release.
PR: 255570
(cherry picked from commit 4652422eb477731f284b1345afeefef7f269da50)
compilert-rt: build out-of-line LSE atomics helpers for aarch64
Both clang >= 12 and gcc >= 10.1 now default to -moutline-atomics for
aarch64. This requires a bunch of helper functions in libcompiler_rt.a,
to avoid link errors like "undefined symbol: __aarch64_ldadd8_acq_rel".
(Note: of course you can use -mno-outline-atomics as a workaround too,
but this would negate the potential performance benefit of the faster
LSE instructions.)
Bump __FreeBSD_version so ports maintainers can easily detect this.
PR: 257392
(cherry picked from commit cc55ee8009a550810d38777fd6ace9abf3a2f6b4)
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/BPF')
25 files changed, 1351 insertions, 195 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPF.h b/contrib/llvm-project/llvm/lib/Target/BPF/BPF.h index 4a46b11e5e08..a98a3e08d5de 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BPF.h +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPF.h @@ -10,14 +10,17 @@ #define LLVM_LIB_TARGET_BPF_BPF_H #include "MCTargetDesc/BPFMCTargetDesc.h" +#include "llvm/IR/PassManager.h" #include "llvm/Target/TargetMachine.h" namespace llvm { class BPFTargetMachine; -ModulePass *createBPFAbstractMemberAccess(BPFTargetMachine *TM); -ModulePass *createBPFPreserveDIType(); +ModulePass *createBPFAdjustOpt(); +ModulePass *createBPFCheckAndAdjustIR(); +FunctionPass *createBPFAbstractMemberAccess(BPFTargetMachine *TM); +FunctionPass *createBPFPreserveDIType(); FunctionPass *createBPFISelDag(BPFTargetMachine &TM); FunctionPass *createBPFMISimplifyPatchablePass(); FunctionPass *createBPFMIPeepholePass(); @@ -25,13 +28,39 @@ FunctionPass *createBPFMIPeepholeTruncElimPass(); FunctionPass *createBPFMIPreEmitPeepholePass(); FunctionPass *createBPFMIPreEmitCheckingPass(); -void initializeBPFAbstractMemberAccessPass(PassRegistry&); +void initializeBPFAdjustOptPass(PassRegistry&); +void initializeBPFCheckAndAdjustIRPass(PassRegistry&); + +void initializeBPFAbstractMemberAccessLegacyPassPass(PassRegistry &); void initializeBPFPreserveDITypePass(PassRegistry&); void initializeBPFMISimplifyPatchablePass(PassRegistry&); void initializeBPFMIPeepholePass(PassRegistry&); void initializeBPFMIPeepholeTruncElimPass(PassRegistry&); void initializeBPFMIPreEmitPeepholePass(PassRegistry&); void initializeBPFMIPreEmitCheckingPass(PassRegistry&); -} + +class BPFAbstractMemberAccessPass + : public PassInfoMixin<BPFAbstractMemberAccessPass> { + BPFTargetMachine *TM; + +public: + BPFAbstractMemberAccessPass(BPFTargetMachine *TM) : TM(TM) {} + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + + static bool isRequired() { return true; } +}; + +class BPFPreserveDITypePass : public PassInfoMixin<BPFPreserveDITypePass> { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + + static bool isRequired() { return true; } +}; + +class BPFAdjustOptPass : public PassInfoMixin<BPFAdjustOptPass> { +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; +} // namespace llvm #endif 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(); } diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFAdjustOpt.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/BPFAdjustOpt.cpp new file mode 100644 index 000000000000..da543e7eba53 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFAdjustOpt.cpp @@ -0,0 +1,323 @@ +//===---------------- BPFAdjustOpt.cpp - Adjust Optimization --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Adjust optimization to make the code more kernel verifier friendly. +// +//===----------------------------------------------------------------------===// + +#include "BPF.h" +#include "BPFCORE.h" +#include "BPFTargetMachine.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/User.h" +#include "llvm/IR/Value.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" + +#define DEBUG_TYPE "bpf-adjust-opt" + +using namespace llvm; + +static cl::opt<bool> + DisableBPFserializeICMP("bpf-disable-serialize-icmp", cl::Hidden, + cl::desc("BPF: Disable Serializing ICMP insns."), + cl::init(false)); + +static cl::opt<bool> DisableBPFavoidSpeculation( + "bpf-disable-avoid-speculation", cl::Hidden, + cl::desc("BPF: Disable Avoiding Speculative Code Motion."), + cl::init(false)); + +namespace { + +class BPFAdjustOpt final : public ModulePass { +public: + static char ID; + + BPFAdjustOpt() : ModulePass(ID) {} + bool runOnModule(Module &M) override; +}; + +class BPFAdjustOptImpl { + struct PassThroughInfo { + Instruction *Input; + Instruction *UsedInst; + uint32_t OpIdx; + PassThroughInfo(Instruction *I, Instruction *U, uint32_t Idx) + : Input(I), UsedInst(U), OpIdx(Idx) {} + }; + +public: + BPFAdjustOptImpl(Module *M) : M(M) {} + + bool run(); + +private: + Module *M; + SmallVector<PassThroughInfo, 16> PassThroughs; + + void adjustBasicBlock(BasicBlock &BB); + bool serializeICMPCrossBB(BasicBlock &BB); + void adjustInst(Instruction &I); + bool serializeICMPInBB(Instruction &I); + bool avoidSpeculation(Instruction &I); + bool insertPassThrough(); +}; + +} // End anonymous namespace + +char BPFAdjustOpt::ID = 0; +INITIALIZE_PASS(BPFAdjustOpt, "bpf-adjust-opt", "BPF Adjust Optimization", + false, false) + +ModulePass *llvm::createBPFAdjustOpt() { return new BPFAdjustOpt(); } + +bool BPFAdjustOpt::runOnModule(Module &M) { return BPFAdjustOptImpl(&M).run(); } + +bool BPFAdjustOptImpl::run() { + for (Function &F : *M) + for (auto &BB : F) { + adjustBasicBlock(BB); + for (auto &I : BB) + adjustInst(I); + } + + return insertPassThrough(); +} + +bool BPFAdjustOptImpl::insertPassThrough() { + for (auto &Info : PassThroughs) { + auto *CI = BPFCoreSharedInfo::insertPassThrough( + M, Info.UsedInst->getParent(), Info.Input, Info.UsedInst); + Info.UsedInst->setOperand(Info.OpIdx, CI); + } + + return !PassThroughs.empty(); +} + +// To avoid combining conditionals in the same basic block by +// instrcombine optimization. +bool BPFAdjustOptImpl::serializeICMPInBB(Instruction &I) { + // For: + // comp1 = icmp <opcode> ...; + // comp2 = icmp <opcode> ...; + // ... or comp1 comp2 ... + // changed to: + // comp1 = icmp <opcode> ...; + // comp2 = icmp <opcode> ...; + // new_comp1 = __builtin_bpf_passthrough(seq_num, comp1) + // ... or new_comp1 comp2 ... + if (I.getOpcode() != Instruction::Or) + return false; + auto *Icmp1 = dyn_cast<ICmpInst>(I.getOperand(0)); + if (!Icmp1) + return false; + auto *Icmp2 = dyn_cast<ICmpInst>(I.getOperand(1)); + if (!Icmp2) + return false; + + Value *Icmp1Op0 = Icmp1->getOperand(0); + Value *Icmp2Op0 = Icmp2->getOperand(0); + if (Icmp1Op0 != Icmp2Op0) + return false; + + // Now we got two icmp instructions which feed into + // an "or" instruction. + PassThroughInfo Info(Icmp1, &I, 0); + PassThroughs.push_back(Info); + return true; +} + +// To avoid combining conditionals in the same basic block by +// instrcombine optimization. +bool BPFAdjustOptImpl::serializeICMPCrossBB(BasicBlock &BB) { + // For: + // B1: + // comp1 = icmp <opcode> ...; + // if (comp1) goto B2 else B3; + // B2: + // comp2 = icmp <opcode> ...; + // if (comp2) goto B4 else B5; + // B4: + // ... + // changed to: + // B1: + // comp1 = icmp <opcode> ...; + // comp1 = __builtin_bpf_passthrough(seq_num, comp1); + // if (comp1) goto B2 else B3; + // B2: + // comp2 = icmp <opcode> ...; + // if (comp2) goto B4 else B5; + // B4: + // ... + + // Check basic predecessors, if two of them (say B1, B2) are using + // icmp instructions to generate conditions and one is the predesessor + // of another (e.g., B1 is the predecessor of B2). Add a passthrough + // barrier after icmp inst of block B1. + BasicBlock *B2 = BB.getSinglePredecessor(); + if (!B2) + return false; + + BasicBlock *B1 = B2->getSinglePredecessor(); + if (!B1) + return false; + + Instruction *TI = B2->getTerminator(); + auto *BI = dyn_cast<BranchInst>(TI); + if (!BI || !BI->isConditional()) + return false; + auto *Cond = dyn_cast<ICmpInst>(BI->getCondition()); + if (!Cond || B2->getFirstNonPHI() != Cond) + return false; + Value *B2Op0 = Cond->getOperand(0); + auto Cond2Op = Cond->getPredicate(); + + TI = B1->getTerminator(); + BI = dyn_cast<BranchInst>(TI); + if (!BI || !BI->isConditional()) + return false; + Cond = dyn_cast<ICmpInst>(BI->getCondition()); + if (!Cond) + return false; + Value *B1Op0 = Cond->getOperand(0); + auto Cond1Op = Cond->getPredicate(); + + if (B1Op0 != B2Op0) + return false; + + if (Cond1Op == ICmpInst::ICMP_SGT || Cond1Op == ICmpInst::ICMP_SGE) { + if (Cond2Op != ICmpInst::ICMP_SLT && Cond1Op != ICmpInst::ICMP_SLE) + return false; + } else if (Cond1Op == ICmpInst::ICMP_SLT || Cond1Op == ICmpInst::ICMP_SLE) { + if (Cond2Op != ICmpInst::ICMP_SGT && Cond1Op != ICmpInst::ICMP_SGE) + return false; + } else { + return false; + } + + PassThroughInfo Info(Cond, BI, 0); + PassThroughs.push_back(Info); + + return true; +} + +// To avoid speculative hoisting certain computations out of +// a basic block. +bool BPFAdjustOptImpl::avoidSpeculation(Instruction &I) { + if (auto *LdInst = dyn_cast<LoadInst>(&I)) { + if (auto *GV = dyn_cast<GlobalVariable>(LdInst->getOperand(0))) { + if (GV->hasAttribute(BPFCoreSharedInfo::AmaAttr) || + GV->hasAttribute(BPFCoreSharedInfo::TypeIdAttr)) + return false; + } + } + + if (!isa<LoadInst>(&I) && !isa<CallInst>(&I)) + return false; + + // For: + // B1: + // var = ... + // ... + // /* icmp may not be in the same block as var = ... */ + // comp1 = icmp <opcode> var, <const>; + // if (comp1) goto B2 else B3; + // B2: + // ... var ... + // change to: + // B1: + // var = ... + // ... + // /* icmp may not be in the same block as var = ... */ + // comp1 = icmp <opcode> var, <const>; + // if (comp1) goto B2 else B3; + // B2: + // var = __builtin_bpf_passthrough(seq_num, var); + // ... var ... + bool isCandidate = false; + SmallVector<PassThroughInfo, 4> Candidates; + for (User *U : I.users()) { + Instruction *Inst = dyn_cast<Instruction>(U); + if (!Inst) + continue; + + // May cover a little bit more than the + // above pattern. + if (auto *Icmp1 = dyn_cast<ICmpInst>(Inst)) { + Value *Icmp1Op1 = Icmp1->getOperand(1); + if (!isa<Constant>(Icmp1Op1)) + return false; + isCandidate = true; + continue; + } + + // Ignore the use in the same basic block as the definition. + if (Inst->getParent() == I.getParent()) + continue; + + // use in a different basic block, If there is a call or + // load/store insn before this instruction in this basic + // block. Most likely it cannot be hoisted out. Skip it. + for (auto &I2 : *Inst->getParent()) { + if (dyn_cast<CallInst>(&I2)) + return false; + if (dyn_cast<LoadInst>(&I2) || dyn_cast<StoreInst>(&I2)) + return false; + if (&I2 == Inst) + break; + } + + // It should be used in a GEP or a simple arithmetic like + // ZEXT/SEXT which is used for GEP. + if (Inst->getOpcode() == Instruction::ZExt || + Inst->getOpcode() == Instruction::SExt) { + PassThroughInfo Info(&I, Inst, 0); + Candidates.push_back(Info); + } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) { + // traverse GEP inst to find Use operand index + unsigned i, e; + for (i = 1, e = GI->getNumOperands(); i != e; ++i) { + Value *V = GI->getOperand(i); + if (V == &I) + break; + } + if (i == e) + continue; + + PassThroughInfo Info(&I, GI, i); + Candidates.push_back(Info); + } + } + + if (!isCandidate || Candidates.empty()) + return false; + + llvm::append_range(PassThroughs, Candidates); + return true; +} + +void BPFAdjustOptImpl::adjustBasicBlock(BasicBlock &BB) { + if (!DisableBPFserializeICMP && serializeICMPCrossBB(BB)) + return; +} + +void BPFAdjustOptImpl::adjustInst(Instruction &I) { + if (!DisableBPFserializeICMP && serializeICMPInBB(I)) + return; + if (!DisableBPFavoidSpeculation && avoidSpeculation(I)) + return; +} + +PreservedAnalyses BPFAdjustOptPass::run(Module &M, ModuleAnalysisManager &AM) { + return BPFAdjustOptImpl(&M).run() ? PreservedAnalyses::none() + : PreservedAnalyses::all(); +} diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFCORE.h b/contrib/llvm-project/llvm/lib/Target/BPF/BPFCORE.h index af6425b16fa0..0c504412480d 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BPFCORE.h +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFCORE.h @@ -13,6 +13,10 @@ namespace llvm { +class BasicBlock; +class Instruction; +class Module; + class BPFCoreSharedInfo { public: enum PatchableRelocKind : uint32_t { @@ -24,6 +28,10 @@ public: FIELD_RSHIFT_U64, BTF_TYPE_ID_LOCAL, BTF_TYPE_ID_REMOTE, + TYPE_EXISTENCE, + TYPE_SIZE, + ENUM_VALUE_EXISTENCE, + ENUM_VALUE, MAX_FIELD_RELOC_KIND, }; @@ -35,10 +43,32 @@ public: MAX_BTF_TYPE_ID_FLAG, }; + enum PreserveTypeInfo : uint32_t { + PRESERVE_TYPE_INFO_EXISTENCE = 0, + PRESERVE_TYPE_INFO_SIZE, + + MAX_PRESERVE_TYPE_INFO_FLAG, + }; + + enum PreserveEnumValue : uint32_t { + PRESERVE_ENUM_VALUE_EXISTENCE = 0, + PRESERVE_ENUM_VALUE, + + MAX_PRESERVE_ENUM_VALUE_FLAG, + }; + /// The attribute attached to globals representing a field access static constexpr StringRef AmaAttr = "btf_ama"; /// The attribute attached to globals representing a type id static constexpr StringRef TypeIdAttr = "btf_type_id"; + + /// llvm.bpf.passthrough builtin seq number + static uint32_t SeqNum; + + /// Insert a bpf passthrough builtin function. + static Instruction *insertPassThrough(Module *M, BasicBlock *BB, + Instruction *Input, + Instruction *Before); }; } // namespace llvm diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp new file mode 100644 index 000000000000..5239218ad003 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp @@ -0,0 +1,130 @@ +//===------------ BPFCheckAndAdjustIR.cpp - Check and Adjust IR -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Check IR and adjust IR for verifier friendly codes. +// The following are done for IR checking: +// - no relocation globals in PHI node. +// The following are done for IR adjustment: +// - remove __builtin_bpf_passthrough builtins. Target independent IR +// optimizations are done and those builtins can be removed. +// +//===----------------------------------------------------------------------===// + +#include "BPF.h" +#include "BPFCORE.h" +#include "BPFTargetMachine.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/User.h" +#include "llvm/IR/Value.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" + +#define DEBUG_TYPE "bpf-check-and-opt-ir" + +using namespace llvm; + +namespace { + +class BPFCheckAndAdjustIR final : public ModulePass { + bool runOnModule(Module &F) override; + +public: + static char ID; + BPFCheckAndAdjustIR() : ModulePass(ID) {} + +private: + void checkIR(Module &M); + bool adjustIR(Module &M); + bool removePassThroughBuiltin(Module &M); +}; +} // End anonymous namespace + +char BPFCheckAndAdjustIR::ID = 0; +INITIALIZE_PASS(BPFCheckAndAdjustIR, DEBUG_TYPE, "BPF Check And Adjust IR", + false, false) + +ModulePass *llvm::createBPFCheckAndAdjustIR() { + return new BPFCheckAndAdjustIR(); +} + +void BPFCheckAndAdjustIR::checkIR(Module &M) { + // Ensure relocation global won't appear in PHI node + // This may happen if the compiler generated the following code: + // B1: + // g1 = @llvm.skb_buff:0:1... + // ... + // goto B_COMMON + // B2: + // g2 = @llvm.skb_buff:0:2... + // ... + // goto B_COMMON + // B_COMMON: + // g = PHI(g1, g2) + // x = load g + // ... + // If anything likes the above "g = PHI(g1, g2)", issue a fatal error. + for (Function &F : M) + for (auto &BB : F) + for (auto &I : BB) { + PHINode *PN = dyn_cast<PHINode>(&I); + if (!PN || PN->use_empty()) + continue; + for (int i = 0, e = PN->getNumIncomingValues(); i < e; ++i) { + auto *GV = dyn_cast<GlobalVariable>(PN->getIncomingValue(i)); + if (!GV) + continue; + if (GV->hasAttribute(BPFCoreSharedInfo::AmaAttr) || + GV->hasAttribute(BPFCoreSharedInfo::TypeIdAttr)) + report_fatal_error("relocation global in PHI node"); + } + } +} + +bool BPFCheckAndAdjustIR::removePassThroughBuiltin(Module &M) { + // Remove __builtin_bpf_passthrough()'s which are used to prevent + // certain IR optimizations. Now major IR optimizations are done, + // remove them. + bool Changed = false; + CallInst *ToBeDeleted = nullptr; + for (Function &F : M) + for (auto &BB : F) + for (auto &I : BB) { + if (ToBeDeleted) { + ToBeDeleted->eraseFromParent(); + ToBeDeleted = nullptr; + } + + auto *Call = dyn_cast<CallInst>(&I); + if (!Call) + continue; + auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand()); + if (!GV) + continue; + if (!GV->getName().startswith("llvm.bpf.passthrough")) + continue; + Changed = true; + Value *Arg = Call->getArgOperand(1); + Call->replaceAllUsesWith(Arg); + ToBeDeleted = Call; + } + return Changed; +} + +bool BPFCheckAndAdjustIR::adjustIR(Module &M) { + return removePassThroughBuiltin(M); +} + +bool BPFCheckAndAdjustIR::runOnModule(Module &M) { + checkIR(M); + return adjustIR(M); +} diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp index 77f565fb5957..f10a0d4c0077 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp @@ -494,8 +494,6 @@ void BPFDAGToDAGISel::PreprocessTrunc(SDNode *Node, CurDAG->ReplaceAllUsesWith(SDValue(Node, 0), BaseV); I++; CurDAG->DeleteNode(Node); - - return; } FunctionPass *llvm::createBPFISelDag(BPFTargetMachine &TM) { diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFISelLowering.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/BPFISelLowering.cpp index a02556a39909..3322b8d93b3a 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BPFISelLowering.cpp +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFISelLowering.cpp @@ -20,7 +20,6 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" -#include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/IR/DiagnosticInfo.h" diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrFormats.td b/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrFormats.td index 9f00dc85d789..a809065014e5 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrFormats.td +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrFormats.td @@ -44,6 +44,9 @@ def BPF_MOV : BPFArithOp<0xb>; def BPF_ARSH : BPFArithOp<0xc>; def BPF_END : BPFArithOp<0xd>; +def BPF_XCHG : BPFArithOp<0xe>; +def BPF_CMPXCHG : BPFArithOp<0xf>; + class BPFEndDir<bits<1> val> { bits<1> Value = val; } @@ -86,7 +89,13 @@ def BPF_IMM : BPFModeModifer<0x0>; def BPF_ABS : BPFModeModifer<0x1>; def BPF_IND : BPFModeModifer<0x2>; def BPF_MEM : BPFModeModifer<0x3>; -def BPF_XADD : BPFModeModifer<0x6>; +def BPF_ATOMIC : BPFModeModifer<0x6>; + +class BPFAtomicFlag<bits<4> val> { + bits<4> Value = val; +} + +def BPF_FETCH : BPFAtomicFlag<0x1>; class InstBPF<dag outs, dag ins, string asmstr, list<dag> pattern> : Instruction { diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.td b/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.td index 4298e2eaec04..082e1f4a92c2 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.td +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.td @@ -617,9 +617,9 @@ let Predicates = [BPFNoALU32] in { def : Pat<(i64 (extloadi32 ADDRri:$src)), (i64 (LDW ADDRri:$src))>; } -// Atomics +// Atomic XADD for BPFNoALU32 class XADD<BPFWidthModifer SizeOp, string OpcodeStr, PatFrag OpNode> - : TYPE_LD_ST<BPF_XADD.Value, SizeOp.Value, + : TYPE_LD_ST<BPF_ATOMIC.Value, SizeOp.Value, (outs GPR:$dst), (ins MEMri:$addr, GPR:$val), "lock *("#OpcodeStr#" *)($addr) += $val", @@ -630,14 +630,88 @@ class XADD<BPFWidthModifer SizeOp, string OpcodeStr, PatFrag OpNode> let Inst{51-48} = addr{19-16}; // base reg let Inst{55-52} = dst; let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = BPF_ADD.Value; let BPFClass = BPF_STX; } -class XADD32<BPFWidthModifer SizeOp, string OpcodeStr, PatFrag OpNode> - : TYPE_LD_ST<BPF_XADD.Value, SizeOp.Value, +let Constraints = "$dst = $val" in { + let Predicates = [BPFNoALU32] in { + def XADDW : XADD<BPF_W, "u32", atomic_load_add_32>; + } +} + +// Atomic add, and, or, xor +class ATOMIC_NOFETCH<BPFArithOp Opc, string Opstr> + : TYPE_LD_ST<BPF_ATOMIC.Value, BPF_DW.Value, + (outs GPR:$dst), + (ins MEMri:$addr, GPR:$val), + "lock *(u64 *)($addr) " #Opstr# "= $val", + []> { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = dst; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = Opc.Value; + let BPFClass = BPF_STX; +} + +class ATOMIC32_NOFETCH<BPFArithOp Opc, string Opstr> + : TYPE_LD_ST<BPF_ATOMIC.Value, BPF_W.Value, (outs GPR32:$dst), (ins MEMri:$addr, GPR32:$val), - "lock *("#OpcodeStr#" *)($addr) += $val", + "lock *(u32 *)($addr) " #Opstr# "= $val", + []> { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = dst; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = Opc.Value; + let BPFClass = BPF_STX; +} + +let Constraints = "$dst = $val" in { + let Predicates = [BPFHasALU32], DecoderNamespace = "BPFALU32" in { + def XADDW32 : ATOMIC32_NOFETCH<BPF_ADD, "+">; + def XANDW32 : ATOMIC32_NOFETCH<BPF_AND, "&">; + def XORW32 : ATOMIC32_NOFETCH<BPF_OR, "|">; + def XXORW32 : ATOMIC32_NOFETCH<BPF_XOR, "^">; + } + + def XADDD : ATOMIC_NOFETCH<BPF_ADD, "+">; + def XANDD : ATOMIC_NOFETCH<BPF_AND, "&">; + def XORD : ATOMIC_NOFETCH<BPF_OR, "|">; + def XXORD : ATOMIC_NOFETCH<BPF_XOR, "^">; +} + +// Atomic Fetch-and-<add, and, or, xor> operations +class XFALU64<BPFWidthModifer SizeOp, BPFArithOp Opc, string OpcodeStr, + string OpcStr, PatFrag OpNode> + : TYPE_LD_ST<BPF_ATOMIC.Value, SizeOp.Value, + (outs GPR:$dst), + (ins MEMri:$addr, GPR:$val), + "$dst = atomic_fetch_"#OpcStr#"(("#OpcodeStr#" *)($addr), $val)", + [(set GPR:$dst, (OpNode ADDRri:$addr, GPR:$val))]> { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = dst; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = Opc.Value; + let Inst{3-0} = BPF_FETCH.Value; + let BPFClass = BPF_STX; +} + +class XFALU32<BPFWidthModifer SizeOp, BPFArithOp Opc, string OpcodeStr, + string OpcStr, PatFrag OpNode> + : TYPE_LD_ST<BPF_ATOMIC.Value, SizeOp.Value, + (outs GPR32:$dst), + (ins MEMri:$addr, GPR32:$val), + "$dst = atomic_fetch_"#OpcStr#"(("#OpcodeStr#" *)($addr), $val)", [(set GPR32:$dst, (OpNode ADDRri:$addr, GPR32:$val))]> { bits<4> dst; bits<20> addr; @@ -645,19 +719,117 @@ class XADD32<BPFWidthModifer SizeOp, string OpcodeStr, PatFrag OpNode> let Inst{51-48} = addr{19-16}; // base reg let Inst{55-52} = dst; let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = Opc.Value; + let Inst{3-0} = BPF_FETCH.Value; let BPFClass = BPF_STX; } let Constraints = "$dst = $val" in { - let Predicates = [BPFNoALU32] in { - def XADDW : XADD<BPF_W, "u32", atomic_load_add_32>; + let Predicates = [BPFHasALU32], DecoderNamespace = "BPFALU32" in { + def XFADDW32 : XFALU32<BPF_W, BPF_ADD, "u32", "add", atomic_load_add_32>; + def XFANDW32 : XFALU32<BPF_W, BPF_AND, "u32", "and", atomic_load_and_32>; + def XFORW32 : XFALU32<BPF_W, BPF_OR, "u32", "or", atomic_load_or_32>; + def XFXORW32 : XFALU32<BPF_W, BPF_XOR, "u32", "xor", atomic_load_xor_32>; } + def XFADDD : XFALU64<BPF_DW, BPF_ADD, "u64", "add", atomic_load_add_64>; + def XFANDD : XFALU64<BPF_DW, BPF_AND, "u64", "and", atomic_load_and_64>; + def XFORD : XFALU64<BPF_DW, BPF_OR, "u64", "or", atomic_load_or_64>; + def XFXORD : XFALU64<BPF_DW, BPF_XOR, "u64", "xor", atomic_load_xor_64>; +} + +// atomic_load_sub can be represented as a neg followed +// by an atomic_load_add. +def : Pat<(atomic_load_sub_32 ADDRri:$addr, GPR32:$val), + (XFADDW32 ADDRri:$addr, (NEG_32 GPR32:$val))>; +def : Pat<(atomic_load_sub_64 ADDRri:$addr, GPR:$val), + (XFADDD ADDRri:$addr, (NEG_64 GPR:$val))>; + +// Atomic Exchange +class XCHG<BPFWidthModifer SizeOp, string OpcodeStr, PatFrag OpNode> + : TYPE_LD_ST<BPF_ATOMIC.Value, SizeOp.Value, + (outs GPR:$dst), + (ins MEMri:$addr, GPR:$val), + "$dst = xchg_"#OpcodeStr#"($addr, $val)", + [(set GPR:$dst, (OpNode ADDRri:$addr,GPR:$val))]> { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = dst; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = BPF_XCHG.Value; + let Inst{3-0} = BPF_FETCH.Value; + let BPFClass = BPF_STX; +} + +class XCHG32<BPFWidthModifer SizeOp, string OpcodeStr, PatFrag OpNode> + : TYPE_LD_ST<BPF_ATOMIC.Value, SizeOp.Value, + (outs GPR32:$dst), + (ins MEMri:$addr, GPR32:$val), + "$dst = xchg32_"#OpcodeStr#"($addr, $val)", + [(set GPR32:$dst, (OpNode ADDRri:$addr,GPR32:$val))]> { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = dst; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = BPF_XCHG.Value; + let Inst{3-0} = BPF_FETCH.Value; + let BPFClass = BPF_STX; +} + +let Constraints = "$dst = $val" in { let Predicates = [BPFHasALU32], DecoderNamespace = "BPFALU32" in { - def XADDW32 : XADD32<BPF_W, "u32", atomic_load_add_32>; + def XCHGW32 : XCHG32<BPF_W, "32", atomic_swap_32>; } - def XADDD : XADD<BPF_DW, "u64", atomic_load_add_64>; + def XCHGD : XCHG<BPF_DW, "64", atomic_swap_64>; +} + +// Compare-And-Exchange +class CMPXCHG<BPFWidthModifer SizeOp, string OpcodeStr, PatFrag OpNode> + : TYPE_LD_ST<BPF_ATOMIC.Value, SizeOp.Value, + (outs), + (ins MEMri:$addr, GPR:$new), + "r0 = cmpxchg_"#OpcodeStr#"($addr, r0, $new)", + [(set R0, (OpNode ADDRri:$addr, R0, GPR:$new))]> { + bits<4> new; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = new; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = BPF_CMPXCHG.Value; + let Inst{3-0} = BPF_FETCH.Value; + let BPFClass = BPF_STX; +} + +class CMPXCHG32<BPFWidthModifer SizeOp, string OpcodeStr, PatFrag OpNode> + : TYPE_LD_ST<BPF_ATOMIC.Value, SizeOp.Value, + (outs), + (ins MEMri:$addr, GPR32:$new), + "w0 = cmpxchg32_"#OpcodeStr#"($addr, w0, $new)", + [(set W0, (OpNode ADDRri:$addr, W0, GPR32:$new))]> { + bits<4> new; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = new; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = BPF_CMPXCHG.Value; + let Inst{3-0} = BPF_FETCH.Value; + let BPFClass = BPF_STX; +} + +let Predicates = [BPFHasALU32], Defs = [W0], Uses = [W0], + DecoderNamespace = "BPFALU32" in { + def CMPXCHGW32 : CMPXCHG32<BPF_W, "32", atomic_cmp_swap_32>; +} + +let Defs = [R0], Uses = [R0] in { + def CMPXCHGD : CMPXCHG<BPF_DW, "64", atomic_cmp_swap_64>; } // bswap16, bswap32, bswap64 diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFMIChecking.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/BPFMIChecking.cpp index f82f166eda4d..4e24e3d911b8 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BPFMIChecking.cpp +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFMIChecking.cpp @@ -41,7 +41,7 @@ private: // Initialize class variables. void initialize(MachineFunction &MFParm); - void checkingIllegalXADD(void); + bool processAtomicInsts(void); public: @@ -49,7 +49,7 @@ public: bool runOnMachineFunction(MachineFunction &MF) override { if (!skipFunction(MF.getFunction())) { initialize(MF); - checkingIllegalXADD(); + return processAtomicInsts(); } return false; } @@ -143,17 +143,15 @@ static bool hasLiveDefs(const MachineInstr &MI, const TargetRegisterInfo *TRI) { return true; // Otherwise, return true if any aliased SuperReg of GPR32 is not dead. - std::vector<unsigned>::iterator search_begin = GPR64DeadDefs.begin(); - std::vector<unsigned>::iterator search_end = GPR64DeadDefs.end(); for (auto I : GPR32LiveDefs) for (MCSuperRegIterator SR(I, TRI); SR.isValid(); ++SR) - if (std::find(search_begin, search_end, *SR) == search_end) - return true; + if (!llvm::is_contained(GPR64DeadDefs, *SR)) + return true; return false; } -void BPFMIPreEmitChecking::checkingIllegalXADD(void) { +bool BPFMIPreEmitChecking::processAtomicInsts(void) { for (MachineBasicBlock &MBB : *MF) { for (MachineInstr &MI : MBB) { if (MI.getOpcode() != BPF::XADDW && @@ -174,7 +172,71 @@ void BPFMIPreEmitChecking::checkingIllegalXADD(void) { } } - return; + // Check return values of atomic_fetch_and_{add,and,or,xor}. + // If the return is not used, the atomic_fetch_and_<op> instruction + // is replaced with atomic_<op> instruction. + MachineInstr *ToErase = nullptr; + bool Changed = false; + const BPFInstrInfo *TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo(); + for (MachineBasicBlock &MBB : *MF) { + for (MachineInstr &MI : MBB) { + if (ToErase) { + ToErase->eraseFromParent(); + ToErase = nullptr; + } + + if (MI.getOpcode() != BPF::XFADDW32 && MI.getOpcode() != BPF::XFADDD && + MI.getOpcode() != BPF::XFANDW32 && MI.getOpcode() != BPF::XFANDD && + MI.getOpcode() != BPF::XFXORW32 && MI.getOpcode() != BPF::XFXORD && + MI.getOpcode() != BPF::XFORW32 && MI.getOpcode() != BPF::XFORD) + continue; + + if (hasLiveDefs(MI, TRI)) + continue; + + LLVM_DEBUG(dbgs() << "Transforming "; MI.dump()); + unsigned newOpcode; + switch (MI.getOpcode()) { + case BPF::XFADDW32: + newOpcode = BPF::XADDW32; + break; + case BPF::XFADDD: + newOpcode = BPF::XADDD; + break; + case BPF::XFANDW32: + newOpcode = BPF::XANDW32; + break; + case BPF::XFANDD: + newOpcode = BPF::XANDD; + break; + case BPF::XFXORW32: + newOpcode = BPF::XXORW32; + break; + case BPF::XFXORD: + newOpcode = BPF::XXORD; + break; + case BPF::XFORW32: + newOpcode = BPF::XORW32; + break; + case BPF::XFORD: + newOpcode = BPF::XORD; + break; + default: + llvm_unreachable("Incorrect Atomic Instruction Opcode"); + } + + BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(newOpcode)) + .add(MI.getOperand(0)) + .add(MI.getOperand(1)) + .add(MI.getOperand(2)) + .add(MI.getOperand(3)); + + ToErase = &MI; + Changed = true; + } + } + + return Changed; } } // end default namespace diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFMIPeephole.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/BPFMIPeephole.cpp index df870314fffe..354980e4bf3c 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BPFMIPeephole.cpp +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFMIPeephole.cpp @@ -475,6 +475,9 @@ bool BPFMIPeepholeTruncElim::eliminateTruncSeq(void) { if (MI.getOpcode() == BPF::SRL_ri && MI.getOperand(2).getImm() == 32) { SrcReg = MI.getOperand(1).getReg(); + if (!MRI->hasOneNonDBGUse(SrcReg)) + continue; + MI2 = MRI->getVRegDef(SrcReg); DstReg = MI.getOperand(0).getReg(); diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFPreserveDIType.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/BPFPreserveDIType.cpp index c3cb7647aa79..0348e2200acb 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BPFPreserveDIType.cpp +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFPreserveDIType.cpp @@ -17,6 +17,7 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.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" @@ -33,58 +34,32 @@ using namespace llvm; namespace { -class BPFPreserveDIType final : public ModulePass { - StringRef getPassName() const override { - return "BPF Preserve DebugInfo Type"; - } - - bool runOnModule(Module &M) override; - -public: - static char ID; - BPFPreserveDIType() : ModulePass(ID) {} - -private: - bool doTransformation(Module &M); -}; -} // End anonymous namespace - -char BPFPreserveDIType::ID = 0; -INITIALIZE_PASS(BPFPreserveDIType, DEBUG_TYPE, "preserve debuginfo type", false, - false) - -ModulePass *llvm::createBPFPreserveDIType() { return new BPFPreserveDIType(); } - -bool BPFPreserveDIType::runOnModule(Module &M) { +static bool BPFPreserveDITypeImpl(Function &F) { LLVM_DEBUG(dbgs() << "********** preserve debuginfo type **********\n"); + Module *M = F.getParent(); + // Bail out if no debug info. - if (M.debug_compile_units().empty()) + if (M->debug_compile_units().empty()) return false; - return doTransformation(M); -} - -bool BPFPreserveDIType::doTransformation(Module &M) { std::vector<CallInst *> PreserveDITypeCalls; - for (auto &F : M) { - for (auto &BB : F) { - for (auto &I : BB) { - auto *Call = dyn_cast<CallInst>(&I); - if (!Call) - continue; - - const auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand()); - if (!GV) - continue; - - if (GV->getName().startswith("llvm.bpf.btf.type.id")) { - if (!Call->getMetadata(LLVMContext::MD_preserve_access_index)) - report_fatal_error( - "Missing metadata for llvm.bpf.btf.type.id intrinsic"); - PreserveDITypeCalls.push_back(Call); - } + for (auto &BB : F) { + for (auto &I : BB) { + auto *Call = dyn_cast<CallInst>(&I); + if (!Call) + continue; + + const auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand()); + if (!GV) + continue; + + if (GV->getName().startswith("llvm.bpf.btf.type.id")) { + if (!Call->getMetadata(LLVMContext::MD_preserve_access_index)) + report_fatal_error( + "Missing metadata for llvm.bpf.btf.type.id intrinsic"); + PreserveDITypeCalls.push_back(Call); } } } @@ -93,39 +68,81 @@ bool BPFPreserveDIType::doTransformation(Module &M) { return false; std::string BaseName = "llvm.btf_type_id."; - int Count = 0; + static int Count = 0; for (auto Call : PreserveDITypeCalls) { - const ConstantInt *Flag = dyn_cast<ConstantInt>(Call->getArgOperand(2)); + const ConstantInt *Flag = dyn_cast<ConstantInt>(Call->getArgOperand(1)); assert(Flag); uint64_t FlagValue = Flag->getValue().getZExtValue(); if (FlagValue >= BPFCoreSharedInfo::MAX_BTF_TYPE_ID_FLAG) report_fatal_error("Incorrect flag for llvm.bpf.btf.type.id intrinsic"); + MDNode *MD = Call->getMetadata(LLVMContext::MD_preserve_access_index); + uint32_t Reloc; - if (FlagValue == BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL_RELOC) + if (FlagValue == BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL_RELOC) { Reloc = BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL; - else + } else { Reloc = BPFCoreSharedInfo::BTF_TYPE_ID_REMOTE; + DIType *Ty = cast<DIType>(MD); + while (auto *DTy = dyn_cast<DIDerivedType>(Ty)) { + unsigned Tag = DTy->getTag(); + if (Tag != dwarf::DW_TAG_const_type && + Tag != dwarf::DW_TAG_volatile_type) + break; + Ty = DTy->getBaseType(); + } + + if (Ty->getName().empty()) + report_fatal_error("Empty type name for BTF_TYPE_ID_REMOTE reloc"); + MD = Ty; + } BasicBlock *BB = Call->getParent(); - IntegerType *VarType = Type::getInt32Ty(BB->getContext()); + IntegerType *VarType = Type::getInt64Ty(BB->getContext()); std::string GVName = BaseName + std::to_string(Count) + "$" + std::to_string(Reloc); - GlobalVariable *GV = - new GlobalVariable(M, VarType, false, GlobalVariable::ExternalLinkage, - NULL, GVName); + GlobalVariable *GV = new GlobalVariable( + *M, VarType, false, GlobalVariable::ExternalLinkage, NULL, GVName); GV->addAttribute(BPFCoreSharedInfo::TypeIdAttr); - MDNode *MD = Call->getMetadata(LLVMContext::MD_preserve_access_index); GV->setMetadata(LLVMContext::MD_preserve_access_index, MD); // Load the global variable which represents the type info. - auto *LDInst = new LoadInst(Type::getInt32Ty(BB->getContext()), GV, "", - Call); - Call->replaceAllUsesWith(LDInst); + auto *LDInst = + new LoadInst(Type::getInt64Ty(BB->getContext()), GV, "", Call); + Instruction *PassThroughInst = + BPFCoreSharedInfo::insertPassThrough(M, BB, LDInst, Call); + Call->replaceAllUsesWith(PassThroughInst); Call->eraseFromParent(); Count++; } return true; } + +class BPFPreserveDIType final : public FunctionPass { + bool runOnFunction(Function &F) override; + +public: + static char ID; + BPFPreserveDIType() : FunctionPass(ID) {} +}; +} // End anonymous namespace + +char BPFPreserveDIType::ID = 0; +INITIALIZE_PASS(BPFPreserveDIType, DEBUG_TYPE, "BPF Preserve Debuginfo Type", + false, false) + +FunctionPass *llvm::createBPFPreserveDIType() { + return new BPFPreserveDIType(); +} + +bool BPFPreserveDIType::runOnFunction(Function &F) { + return BPFPreserveDITypeImpl(F); +} + +PreservedAnalyses BPFPreserveDITypePass::run(Function &F, + FunctionAnalysisManager &AM) { + return BPFPreserveDITypeImpl(F) ? PreservedAnalyses::none() + : PreservedAnalyses::all(); +} diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFSubtarget.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/BPFSubtarget.cpp index f3cb03b1f1f5..fac02e6476b7 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BPFSubtarget.cpp +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFSubtarget.cpp @@ -29,7 +29,7 @@ BPFSubtarget &BPFSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { initializeEnvironment(); initSubtargetFeatures(CPU, FS); - ParseSubtargetFeatures(CPU, FS); + ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS); return *this; } @@ -59,6 +59,6 @@ void BPFSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) { BPFSubtarget::BPFSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS, const TargetMachine &TM) - : BPFGenSubtargetInfo(TT, CPU, FS), InstrInfo(), + : BPFGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), InstrInfo(), FrameLowering(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this) {} diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFSubtarget.h b/contrib/llvm-project/llvm/lib/Target/BPF/BPFSubtarget.h index 3da6a026ab7e..7649e0e92222 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BPFSubtarget.h +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFSubtarget.h @@ -67,7 +67,7 @@ public: // ParseSubtargetFeatures - Parses features string setting specified // subtarget options. Definition of function is auto generated by tblgen. - void ParseSubtargetFeatures(StringRef CPU, StringRef FS); + void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); bool getHasJmpExt() const { return HasJmpExt; } bool getHasJmp32() const { return HasJmp32; } bool getHasAlu32() const { return HasAlu32; } diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/BPFTargetMachine.cpp index 54204ee197ec..a8fef2517b03 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BPFTargetMachine.cpp +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFTargetMachine.cpp @@ -12,15 +12,22 @@ #include "BPFTargetMachine.h" #include "BPF.h" +#include "BPFTargetTransformInfo.h" #include "MCTargetDesc/BPFMCAsmInfo.h" #include "TargetInfo/BPFTargetInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Passes/PassBuilder.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Target/TargetOptions.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/SimplifyCFG.h" +#include "llvm/Transforms/Utils/SimplifyCFGOptions.h" using namespace llvm; static cl:: @@ -34,8 +41,10 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFTarget() { RegisterTargetMachine<BPFTargetMachine> Z(getTheBPFTarget()); PassRegistry &PR = *PassRegistry::getPassRegistry(); - initializeBPFAbstractMemberAccessPass(PR); + initializeBPFAbstractMemberAccessLegacyPassPass(PR); initializeBPFPreserveDITypePass(PR); + initializeBPFAdjustOptPass(PR); + initializeBPFCheckAndAdjustIRPass(PR); initializeBPFMIPeepholePass(PR); initializeBPFMIPeepholeTruncElimPass(PR); } @@ -49,9 +58,7 @@ static std::string computeDataLayout(const Triple &TT) { } static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM) { - if (!RM.hasValue()) - return Reloc::PIC_; - return *RM; + return RM.getValueOr(Reloc::PIC_); } BPFTargetMachine::BPFTargetMachine(const Target &T, const Triple &TT, @@ -94,14 +101,56 @@ TargetPassConfig *BPFTargetMachine::createPassConfig(PassManagerBase &PM) { return new BPFPassConfig(*this, PM); } -void BPFPassConfig::addIRPasses() { +void BPFTargetMachine::adjustPassManager(PassManagerBuilder &Builder) { + Builder.addExtension( + PassManagerBuilder::EP_EarlyAsPossible, + [&](const PassManagerBuilder &, legacy::PassManagerBase &PM) { + PM.add(createBPFAbstractMemberAccess(this)); + PM.add(createBPFPreserveDIType()); + }); + + Builder.addExtension( + PassManagerBuilder::EP_Peephole, + [&](const PassManagerBuilder &, legacy::PassManagerBase &PM) { + PM.add(createCFGSimplificationPass( + SimplifyCFGOptions().hoistCommonInsts(true))); + }); + Builder.addExtension( + PassManagerBuilder::EP_ModuleOptimizerEarly, + [&](const PassManagerBuilder &, legacy::PassManagerBase &PM) { + PM.add(createBPFAdjustOpt()); + }); +} - addPass(createBPFAbstractMemberAccess(&getBPFTargetMachine())); - addPass(createBPFPreserveDIType()); +void BPFTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB, + bool DebugPassManager) { + PB.registerPipelineStartEPCallback( + [=](ModulePassManager &MPM, PassBuilder::OptimizationLevel) { + FunctionPassManager FPM(DebugPassManager); + FPM.addPass(BPFAbstractMemberAccessPass(this)); + FPM.addPass(BPFPreserveDITypePass()); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + }); + PB.registerPeepholeEPCallback([=](FunctionPassManager &FPM, + PassBuilder::OptimizationLevel Level) { + FPM.addPass(SimplifyCFGPass(SimplifyCFGOptions().hoistCommonInsts(true))); + }); + PB.registerPipelineEarlySimplificationEPCallback( + [=](ModulePassManager &MPM, PassBuilder::OptimizationLevel) { + MPM.addPass(BPFAdjustOptPass()); + }); +} +void BPFPassConfig::addIRPasses() { + addPass(createBPFCheckAndAdjustIR()); TargetPassConfig::addIRPasses(); } +TargetTransformInfo +BPFTargetMachine::getTargetTransformInfo(const Function &F) { + return TargetTransformInfo(BPFTTIImpl(this, F)); +} + // Install an instruction selector pass using // the ISelDag to gen BPF code. bool BPFPassConfig::addInstSelector() { diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFTargetMachine.h b/contrib/llvm-project/llvm/lib/Target/BPF/BPFTargetMachine.h index beac7bd862da..61c8a44cc402 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BPFTargetMachine.h +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFTargetMachine.h @@ -34,9 +34,15 @@ public: TargetPassConfig *createPassConfig(PassManagerBase &PM) override; + TargetTransformInfo getTargetTransformInfo(const Function &F) override; + TargetLoweringObjectFile *getObjFileLowering() const override { return TLOF.get(); } + + void adjustPassManager(PassManagerBuilder &) override; + void registerPassBuilderCallbacks(PassBuilder &PB, + bool DebugPassManager) override; }; } diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFTargetTransformInfo.h b/contrib/llvm-project/llvm/lib/Target/BPF/BPFTargetTransformInfo.h new file mode 100644 index 000000000000..62055497e685 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFTargetTransformInfo.h @@ -0,0 +1,61 @@ +//===------ BPFTargetTransformInfo.h - BPF specific TTI ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file uses the target's specific information to +// provide more precise answers to certain TTI queries, while letting the +// target independent and default TTI implementations handle the rest. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_BPF_BPFTARGETTRANSFORMINFO_H +#define LLVM_LIB_TARGET_BPF_BPFTARGETTRANSFORMINFO_H + +#include "BPFTargetMachine.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/BasicTTIImpl.h" +#include "llvm/Transforms/Utils/ScalarEvolutionExpander.h" + +namespace llvm { +class BPFTTIImpl : public BasicTTIImplBase<BPFTTIImpl> { + typedef BasicTTIImplBase<BPFTTIImpl> BaseT; + typedef TargetTransformInfo TTI; + friend BaseT; + + const BPFSubtarget *ST; + const BPFTargetLowering *TLI; + + const BPFSubtarget *getST() const { return ST; } + const BPFTargetLowering *getTLI() const { return TLI; } + +public: + explicit BPFTTIImpl(const BPFTargetMachine *TM, const Function &F) + : BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)), + TLI(ST->getTargetLowering()) {} + + int getIntImmCost(const APInt &Imm, Type *Ty, TTI::TargetCostKind CostKind) { + if (Imm.getBitWidth() <= 64 && isInt<32>(Imm.getSExtValue())) + return TTI::TCC_Free; + + return TTI::TCC_Basic; + } + + int getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy, + CmpInst::Predicate VecPred, + TTI::TargetCostKind CostKind, + const llvm::Instruction *I = nullptr) { + if (Opcode == Instruction::Select) + return SCEVCheapExpansionBudget; + + return BaseT::getCmpSelInstrCost(Opcode, ValTy, CondTy, VecPred, CostKind, + I); + } +}; + +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_BPF_BPFTARGETTRANSFORMINFO_H diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BTF.def b/contrib/llvm-project/llvm/lib/Target/BPF/BTF.def index 2d2e9a04aa6d..66cf2c90ead4 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BTF.def +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BTF.def @@ -30,5 +30,6 @@ HANDLE_BTF_KIND(12, FUNC) HANDLE_BTF_KIND(13, FUNC_PROTO) HANDLE_BTF_KIND(14, VAR) HANDLE_BTF_KIND(15, DATASEC) +HANDLE_BTF_KIND(16, FLOAT) #undef HANDLE_BTF_KIND diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BTFDebug.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/BTFDebug.cpp index 4510e9357489..9249d679c7bd 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BTFDebug.cpp +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BTFDebug.cpp @@ -22,6 +22,7 @@ #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/Support/LineIterator.h" +#include "llvm/Target/TargetLoweringObjectFile.h" using namespace llvm; @@ -370,6 +371,21 @@ void BTFKindDataSec::emitType(MCStreamer &OS) { } } +BTFTypeFloat::BTFTypeFloat(uint32_t SizeInBits, StringRef TypeName) + : Name(TypeName) { + Kind = BTF::BTF_KIND_FLOAT; + BTFType.Info = Kind << 24; + BTFType.Size = roundupToBytes(SizeInBits); +} + +void BTFTypeFloat::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + + BTFType.NameOff = BDebug.addString(Name); +} + uint32_t BTFStringTable::addString(StringRef S) { // Check whether the string already exists. for (auto &OffsetM : OffsetToIdMap) { @@ -408,18 +424,28 @@ uint32_t BTFDebug::addType(std::unique_ptr<BTFTypeBase> TypeEntry) { } void BTFDebug::visitBasicType(const DIBasicType *BTy, uint32_t &TypeId) { - // Only int types are supported in BTF. + // Only int and binary floating point types are supported in BTF. uint32_t Encoding = BTy->getEncoding(); - if (Encoding != dwarf::DW_ATE_boolean && Encoding != dwarf::DW_ATE_signed && - Encoding != dwarf::DW_ATE_signed_char && - Encoding != dwarf::DW_ATE_unsigned && - Encoding != dwarf::DW_ATE_unsigned_char) + std::unique_ptr<BTFTypeBase> TypeEntry; + switch (Encoding) { + case dwarf::DW_ATE_boolean: + case dwarf::DW_ATE_signed: + case dwarf::DW_ATE_signed_char: + case dwarf::DW_ATE_unsigned: + case dwarf::DW_ATE_unsigned_char: + // Create a BTF type instance for this DIBasicType and put it into + // DIToIdMap for cross-type reference check. + TypeEntry = std::make_unique<BTFTypeInt>( + Encoding, BTy->getSizeInBits(), BTy->getOffsetInBits(), BTy->getName()); + break; + case dwarf::DW_ATE_float: + TypeEntry = + std::make_unique<BTFTypeFloat>(BTy->getSizeInBits(), BTy->getName()); + break; + default: return; + } - // Create a BTF type instance for this DIBasicType and put it into - // DIToIdMap for cross-type reference check. - auto TypeEntry = std::make_unique<BTFTypeInt>( - Encoding, BTy->getSizeInBits(), BTy->getOffsetInBits(), BTy->getName()); TypeId = addType(std::move(TypeEntry), BTy); } @@ -993,12 +1019,13 @@ void BTFDebug::generatePatchImmReloc(const MCSymbol *ORSym, uint32_t RootId, FieldReloc.OffsetNameOff = addString(IndexPattern); FieldReloc.RelocKind = std::stoull(std::string(RelocKindStr)); - PatchImms[GVar] = std::stoul(std::string(PatchImmStr)); + PatchImms[GVar] = std::make_pair(std::stoll(std::string(PatchImmStr)), + FieldReloc.RelocKind); } else { StringRef RelocStr = AccessPattern.substr(FirstDollar + 1); FieldReloc.OffsetNameOff = addString("0"); FieldReloc.RelocKind = std::stoull(std::string(RelocStr)); - PatchImms[GVar] = RootId; + PatchImms[GVar] = std::make_pair(RootId, FieldReloc.RelocKind); } FieldRelocTable[SecNameOff].push_back(FieldReloc); } @@ -1074,6 +1101,9 @@ void BTFDebug::beginInstruction(const MachineInstr *MI) { } } + if (!CurMI) // no debug info + return; + // Skip this instruction if no DebugLoc or the DebugLoc // is the same as the previous instruction. const DebugLoc &DL = MI->getDebugLoc(); @@ -1125,6 +1155,20 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) { if (ProcessingMapDef != SecName.startswith(".maps")) continue; + // Create a .rodata datasec if the global variable is an initialized + // constant with private linkage and if it won't be in .rodata.str<#> + // and .rodata.cst<#> sections. + if (SecName == ".rodata" && Global.hasPrivateLinkage() && + DataSecEntries.find(std::string(SecName)) == DataSecEntries.end()) { + SectionKind GVKind = + TargetLoweringObjectFile::getKindForGlobal(&Global, Asm->TM); + // skip .rodata.str<#> and .rodata.cst<#> sections + if (!GVKind.isMergeableCString() && !GVKind.isMergeableConst()) { + DataSecEntries[std::string(SecName)] = + std::make_unique<BTFKindDataSec>(Asm, std::string(SecName)); + } + } + SmallVector<DIGlobalVariableExpression *, 1> GVs; Global.getDebugInfo(GVs); @@ -1152,6 +1196,7 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) { if (Linkage != GlobalValue::InternalLinkage && Linkage != GlobalValue::ExternalLinkage && Linkage != GlobalValue::WeakAnyLinkage && + Linkage != GlobalValue::WeakODRLinkage && Linkage != GlobalValue::ExternalWeakLinkage) continue; @@ -1180,8 +1225,8 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) { const DataLayout &DL = Global.getParent()->getDataLayout(); uint32_t Size = DL.getTypeAllocSize(Global.getType()->getElementType()); - DataSecEntries[std::string(SecName)]->addVar(VarId, Asm->getSymbol(&Global), - Size); + DataSecEntries[std::string(SecName)]->addDataSecEntry(VarId, + Asm->getSymbol(&Global), Size); } } @@ -1194,14 +1239,23 @@ bool BTFDebug::InstLower(const MachineInstr *MI, MCInst &OutMI) { auto *GVar = dyn_cast<GlobalVariable>(GVal); if (GVar) { // Emit "mov ri, <imm>" - uint32_t Imm; + int64_t Imm; + uint32_t Reloc; if (GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr) || - GVar->hasAttribute(BPFCoreSharedInfo::TypeIdAttr)) - Imm = PatchImms[GVar]; - else + GVar->hasAttribute(BPFCoreSharedInfo::TypeIdAttr)) { + Imm = PatchImms[GVar].first; + Reloc = PatchImms[GVar].second; + } else { return false; + } - OutMI.setOpcode(BPF::MOV_ri); + if (Reloc == BPFCoreSharedInfo::ENUM_VALUE_EXISTENCE || + Reloc == BPFCoreSharedInfo::ENUM_VALUE || + Reloc == BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL || + Reloc == BPFCoreSharedInfo::BTF_TYPE_ID_REMOTE) + OutMI.setOpcode(BPF::LD_imm64); + else + OutMI.setOpcode(BPF::MOV_ri); OutMI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); OutMI.addOperand(MCOperand::createImm(Imm)); return true; @@ -1215,7 +1269,7 @@ bool BTFDebug::InstLower(const MachineInstr *MI, MCInst &OutMI) { const GlobalValue *GVal = MO.getGlobal(); auto *GVar = dyn_cast<GlobalVariable>(GVal); if (GVar && GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) { - uint32_t Imm = PatchImms[GVar]; + uint32_t Imm = PatchImms[GVar].first; OutMI.setOpcode(MI->getOperand(1).getImm()); if (MI->getOperand(0).isImm()) OutMI.addOperand(MCOperand::createImm(MI->getOperand(0).getImm())); @@ -1250,7 +1304,19 @@ void BTFDebug::processFuncPrototypes(const Function *F) { uint8_t Scope = BTF::FUNC_EXTERN; auto FuncTypeEntry = std::make_unique<BTFTypeFunc>(SP->getName(), ProtoTypeId, Scope); - addType(std::move(FuncTypeEntry)); + uint32_t FuncId = addType(std::move(FuncTypeEntry)); + if (F->hasSection()) { + StringRef SecName = F->getSection(); + + if (DataSecEntries.find(std::string(SecName)) == DataSecEntries.end()) { + DataSecEntries[std::string(SecName)] = + std::make_unique<BTFKindDataSec>(Asm, std::string(SecName)); + } + + // We really don't know func size, set it to 0. + DataSecEntries[std::string(SecName)]->addDataSecEntry(FuncId, + Asm->getSymbol(F), 0); + } } void BTFDebug::endModule() { diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BTFDebug.h b/contrib/llvm-project/llvm/lib/Target/BPF/BTFDebug.h index 2f39f665299a..76f1901779bb 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/BTFDebug.h +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BTFDebug.h @@ -16,7 +16,8 @@ #include "llvm/ADT/StringMap.h" #include "llvm/CodeGen/DebugHandlerBase.h" -#include "llvm/CodeGen/MachineInstr.h" +#include <cstdint> +#include <map> #include <set> #include <unordered_map> #include "BTF.h" @@ -27,9 +28,12 @@ class AsmPrinter; class BTFDebug; class DIType; class GlobalVariable; +class MachineFunction; +class MachineInstr; +class MachineOperand; +class MCInst; class MCStreamer; class MCSymbol; -class MachineFunction; /// The base class for BTF type generation. class BTFTypeBase { @@ -183,7 +187,7 @@ public: uint32_t getSize() override { return BTFTypeBase::getSize() + BTF::BTFDataSecVarSize * Vars.size(); } - void addVar(uint32_t Id, const MCSymbol *Sym, uint32_t Size) { + void addDataSecEntry(uint32_t Id, const MCSymbol *Sym, uint32_t Size) { Vars.push_back(std::make_tuple(Id, Sym, Size)); } std::string getName() { return Name; } @@ -191,6 +195,15 @@ public: void emitType(MCStreamer &OS) override; }; +/// Handle binary floating point type. +class BTFTypeFloat : public BTFTypeBase { + StringRef Name; + +public: + BTFTypeFloat(uint32_t SizeInBits, StringRef TypeName); + void completeType(BTFDebug &BDebug) override; +}; + /// String table. class BTFStringTable { /// String table size in bytes. @@ -251,7 +264,7 @@ class BTFDebug : public DebugHandlerBase { StringMap<std::vector<std::string>> FileContent; std::map<std::string, std::unique_ptr<BTFKindDataSec>> DataSecEntries; std::vector<BTFTypeStruct *> StructTypes; - std::map<const GlobalVariable *, uint32_t> PatchImms; + std::map<const GlobalVariable *, std::pair<int64_t, uint32_t>> PatchImms; std::map<StringRef, std::pair<bool, std::vector<BTFTypeDerived *>>> FixupDerivedTypes; std::set<const Function *>ProtoFunctions; diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/Disassembler/BPFDisassembler.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/Disassembler/BPFDisassembler.cpp index 4d98dc7341d0..3a1492743bf4 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/Disassembler/BPFDisassembler.cpp +++ b/contrib/llvm-project/llvm/lib/Target/BPF/Disassembler/BPFDisassembler.cpp @@ -58,7 +58,7 @@ public: BPF_MEM = 0x3, BPF_LEN = 0x4, BPF_MSH = 0x5, - BPF_XADD = 0x6 + BPF_ATOMIC = 0x6 }; BPFDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) @@ -176,7 +176,7 @@ DecodeStatus BPFDisassembler::getInstruction(MCInst &Instr, uint64_t &Size, uint8_t InstMode = getInstMode(Insn); if ((InstClass == BPF_LDX || InstClass == BPF_STX) && getInstSize(Insn) != BPF_DW && - (InstMode == BPF_MEM || InstMode == BPF_XADD) && + (InstMode == BPF_MEM || InstMode == BPF_ATOMIC) && STI.getFeatureBits()[BPF::ALU32]) Result = decodeInstruction(DecoderTableBPFALU3264, Instr, Insn, Address, this, STI); diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp index 9d829ac45a10..29e9d5da0836 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp +++ b/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp @@ -43,11 +43,6 @@ public: unsigned getNumFixupKinds() const override { return 1; } - bool mayNeedRelaxation(const MCInst &Inst, - const MCSubtargetInfo &STI) const override { - return false; - } - bool writeNopData(raw_ostream &OS, uint64_t Count) const override; }; diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFInstPrinter.h b/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFInstPrinter.h index 2181bb575cdd..e76067ea41ae 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFInstPrinter.h +++ b/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFInstPrinter.h @@ -32,6 +32,7 @@ public: void printBrTargetOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); // Autogenerated by tblgen. + std::pair<const char *, uint64_t> getMnemonic(const MCInst *MI) override; void printInstruction(const MCInst *MI, uint64_t Address, raw_ostream &O); static const char *getRegisterName(unsigned RegNo); }; diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp index f9abe76c976b..12af92e0d198 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp +++ b/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp @@ -13,6 +13,7 @@ #include "MCTargetDesc/BPFMCTargetDesc.h" #include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrInfo.h" @@ -158,12 +159,18 @@ void BPFMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, uint64_t BPFMCCodeEmitter::getMemoryOpValue(const MCInst &MI, unsigned Op, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { + // For CMPXCHG instructions, output is implicitly in R0/W0, + // so memory operand starts from operand 0. + int MemOpStartIndex = 1, Opcode = MI.getOpcode(); + if (Opcode == BPF::CMPXCHGW32 || Opcode == BPF::CMPXCHGD) + MemOpStartIndex = 0; + uint64_t Encoding; - const MCOperand Op1 = MI.getOperand(1); + const MCOperand Op1 = MI.getOperand(MemOpStartIndex); assert(Op1.isReg() && "First operand is not register."); Encoding = MRI.getEncodingValue(Op1.getReg()); Encoding <<= 16; - MCOperand Op2 = MI.getOperand(2); + MCOperand Op2 = MI.getOperand(MemOpStartIndex + 1); assert(Op2.isImm() && "Second operand is not immediate."); Encoding |= Op2.getImm() & 0xffff; return Encoding; diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp index 58da0830d002..8fb7d7e89f09 100644 --- a/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp +++ b/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp @@ -46,7 +46,7 @@ static MCRegisterInfo *createBPFMCRegisterInfo(const Triple &TT) { static MCSubtargetInfo *createBPFMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { - return createBPFMCSubtargetInfoImpl(TT, CPU, FS); + return createBPFMCSubtargetInfoImpl(TT, CPU, /*TuneCPU*/ CPU, FS); } static MCStreamer *createBPFMCStreamer(const Triple &T, MCContext &Ctx, |