diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Transforms/Utils/SCCPSolver.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Transforms/Utils/SCCPSolver.cpp | 204 |
1 files changed, 59 insertions, 145 deletions
diff --git a/contrib/llvm-project/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/contrib/llvm-project/llvm/lib/Transforms/Utils/SCCPSolver.cpp index d7e8eaf677c6..eee91e70292e 100644 --- a/contrib/llvm-project/llvm/lib/Transforms/Utils/SCCPSolver.cpp +++ b/contrib/llvm-project/llvm/lib/Transforms/Utils/SCCPSolver.cpp @@ -15,14 +15,12 @@ #include "llvm/Transforms/Utils/SCCPSolver.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/InstructionSimplify.h" -#include "llvm/Analysis/ValueTracking.h" -#include "llvm/InitializePasses.h" -#include "llvm/Pass.h" +#include "llvm/Analysis/ValueLattice.h" +#include "llvm/IR/InstVisitor.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/Utils/Local.h" #include <cassert> #include <utility> #include <vector> @@ -452,7 +450,8 @@ public: return TrackingIncomingArguments; } - void markArgInFuncSpecialization(Function *F, Argument *A, Constant *C); + void markArgInFuncSpecialization(Function *F, + const SmallVectorImpl<ArgInfo> &Args); void markFunctionUnreachable(Function *F) { for (auto &BB : *F) @@ -526,29 +525,38 @@ Constant *SCCPInstVisitor::getConstant(const ValueLatticeElement &LV) const { return nullptr; } -void SCCPInstVisitor::markArgInFuncSpecialization(Function *F, Argument *A, - Constant *C) { - assert(F->arg_size() == A->getParent()->arg_size() && +void SCCPInstVisitor::markArgInFuncSpecialization( + Function *F, const SmallVectorImpl<ArgInfo> &Args) { + assert(!Args.empty() && "Specialization without arguments"); + assert(F->arg_size() == Args[0].Formal->getParent()->arg_size() && "Functions should have the same number of arguments"); - // Mark the argument constant in the new function. - markConstant(A, C); - - // For the remaining arguments in the new function, copy the lattice state - // over from the old function. - for (auto I = F->arg_begin(), J = A->getParent()->arg_begin(), - E = F->arg_end(); - I != E; ++I, ++J) - if (J != A && ValueState.count(I)) { + auto Iter = Args.begin(); + Argument *NewArg = F->arg_begin(); + Argument *OldArg = Args[0].Formal->getParent()->arg_begin(); + for (auto End = F->arg_end(); NewArg != End; ++NewArg, ++OldArg) { + + LLVM_DEBUG(dbgs() << "SCCP: Marking argument " + << NewArg->getNameOrAsOperand() << "\n"); + + if (Iter != Args.end() && OldArg == Iter->Formal) { + // Mark the argument constants in the new function. + markConstant(NewArg, Iter->Actual); + ++Iter; + } else if (ValueState.count(OldArg)) { + // For the remaining arguments in the new function, copy the lattice state + // over from the old function. + // // Note: This previously looked like this: - // ValueState[J] = ValueState[I]; + // ValueState[NewArg] = ValueState[OldArg]; // This is incorrect because the DenseMap class may resize the underlying - // memory when inserting `J`, which will invalidate the reference to `I`. - // Instead, we make sure `J` exists, then set it to `I` afterwards. - auto &NewValue = ValueState[J]; - NewValue = ValueState[I]; - pushToWorkList(NewValue, J); + // memory when inserting `NewArg`, which will invalidate the reference to + // `OldArg`. Instead, we make sure `NewArg` exists before setting it. + auto &NewValue = ValueState[NewArg]; + NewValue = ValueState[OldArg]; + pushToWorkList(NewValue, NewArg); } + } } void SCCPInstVisitor::visitInstruction(Instruction &I) { @@ -988,7 +996,7 @@ void SCCPInstVisitor::visitBinaryOperator(Instruction &I) { if ((V1State.isConstant() || V2State.isConstant())) { Value *V1 = isConstant(V1State) ? getConstant(V1State) : I.getOperand(0); Value *V2 = isConstant(V2State) ? getConstant(V2State) : I.getOperand(1); - Value *R = SimplifyBinOp(I.getOpcode(), V1, V2, SimplifyQuery(DL)); + Value *R = simplifyBinOp(I.getOpcode(), V1, V2, SimplifyQuery(DL)); auto *C = dyn_cast_or_null<Constant>(R); if (C) { // X op Y -> undef. @@ -1287,17 +1295,6 @@ void SCCPInstVisitor::handleCallResult(CallBase &CB) { return; } - // TODO: Actually filp MayIncludeUndef for the created range to false, - // once most places in the optimizer respect the branches on - // undef/poison are UB rule. The reason why the new range cannot be - // undef is as follows below: - // The new range is based on a branch condition. That guarantees that - // neither of the compare operands can be undef in the branch targets, - // unless we have conditions that are always true/false (e.g. icmp ule - // i32, %a, i32_max). For the latter overdefined/empty range will be - // inferred, but the branch will get folded accordingly anyways. - bool MayIncludeUndef = !isa<PredicateAssume>(PI); - ValueLatticeElement CondVal = getValueState(OtherOp); ValueLatticeElement &IV = ValueState[&CB]; if (CondVal.isConstantRange() || CopyOfVal.isConstantRange()) { @@ -1322,9 +1319,15 @@ void SCCPInstVisitor::handleCallResult(CallBase &CB) { if (!CopyOfCR.contains(NewCR) && CopyOfCR.getSingleMissingElement()) NewCR = CopyOfCR; + // The new range is based on a branch condition. That guarantees that + // neither of the compare operands can be undef in the branch targets, + // unless we have conditions that are always true/false (e.g. icmp ule + // i32, %a, i32_max). For the latter overdefined/empty range will be + // inferred, but the branch will get folded accordingly anyways. addAdditionalUser(OtherOp, &CB); - mergeInValue(IV, &CB, - ValueLatticeElement::getRange(NewCR, MayIncludeUndef)); + mergeInValue( + IV, &CB, + ValueLatticeElement::getRange(NewCR, /*MayIncludeUndef*/ false)); return; } else if (Pred == CmpInst::ICMP_EQ && CondVal.isConstant()) { // For non-integer values or integer constant expressions, only @@ -1332,8 +1335,7 @@ void SCCPInstVisitor::handleCallResult(CallBase &CB) { addAdditionalUser(OtherOp, &CB); mergeInValue(IV, &CB, CondVal); return; - } else if (Pred == CmpInst::ICMP_NE && CondVal.isConstant() && - !MayIncludeUndef) { + } else if (Pred == CmpInst::ICMP_NE && CondVal.isConstant()) { // Propagate inequalities. addAdditionalUser(OtherOp, &CB); mergeInValue(IV, &CB, @@ -1442,22 +1444,19 @@ void SCCPInstVisitor::solve() { } } -/// resolvedUndefsIn - While solving the dataflow for a function, we assume -/// that branches on undef values cannot reach any of their successors. -/// However, this is not a safe assumption. After we solve dataflow, this -/// method should be use to handle this. If this returns true, the solver -/// should be rerun. +/// While solving the dataflow for a function, we don't compute a result for +/// operations with an undef operand, to allow undef to be lowered to a +/// constant later. For example, constant folding of "zext i8 undef to i16" +/// would result in "i16 0", and if undef is later lowered to "i8 1", then the +/// zext result would become "i16 1" and would result into an overdefined +/// lattice value once merged with the previous result. Not computing the +/// result of the zext (treating undef the same as unknown) allows us to handle +/// a later undef->constant lowering more optimally. /// -/// This method handles this by finding an unresolved branch and marking it one -/// of the edges from the block as being feasible, even though the condition -/// doesn't say it would otherwise be. This allows SCCP to find the rest of the -/// CFG and only slightly pessimizes the analysis results (by marking one, -/// potentially infeasible, edge feasible). This cannot usefully modify the -/// constraints on the condition of the branch, as that would impact other users -/// of the value. -/// -/// This scan also checks for values that use undefs. It conservatively marks -/// them as overdefined. +/// However, if the operand remains undef when the solver returns, we do need +/// to assign some result to the instruction (otherwise we would treat it as +/// unreachable). For simplicity, we mark any instructions that are still +/// unknown as overdefined. bool SCCPInstVisitor::resolvedUndefsIn(Function &F) { bool MadeChange = false; for (BasicBlock &BB : F) { @@ -1486,7 +1485,7 @@ bool SCCPInstVisitor::resolvedUndefsIn(Function &F) { // more precise than this but it isn't worth bothering. for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { ValueLatticeElement &LV = getStructValueState(&I, i); - if (LV.isUnknownOrUndef()) { + if (LV.isUnknown()) { markOverdefined(LV, &I); MadeChange = true; } @@ -1495,7 +1494,7 @@ bool SCCPInstVisitor::resolvedUndefsIn(Function &F) { } ValueLatticeElement &LV = getValueState(&I); - if (!LV.isUnknownOrUndef()) + if (!LV.isUnknown()) continue; // There are two reasons a call can have an undef result @@ -1518,91 +1517,6 @@ bool SCCPInstVisitor::resolvedUndefsIn(Function &F) { markOverdefined(&I); MadeChange = true; } - - // Check to see if we have a branch or switch on an undefined value. If so - // we force the branch to go one way or the other to make the successor - // values live. It doesn't really matter which way we force it. - Instruction *TI = BB.getTerminator(); - if (auto *BI = dyn_cast<BranchInst>(TI)) { - if (!BI->isConditional()) - continue; - if (!getValueState(BI->getCondition()).isUnknownOrUndef()) - continue; - - // If the input to SCCP is actually branch on undef, fix the undef to - // false. - if (isa<UndefValue>(BI->getCondition())) { - BI->setCondition(ConstantInt::getFalse(BI->getContext())); - markEdgeExecutable(&BB, TI->getSuccessor(1)); - MadeChange = true; - continue; - } - - // Otherwise, it is a branch on a symbolic value which is currently - // considered to be undef. Make sure some edge is executable, so a - // branch on "undef" always flows somewhere. - // FIXME: Distinguish between dead code and an LLVM "undef" value. - BasicBlock *DefaultSuccessor = TI->getSuccessor(1); - if (markEdgeExecutable(&BB, DefaultSuccessor)) - MadeChange = true; - - continue; - } - - if (auto *IBR = dyn_cast<IndirectBrInst>(TI)) { - // Indirect branch with no successor ?. Its ok to assume it branches - // to no target. - if (IBR->getNumSuccessors() < 1) - continue; - - if (!getValueState(IBR->getAddress()).isUnknownOrUndef()) - continue; - - // If the input to SCCP is actually branch on undef, fix the undef to - // the first successor of the indirect branch. - if (isa<UndefValue>(IBR->getAddress())) { - IBR->setAddress(BlockAddress::get(IBR->getSuccessor(0))); - markEdgeExecutable(&BB, IBR->getSuccessor(0)); - MadeChange = true; - continue; - } - - // Otherwise, it is a branch on a symbolic value which is currently - // considered to be undef. Make sure some edge is executable, so a - // branch on "undef" always flows somewhere. - // FIXME: IndirectBr on "undef" doesn't actually need to go anywhere: - // we can assume the branch has undefined behavior instead. - BasicBlock *DefaultSuccessor = IBR->getSuccessor(0); - if (markEdgeExecutable(&BB, DefaultSuccessor)) - MadeChange = true; - - continue; - } - - if (auto *SI = dyn_cast<SwitchInst>(TI)) { - if (!SI->getNumCases() || - !getValueState(SI->getCondition()).isUnknownOrUndef()) - continue; - - // If the input to SCCP is actually switch on undef, fix the undef to - // the first constant. - if (isa<UndefValue>(SI->getCondition())) { - SI->setCondition(SI->case_begin()->getCaseValue()); - markEdgeExecutable(&BB, SI->case_begin()->getCaseSuccessor()); - MadeChange = true; - continue; - } - - // Otherwise, it is a branch on a symbolic value which is currently - // considered to be undef. Make sure some edge is executable, so a - // branch on "undef" always flows somewhere. - // FIXME: Distinguish between dead code and an LLVM "undef" value. - BasicBlock *DefaultSuccessor = SI->case_begin()->getCaseSuccessor(); - if (markEdgeExecutable(&BB, DefaultSuccessor)) - MadeChange = true; - - continue; - } } return MadeChange; @@ -1618,7 +1532,7 @@ SCCPSolver::SCCPSolver( LLVMContext &Ctx) : Visitor(new SCCPInstVisitor(DL, std::move(GetTLI), Ctx)) {} -SCCPSolver::~SCCPSolver() {} +SCCPSolver::~SCCPSolver() = default; void SCCPSolver::addAnalysis(Function &F, AnalysisResultsForFn A) { return Visitor->addAnalysis(F, std::move(A)); @@ -1713,9 +1627,9 @@ SmallPtrSetImpl<Function *> &SCCPSolver::getArgumentTrackedFunctions() { return Visitor->getArgumentTrackedFunctions(); } -void SCCPSolver::markArgInFuncSpecialization(Function *F, Argument *A, - Constant *C) { - Visitor->markArgInFuncSpecialization(F, A, C); +void SCCPSolver::markArgInFuncSpecialization( + Function *F, const SmallVectorImpl<ArgInfo> &Args) { + Visitor->markArgInFuncSpecialization(F, Args); } void SCCPSolver::markFunctionUnreachable(Function *F) { |