diff --git a/llvm/include/llvm/IR/IntrinsicsBPF.td b/llvm/include/llvm/IR/IntrinsicsBPF.td --- a/llvm/include/llvm/IR/IntrinsicsBPF.td +++ b/llvm/include/llvm/IR/IntrinsicsBPF.td @@ -34,7 +34,4 @@ [IntrNoMem]>; def int_bpf_passthrough : ClangBuiltin<"__builtin_bpf_passthrough">, Intrinsic<[llvm_any_ty], [llvm_i32_ty, llvm_any_ty], [IntrNoMem]>; - def int_bpf_compare : ClangBuiltin<"__builtin_bpf_compare">, - Intrinsic<[llvm_i1_ty], [llvm_i32_ty, llvm_anyint_ty, llvm_anyint_ty], - [IntrNoMem]>; } diff --git a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h --- a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h +++ b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h @@ -38,6 +38,9 @@ class TargetLibraryInfo; class TargetTransformInfo; +extern cl::opt EnableFoldAndOrOfICmpsUsingRanges; +extern cl::opt EnableFoldICmpWithCastOp; + /// The core instruction combiner logic. /// /// This class provides both the logic to recursively visit instructions and diff --git a/llvm/include/llvm/Transforms/Utils/Local.h b/llvm/include/llvm/Transforms/Utils/Local.h --- a/llvm/include/llvm/Transforms/Utils/Local.h +++ b/llvm/include/llvm/Transforms/Utils/Local.h @@ -171,6 +171,8 @@ /// block that was pointed to. LoopHeaders is an optional input parameter /// providing the set of loop headers that SimplifyCFG should not eliminate. extern cl::opt RequireAndPreserveDomTree; +extern cl::opt AllowHoistInstr; +extern cl::opt AllowFoldTwoEntryPHINode; bool simplifyCFG(BasicBlock *BB, const TargetTransformInfo &TTI, DomTreeUpdater *DTU = nullptr, const SimplifyCFGOptions &Options = {}, diff --git a/llvm/lib/Target/BPF/BPF.h b/llvm/lib/Target/BPF/BPF.h --- a/llvm/lib/Target/BPF/BPF.h +++ b/llvm/lib/Target/BPF/BPF.h @@ -18,7 +18,6 @@ class BPFTargetMachine; class PassRegistry; -ModulePass *createBPFAdjustOpt(); ModulePass *createBPFCheckAndAdjustIR(); FunctionPass *createBPFAbstractMemberAccess(BPFTargetMachine *TM); @@ -32,7 +31,6 @@ FunctionPass *createBPFMIPreEmitCheckingPass(); void initializeBPFAbstractMemberAccessLegacyPassPass(PassRegistry &); -void initializeBPFAdjustOptPass(PassRegistry&); void initializeBPFCheckAndAdjustIRPass(PassRegistry&); void initializeBPFDAGToDAGISelPass(PassRegistry &); void initializeBPFIRPeepholePass(PassRegistry &); @@ -67,11 +65,6 @@ static bool isRequired() { return true; } }; - -class BPFAdjustOptPass : public PassInfoMixin { -public: - PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); -}; } // namespace llvm #endif diff --git a/llvm/lib/Target/BPF/BPFAdjustOpt.cpp b/llvm/lib/Target/BPF/BPFAdjustOpt.cpp deleted file mode 100644 --- a/llvm/lib/Target/BPF/BPFAdjustOpt.cpp +++ /dev/null @@ -1,393 +0,0 @@ -//===---------------- 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/IntrinsicsBPF.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/PatternMatch.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; -using namespace llvm::PatternMatch; - -static cl::opt - DisableBPFserializeICMP("bpf-disable-serialize-icmp", cl::Hidden, - cl::desc("BPF: Disable Serializing ICMP insns."), - cl::init(false)); - -static cl::opt 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 PassThroughs; - - bool adjustICmpToBuiltin(); - 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() { - bool Changed = adjustICmpToBuiltin(); - - for (Function &F : *M) - for (auto &BB : F) { - adjustBasicBlock(BB); - for (auto &I : BB) - adjustInst(I); - } - return insertPassThrough() || Changed; -} - -// Commit acabad9ff6bf ("[InstCombine] try to canonicalize icmp with -// trunc op into mask and cmp") added a transformation to -// convert "(conv)a < power_2_const" to "a & " in certain -// cases and bpf kernel verifier has to handle the resulted code -// conservatively and this may reject otherwise legitimate program. -// Here, we change related icmp code to a builtin which will -// be restored to original icmp code later to prevent that -// InstCombine transformatin. -bool BPFAdjustOptImpl::adjustICmpToBuiltin() { - bool Changed = false; - ICmpInst *ToBeDeleted = nullptr; - for (Function &F : *M) - for (auto &BB : F) - for (auto &I : BB) { - if (ToBeDeleted) { - ToBeDeleted->eraseFromParent(); - ToBeDeleted = nullptr; - } - - auto *Icmp = dyn_cast(&I); - if (!Icmp) - continue; - - Value *Op0 = Icmp->getOperand(0); - if (!isa(Op0)) - continue; - - auto ConstOp1 = dyn_cast(Icmp->getOperand(1)); - if (!ConstOp1) - continue; - - auto ConstOp1Val = ConstOp1->getValue().getZExtValue(); - auto Op = Icmp->getPredicate(); - if (Op == ICmpInst::ICMP_ULT || Op == ICmpInst::ICMP_UGE) { - if ((ConstOp1Val - 1) & ConstOp1Val) - continue; - } else if (Op == ICmpInst::ICMP_ULE || Op == ICmpInst::ICMP_UGT) { - if (ConstOp1Val & (ConstOp1Val + 1)) - continue; - } else { - continue; - } - - Constant *Opcode = - ConstantInt::get(Type::getInt32Ty(BB.getContext()), Op); - Function *Fn = Intrinsic::getDeclaration( - M, Intrinsic::bpf_compare, {Op0->getType(), ConstOp1->getType()}); - auto *NewInst = CallInst::Create(Fn, {Opcode, Op0, ConstOp1}); - NewInst->insertBefore(&I); - Icmp->replaceAllUsesWith(NewInst); - Changed = true; - ToBeDeleted = Icmp; - } - - return Changed; -} - -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 ...; - // comp2 = icmp ...; - // ... or comp1 comp2 ... - // changed to: - // comp1 = icmp ...; - // comp2 = icmp ...; - // new_comp1 = __builtin_bpf_passthrough(seq_num, comp1) - // ... or new_comp1 comp2 ... - Value *Op0, *Op1; - // Use LogicalOr (accept `or i1` as well as `select i1 Op0, true, Op1`) - if (!match(&I, m_LogicalOr(m_Value(Op0), m_Value(Op1)))) - return false; - auto *Icmp1 = dyn_cast(Op0); - if (!Icmp1) - return false; - auto *Icmp2 = dyn_cast(Op1); - 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 ...; - // if (comp1) goto B2 else B3; - // B2: - // comp2 = icmp ...; - // if (comp2) goto B4 else B5; - // B4: - // ... - // changed to: - // B1: - // comp1 = icmp ...; - // comp1 = __builtin_bpf_passthrough(seq_num, comp1); - // if (comp1) goto B2 else B3; - // B2: - // comp2 = icmp ...; - // 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(TI); - if (!BI || !BI->isConditional()) - return false; - auto *Cond = dyn_cast(BI->getCondition()); - if (!Cond || B2->getFirstNonPHI() != Cond) - return false; - Value *B2Op0 = Cond->getOperand(0); - auto Cond2Op = Cond->getPredicate(); - - TI = B1->getTerminator(); - BI = dyn_cast(TI); - if (!BI || !BI->isConditional()) - return false; - Cond = dyn_cast(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 && Cond2Op != ICmpInst::ICMP_SLE) - return false; - } else if (Cond1Op == ICmpInst::ICMP_SLT || Cond1Op == ICmpInst::ICMP_SLE) { - if (Cond2Op != ICmpInst::ICMP_SGT && Cond2Op != ICmpInst::ICMP_SGE) - return false; - } else if (Cond1Op == ICmpInst::ICMP_ULT || Cond1Op == ICmpInst::ICMP_ULE) { - if (Cond2Op != ICmpInst::ICMP_UGT && Cond2Op != ICmpInst::ICMP_UGE) - return false; - } else if (Cond1Op == ICmpInst::ICMP_UGT || Cond1Op == ICmpInst::ICMP_UGE) { - if (Cond2Op != ICmpInst::ICMP_ULT && Cond2Op != ICmpInst::ICMP_ULE) - 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(&I)) { - if (auto *GV = dyn_cast(LdInst->getOperand(0))) { - if (GV->hasAttribute(BPFCoreSharedInfo::AmaAttr) || - GV->hasAttribute(BPFCoreSharedInfo::TypeIdAttr)) - return false; - } - } - - if (!isa(&I) && !isa(&I)) - return false; - - // For: - // B1: - // var = ... - // ... - // /* icmp may not be in the same block as var = ... */ - // comp1 = icmp var, ; - // if (comp1) goto B2 else B3; - // B2: - // ... var ... - // change to: - // B1: - // var = ... - // ... - // /* icmp may not be in the same block as var = ... */ - // comp1 = icmp var, ; - // if (comp1) goto B2 else B3; - // B2: - // var = __builtin_bpf_passthrough(seq_num, var); - // ... var ... - bool isCandidate = false; - SmallVector Candidates; - for (User *U : I.users()) { - Instruction *Inst = dyn_cast(U); - if (!Inst) - continue; - - // May cover a little bit more than the - // above pattern. - if (auto *Icmp1 = dyn_cast(Inst)) { - Value *Icmp1Op1 = Icmp1->getOperand(1); - if (!isa(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 (isa(&I2)) - return false; - if (isa(&I2) || isa(&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(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/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp b/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp --- a/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp +++ b/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp @@ -46,7 +46,6 @@ void checkIR(Module &M); bool adjustIR(Module &M); bool removePassThroughBuiltin(Module &M); - bool removeCompareBuiltin(Module &M); }; } // End anonymous namespace @@ -121,50 +120,8 @@ return Changed; } -bool BPFCheckAndAdjustIR::removeCompareBuiltin(Module &M) { - // Remove __builtin_bpf_compare()'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(&I); - if (!Call) - continue; - auto *GV = dyn_cast(Call->getCalledOperand()); - if (!GV) - continue; - if (!GV->getName().startswith("llvm.bpf.compare")) - continue; - - Changed = true; - Value *Arg0 = Call->getArgOperand(0); - Value *Arg1 = Call->getArgOperand(1); - Value *Arg2 = Call->getArgOperand(2); - - auto OpVal = cast(Arg0)->getValue().getZExtValue(); - CmpInst::Predicate Opcode = (CmpInst::Predicate)OpVal; - - auto *ICmp = new ICmpInst(Opcode, Arg1, Arg2); - ICmp->insertBefore(Call); - - Call->replaceAllUsesWith(ICmp); - ToBeDeleted = Call; - } - return Changed; -} - bool BPFCheckAndAdjustIR::adjustIR(Module &M) { - bool Changed = removePassThroughBuiltin(M); - Changed = removeCompareBuiltin(M) || Changed; - return Changed; + return removePassThroughBuiltin(M); } bool BPFCheckAndAdjustIR::runOnModule(Module &M) { diff --git a/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/llvm/lib/Target/BPF/BPFTargetMachine.cpp --- a/llvm/lib/Target/BPF/BPFTargetMachine.cpp +++ b/llvm/lib/Target/BPF/BPFTargetMachine.cpp @@ -43,7 +43,6 @@ initializeBPFAbstractMemberAccessLegacyPassPass(PR); initializeBPFPreserveDITypePass(PR); initializeBPFIRPeepholePass(PR); - initializeBPFAdjustOptPass(PR); initializeBPFCheckAndAdjustIRPass(PR); initializeBPFMIPeepholePass(PR); initializeBPFMIPeepholeTruncElimPass(PR); @@ -115,10 +114,6 @@ OptimizationLevel Level) { FPM.addPass(SimplifyCFGPass(SimplifyCFGOptions().hoistCommonInsts(true))); }); - PB.registerPipelineEarlySimplificationEPCallback( - [=](ModulePassManager &MPM, OptimizationLevel) { - MPM.addPass(BPFAdjustOptPass()); - }); } void BPFPassConfig::addIRPasses() { diff --git a/llvm/lib/Target/BPF/BPFTargetTransformInfo.h b/llvm/lib/Target/BPF/BPFTargetTransformInfo.h --- a/llvm/lib/Target/BPF/BPFTargetTransformInfo.h +++ b/llvm/lib/Target/BPF/BPFTargetTransformInfo.h @@ -19,6 +19,8 @@ #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/CodeGen/BasicTTIImpl.h" #include "llvm/Transforms/Utils/ScalarEvolutionExpander.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" +#include "llvm/Transforms/Utils/Local.h" namespace llvm { class BPFTTIImpl : public BasicTTIImplBase { @@ -35,7 +37,13 @@ public: explicit BPFTTIImpl(const BPFTargetMachine *TM, const Function &F) : BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)), - TLI(ST->getTargetLowering()) {} + TLI(ST->getTargetLowering()) { + // Disable certain optimizations which may cause verification failure. + AllowFoldTwoEntryPHINode = false; + AllowHoistInstr = false; + EnableFoldAndOrOfICmpsUsingRanges = false; + EnableFoldICmpWithCastOp = false; + } int getIntImmCost(const APInt &Imm, Type *Ty, TTI::TargetCostKind CostKind) { if (Imm.getBitWidth() <= 64 && isInt<32>(Imm.getSExtValue())) diff --git a/llvm/lib/Target/BPF/CMakeLists.txt b/llvm/lib/Target/BPF/CMakeLists.txt --- a/llvm/lib/Target/BPF/CMakeLists.txt +++ b/llvm/lib/Target/BPF/CMakeLists.txt @@ -16,7 +16,6 @@ add_llvm_target(BPFCodeGen BPFAbstractMemberAccess.cpp - BPFAdjustOpt.cpp BPFAsmPrinter.cpp BPFCheckAndAdjustIR.cpp BPFFrameLowering.cpp diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -24,6 +24,11 @@ #define DEBUG_TYPE "instcombine" +/// FoldAndOrOfICmpsUsingRanges optimization is enabled by default. +cl::opt llvm::EnableFoldAndOrOfICmpsUsingRanges( + "enable-instcombine-foldAndOrOfICmpsUsingRanges", cl::Hidden, cl::init(true), + cl::desc("Enable FoldAndOrOfICmpsUsingRanges transformation")); + /// This is the complement of getICmpCode, which turns an opcode and two /// operands into either a constant true or false, or a brand new ICmp /// instruction. The sign is passed in to determine which kind of predicate to @@ -1168,6 +1173,9 @@ Value *InstCombinerImpl::foldAndOrOfICmpsUsingRanges(ICmpInst *ICmp1, ICmpInst *ICmp2, bool IsAnd) { + if (!EnableFoldAndOrOfICmpsUsingRanges) + return nullptr; + ICmpInst::Predicate Pred1, Pred2; Value *V1, *V2; const APInt *C1, *C2; diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -35,6 +35,11 @@ // How many times is a select replaced by one of its operands? STATISTIC(NumSel, "Number of select opts"); +/// foldICmpWithCastOp optimization is enabled by default. +cl::opt llvm::EnableFoldICmpWithCastOp( + "enable-instcombine-foldICmpWithCastOp", cl::Hidden, cl::init(true), + cl::desc("Enable FoldICmpWithCastOp transformation")); + /// Compute Result = In1+In2, returning true if the result overflowed for this /// type. @@ -5064,6 +5069,9 @@ /// Handle icmp (cast x), (cast or constant). Instruction *InstCombinerImpl::foldICmpWithCastOp(ICmpInst &ICmp) { + if (!EnableFoldICmpWithCastOp) + return nullptr; + // If any operand of ICmp is a inttoptr roundtrip cast then remove it as // icmp compares only pointer's value. // icmp (inttoptr (ptrtoint p1)), p2 --> icmp p1, p2. diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -98,6 +98,14 @@ cl::desc("Temorary development switch used to gradually uplift SimplifyCFG " "into preserving DomTree,")); +cl::opt llvm::AllowHoistInstr( + "allow-hoist-instr", cl::Hidden, cl::init(true), + cl::desc("Allow HoistInstr transformation")); + +cl::opt llvm::AllowFoldTwoEntryPHINode( + "allow-fold-twoentry-phi-node", cl::Hidden, cl::init(true), + cl::desc("Allow FoldTwoEntryPHINode transformation")); + // Chosen as 2 so as to be cheap, but still to have enough power to fold // a select, so the "clamp" idiom (of a min followed by a max) will be caught. // To catch this, we need to fold a compare and a select, hence '2' being the @@ -1455,6 +1463,9 @@ // Returns true if it is safe to reorder an instruction across preceding // instructions in a basic block. static bool isSafeToHoistInstr(Instruction *I, unsigned Flags) { + if (!AllowHoistInstr) + return false; + // Don't reorder a store over a load. if ((Flags & SkipReadMem) && I->mayWriteToMemory()) return false; @@ -3289,6 +3300,9 @@ /// see if we can eliminate it. static bool FoldTwoEntryPHINode(PHINode *PN, const TargetTransformInfo &TTI, DomTreeUpdater *DTU, const DataLayout &DL) { + if (!AllowFoldTwoEntryPHINode) + return false; + // Ok, this is a two entry PHI node. Check to see if this is a simple "if // statement", which has a very simple dominance structure. Basically, we // are trying to find the condition that is being branched on, which diff --git a/llvm/test/CodeGen/BPF/adjust-opt-icmp1.ll b/llvm/test/CodeGen/BPF/adjust-opt-icmp1.ll --- a/llvm/test/CodeGen/BPF/adjust-opt-icmp1.ll +++ b/llvm/test/CodeGen/BPF/adjust-opt-icmp1.ll @@ -2,10 +2,6 @@ ; RUN: llc %t1 -o - | FileCheck -check-prefixes=CHECK %s ; RUN: opt -passes='default' -mtriple=bpf-pc-linux %s | llvm-dis > %t1 ; RUN: llc %t1 -o - | FileCheck -check-prefixes=CHECK %s -; RUN: opt -O2 -mtriple=bpf-pc-linux -bpf-disable-serialize-icmp %s | llvm-dis > %t1 -; RUN: llc %t1 -o - | FileCheck -check-prefixes=CHECK-DISABLE %s -; RUN: opt -passes='default' -mtriple=bpf-pc-linux -bpf-disable-serialize-icmp %s | llvm-dis > %t1 -; RUN: llc %t1 -o - | FileCheck -check-prefixes=CHECK-DISABLE %s ; ; Source: ; int foo(); diff --git a/llvm/test/CodeGen/BPF/adjust-opt-icmp2.ll b/llvm/test/CodeGen/BPF/adjust-opt-icmp2.ll --- a/llvm/test/CodeGen/BPF/adjust-opt-icmp2.ll +++ b/llvm/test/CodeGen/BPF/adjust-opt-icmp2.ll @@ -1,7 +1,5 @@ ; RUN: opt -O2 -mtriple=bpf-pc-linux %s | llvm-dis > %t1 ; RUN: llc %t1 -o - | FileCheck -check-prefixes=CHECK %s -; RUN: opt -O2 -mtriple=bpf-pc-linux -bpf-disable-serialize-icmp %s | llvm-dis > %t1 -; RUN: llc %t1 -o - | FileCheck -check-prefixes=CHECK-DISABLE %s ; ; Source: ; int foo(); diff --git a/llvm/test/CodeGen/BPF/adjust-opt-icmp3.ll b/llvm/test/CodeGen/BPF/adjust-opt-icmp3.ll --- a/llvm/test/CodeGen/BPF/adjust-opt-icmp3.ll +++ b/llvm/test/CodeGen/BPF/adjust-opt-icmp3.ll @@ -40,8 +40,8 @@ } ; CHECK-LABEL: test1 -; CHECK-V1: if r[[#]] > r[[#]] goto -; CHECK-V3: if w[[#]] < 4 goto +; CHECK-V1: if r[[#]] > 3 goto +; CHECK-V3: if w[[#]] > 3 goto ; Function Attrs: nounwind define dso_local i32 @test2(i64 %a) #0 { @@ -68,8 +68,8 @@ } ; CHECK-LABEL: test2 -; CHECK-V1: if r[[#]] > r[[#]] goto -; CHECK-V3: if w[[#]] < 4 goto +; CHECK-V1: if r[[#]] > 3 goto +; CHECK-V3: if w[[#]] > 3 goto attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } diff --git a/llvm/test/CodeGen/BPF/adjust-opt-speculative1.ll b/llvm/test/CodeGen/BPF/adjust-opt-speculative1.ll --- a/llvm/test/CodeGen/BPF/adjust-opt-speculative1.ll +++ b/llvm/test/CodeGen/BPF/adjust-opt-speculative1.ll @@ -1,7 +1,5 @@ ; RUN: opt -O2 -mtriple=bpf-pc-linux %s | llvm-dis > %t1 ; RUN: llc %t1 -o - | FileCheck -check-prefixes=CHECK-COMMON,CHECK %s -; RUN: opt -O2 -mtriple=bpf-pc-linux -bpf-disable-avoid-speculation %s | llvm-dis > %t1 -; RUN: llc %t1 -o - | FileCheck -check-prefixes=CHECK-COMMON,CHECK-DISABLE %s ; ; Source: ; unsigned long foo(); diff --git a/llvm/test/CodeGen/BPF/adjust-opt-speculative2.ll b/llvm/test/CodeGen/BPF/adjust-opt-speculative2.ll --- a/llvm/test/CodeGen/BPF/adjust-opt-speculative2.ll +++ b/llvm/test/CodeGen/BPF/adjust-opt-speculative2.ll @@ -1,7 +1,5 @@ ; RUN: opt -O2 -mtriple=bpf-pc-linux %s | llvm-dis > %t1 ; RUN: llc %t1 -o - | FileCheck -check-prefixes=CHECK-COMMON,CHECK %s -; RUN: opt -O2 -mtriple=bpf-pc-linux -bpf-disable-avoid-speculation %s | llvm-dis > %t1 -; RUN: llc %t1 -o - | FileCheck -check-prefixes=CHECK-COMMON,CHECK-DISABLE %s ; ; Source: ; unsigned foo();