[llvm] 0c5b6e2 - Recommit "[SCCP] Use ValueLatticeElement instead of LatticeVal (NFCI)"
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 13 10:04:34 PDT 2020
Author: Florian Hahn
Date: 2020-03-13T17:03:22Z
New Revision: 0c5b6e2ea567ad64a21e0068df2fb65bd0d742c0
URL: https://github.com/llvm/llvm-project/commit/0c5b6e2ea567ad64a21e0068df2fb65bd0d742c0
DIFF: https://github.com/llvm/llvm-project/commit/0c5b6e2ea567ad64a21e0068df2fb65bd0d742c0.diff
LOG: Recommit "[SCCP] Use ValueLatticeElement instead of LatticeVal (NFCI)"
This patch should fix the cause of the stage2 failures and
PR45185.
This reverts the revert commit c52f839e723ee288db2a3e21860b011f6a9d707e.
Added:
llvm/test/Transforms/SCCP/pr45185-range-predinfo.ll
Modified:
llvm/lib/Transforms/Scalar/SCCP.cpp
llvm/test/Transforms/SCCP/ip-constant-ranges.ll
llvm/test/Transforms/SCCP/resolvedundefsin-tracked-fn.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp
index 2d83fa38b80f..2d65b4d5f786 100644
--- a/llvm/lib/Transforms/Scalar/SCCP.cpp
+++ b/llvm/lib/Transforms/Scalar/SCCP.cpp
@@ -74,91 +74,26 @@ STATISTIC(IPNumGlobalConst, "Number of globals found to be constant by IPSCCP");
namespace {
-/// LatticeVal class - This class represents the
diff erent lattice values that
-/// an LLVM value may occupy. It is a simple class with value semantics.
-///
-class LatticeVal {
- enum LatticeValueTy {
- /// unknown - This LLVM Value has no known value yet.
- unknown,
-
- /// constant - This LLVM Value has a specific constant value.
- constant,
-
- /// overdefined - This instruction is not known to be constant, and we know
- /// it has a value.
- overdefined
- };
-
- /// Val: This stores the current lattice value along with the Constant* for
- /// the constant if this is a 'constant' value.
- PointerIntPair<Constant *, 2, LatticeValueTy> Val;
-
- LatticeValueTy getLatticeValue() const {
- return Val.getInt();
- }
-
-public:
- LatticeVal() : Val(nullptr, unknown) {}
-
- bool isUnknown() const { return getLatticeValue() == unknown; }
-
- bool isConstant() const { return getLatticeValue() == constant; }
-
- bool isOverdefined() const { return getLatticeValue() == overdefined; }
-
- Constant *getConstant() const {
- assert(isConstant() && "Cannot get the constant of a non-constant!");
- return Val.getPointer();
- }
-
- /// markOverdefined - Return true if this is a change in status.
- bool markOverdefined() {
- if (isOverdefined())
- return false;
-
- Val.setInt(overdefined);
- return true;
- }
-
- /// markConstant - Return true if this is a change in status.
- bool markConstant(Constant *V) {
- if (getLatticeValue() == constant) { // Constant
- assert(getConstant() == V && "Marking constant with
diff erent value");
- return false;
- }
-
- assert(isUnknown());
- Val.setInt(constant);
- assert(V && "Marking constant with NULL");
- Val.setPointer(V);
- return true;
- }
-
- /// getConstantInt - If this is a constant with a ConstantInt value, return it
- /// otherwise return null.
- ConstantInt *getConstantInt() const {
- if (isConstant())
- return dyn_cast<ConstantInt>(getConstant());
- return nullptr;
- }
-
- /// getBlockAddress - If this is a constant with a BlockAddress value, return
- /// it, otherwise return null.
- BlockAddress *getBlockAddress() const {
- if (isConstant())
- return dyn_cast<BlockAddress>(getConstant());
- return nullptr;
- }
+// Use ValueLatticeElement as LatticeVal.
+using LatticeVal = ValueLatticeElement;
+
+// Helper to check if \p LV is either a constant or a constant
+// range with a single element. This should cover exactly the same cases as the
+// old LatticeVal::isConstant() and is intended to be used in the transition
+// from LatticeVal to LatticeValueElement.
+bool isConstant(const LatticeVal &LV) {
+ return LV.isConstant() ||
+ (LV.isConstantRange() && LV.getConstantRange().isSingleElement());
+}
- ValueLatticeElement toValueLattice() const {
- if (isOverdefined())
- return ValueLatticeElement::getOverdefined();
- if (isConstant())
- return ValueLatticeElement::get(getConstant());
- return ValueLatticeElement();
- }
-};
+// Helper to check if \p LV is either overdefined or a constant range with more
+// than a single element. This should cover exactly the same cases as the old
+// LatticeVal::isOverdefined() and is intended to be used in the transition from
+// LatticeVal to LatticeValueElement.
+bool isOverdefined(const LatticeVal &LV) {
+ return LV.isOverdefined() ||
+ (LV.isConstantRange() && !LV.getConstantRange().isSingleElement());
+}
//===----------------------------------------------------------------------===//
//
@@ -170,8 +105,6 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
std::function<const TargetLibraryInfo &(Function &)> GetTLI;
SmallPtrSet<BasicBlock *, 8> BBExecutable; // The BBs that are executable.
DenseMap<Value *, LatticeVal> ValueState; // The state each value is in.
- // The state each parameter is in.
- DenseMap<Value *, ValueLatticeElement> ParamState;
/// StructValueState - This maintains ValueState for values that have
/// StructType, for example for formal arguments, calls, insertelement, etc.
@@ -226,6 +159,8 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
DenseMap<Function *, AnalysisResultsForFn> AnalysisResults;
DenseMap<Value *, SmallPtrSet<User *, 2>> AdditionalUsers;
+ LLVMContext &Ctx;
+
public:
void addAnalysis(Function &F, AnalysisResultsForFn A) {
AnalysisResults.insert({&F, std::move(A)});
@@ -245,8 +180,9 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
}
SCCPSolver(const DataLayout &DL,
- std::function<const TargetLibraryInfo &(Function &)> GetTLI)
- : DL(DL), GetTLI(std::move(GetTLI)) {}
+ std::function<const TargetLibraryInfo &(Function &)> GetTLI,
+ LLVMContext &Ctx)
+ : DL(DL), GetTLI(std::move(GetTLI)), Ctx(Ctx) {}
/// MarkBlockExecutable - This method can be used by clients to mark all of
/// the blocks that are known to be intrinsically live in the processed unit.
@@ -382,23 +318,50 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
}
// isStructLatticeConstant - Return true if all the lattice values
- // corresponding to elements of the structure are not overdefined,
+ // corresponding to elements of the structure are constants,
// false otherwise.
bool isStructLatticeConstant(Function *F, StructType *STy) {
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
const auto &It = TrackedMultipleRetVals.find(std::make_pair(F, i));
assert(It != TrackedMultipleRetVals.end());
LatticeVal LV = It->second;
- if (LV.isOverdefined())
+ if (!isConstant(LV))
return false;
}
return true;
}
+ /// Helper to return a Constant if \p LV is either a constant or a constant
+ /// range with a single element.
+ Constant *getConstant(const LatticeVal &LV) const {
+ if (LV.isConstant())
+ return LV.getConstant();
+
+ if (LV.isConstantRange()) {
+ auto &CR = LV.getConstantRange();
+ if (CR.getSingleElement())
+ return ConstantInt::get(Ctx, *CR.getSingleElement());
+ }
+ return nullptr;
+ }
+
private:
+ ConstantInt *getConstantInt(const LatticeVal &IV) const {
+ return dyn_cast_or_null<ConstantInt>(getConstant(IV));
+ }
+
// pushToWorkList - Helper for markConstant/markOverdefined
void pushToWorkList(LatticeVal &IV, Value *V) {
- if (IV.isOverdefined())
+ if (isOverdefined(IV))
+ return OverdefinedInstWorkList.push_back(V);
+ InstWorkList.push_back(V);
+ }
+
+ // Helper to push \p V to the worklist, after updating it to \p IV. Also
+ // prints a debug message with the updated value.
+ void pushToWorkListMsg(LatticeVal &IV, Value *V) {
+ LLVM_DEBUG(dbgs() << "updated " << IV << ": " << *V << '\n');
+ if (isOverdefined(IV))
return OverdefinedInstWorkList.push_back(V);
InstWorkList.push_back(V);
}
@@ -433,22 +396,29 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
return true;
}
- bool mergeInValue(LatticeVal &IV, Value *V, LatticeVal MergeWithV) {
- if (IV.isOverdefined() || MergeWithV.isUnknown())
- return false; // Noop.
- if (MergeWithV.isOverdefined())
- return markOverdefined(IV, V);
- if (IV.isUnknown())
- return markConstant(IV, V, MergeWithV.getConstant());
- if (IV.getConstant() != MergeWithV.getConstant())
- return markOverdefined(IV, V);
+ bool mergeInValue(LatticeVal &IV, Value *V, LatticeVal MergeWithV,
+ bool Widen = true) {
+ // Do a simple form of widening, to avoid extending a range repeatedly in a
+ // loop. If IV is a constant range, it means we already set it once. If
+ // MergeWithV would extend IV, mark V as overdefined.
+ if (Widen && IV.isConstantRange() && MergeWithV.isConstantRange() &&
+ !IV.getConstantRange().contains(MergeWithV.getConstantRange())) {
+ markOverdefined(IV, V);
+ return true;
+ }
+ if (IV.mergeIn(MergeWithV, DL)) {
+ pushToWorkList(IV, V);
+ LLVM_DEBUG(dbgs() << "Merged " << MergeWithV << " into " << *V << " : "
+ << IV << "\n");
+ return true;
+ }
return false;
}
- bool mergeInValue(Value *V, LatticeVal MergeWithV) {
+ bool mergeInValue(Value *V, LatticeVal MergeWithV, bool Widen = true) {
assert(!V->getType()->isStructTy() &&
"non-structs should use markConstant");
- return mergeInValue(ValueState[V], V, MergeWithV);
+ return mergeInValue(ValueState[V], V, MergeWithV, Widen);
}
/// getValueState - Return the LatticeVal object that corresponds to the
@@ -492,18 +462,6 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
return Res;
}
- ValueLatticeElement &getParamState(Value *V) {
- assert(!V->getType()->isStructTy() && "Should use getStructValueState");
-
- std::pair<DenseMap<Value*, ValueLatticeElement>::iterator, bool>
- PI = ParamState.insert(std::make_pair(V, ValueLatticeElement()));
- ValueLatticeElement &LV = PI.first->second;
- if (PI.second)
- LV = getValueState(V).toValueLattice();
-
- return LV;
- }
-
/// getStructValueState - Return the LatticeVal object that corresponds to the
/// value/field pair. This function handles the case when the value hasn't
/// been seen yet by properly seeding constants etc.
@@ -659,7 +617,7 @@ void SCCPSolver::getFeasibleSuccessors(Instruction &TI,
}
LatticeVal BCValue = getValueState(BI->getCondition());
- ConstantInt *CI = BCValue.getConstantInt();
+ ConstantInt *CI = getConstantInt(BCValue);
if (!CI) {
// Overdefined condition variables, and branches on unfoldable constant
// conditions, mean the branch could go either way.
@@ -685,7 +643,7 @@ void SCCPSolver::getFeasibleSuccessors(Instruction &TI,
return;
}
LatticeVal SCValue = getValueState(SI->getCondition());
- ConstantInt *CI = SCValue.getConstantInt();
+ ConstantInt *CI = getConstantInt(SCValue);
if (!CI) { // Overdefined or unknown condition?
// All destinations are executable!
@@ -703,7 +661,7 @@ void SCCPSolver::getFeasibleSuccessors(Instruction &TI,
if (auto *IBR = dyn_cast<IndirectBrInst>(&TI)) {
// Casts are folded by visitCastInst.
LatticeVal IBRValue = getValueState(IBR->getAddress());
- BlockAddress *Addr = IBRValue.getBlockAddress();
+ BlockAddress *Addr = dyn_cast_or_null<BlockAddress>(getConstant(IBRValue));
if (!Addr) { // Overdefined or unknown condition?
// All destinations are executable!
if (!IBRValue.isUnknown())
@@ -770,8 +728,9 @@ void SCCPSolver::visitPHINode(PHINode &PN) {
if (PN.getType()->isStructTy())
return (void)markOverdefined(&PN);
- if (getValueState(&PN).isOverdefined())
- return; // Quick exit
+ if (isOverdefined(getValueState(&PN))) {
+ return (void)markOverdefined(&PN);
+ }
// Super-extra-high-degree PHI nodes are unlikely to ever be marked constant,
// and slow us down a lot. Just mark them overdefined.
@@ -791,11 +750,11 @@ void SCCPSolver::visitPHINode(PHINode &PN) {
if (!isEdgeFeasible(PN.getIncomingBlock(i), PN.getParent()))
continue;
- if (IV.isOverdefined()) // PHI node becomes overdefined!
+ if (isOverdefined(IV)) // PHI node becomes overdefined!
return (void)markOverdefined(&PN);
if (!OperandVal) { // Grab the first value.
- OperandVal = IV.getConstant();
+ OperandVal = getConstant(IV);
continue;
}
@@ -805,7 +764,7 @@ void SCCPSolver::visitPHINode(PHINode &PN) {
// Check to see if there are two
diff erent constants merging, if so, the PHI
// node is overdefined.
- if (IV.getConstant() != OperandVal)
+ if (getConstant(IV) != OperandVal)
return (void)markOverdefined(&PN);
}
@@ -822,7 +781,7 @@ void SCCPSolver::visitReturnInst(ReturnInst &I) {
// ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
// discover a concrete value later.
- if (ValueState[&I].isOverdefined())
+ if (isOverdefined(ValueState[&I]))
return;
Function *F = I.getParent()->getParent();
@@ -863,27 +822,25 @@ void SCCPSolver::visitTerminator(Instruction &TI) {
void SCCPSolver::visitCastInst(CastInst &I) {
// ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
// discover a concrete value later.
- if (ValueState[&I].isOverdefined())
+ if (isOverdefined(ValueState[&I]))
return;
LatticeVal OpSt = getValueState(I.getOperand(0));
- if (OpSt.isOverdefined()) // Inherit overdefinedness of operand
- markOverdefined(&I);
- else if (OpSt.isConstant()) {
+ if (Constant *OpC = getConstant(OpSt)) {
// Fold the constant as we build.
- Constant *C = ConstantFoldCastOperand(I.getOpcode(), OpSt.getConstant(),
- I.getType(), DL);
+ Constant *C = ConstantFoldCastOperand(I.getOpcode(), OpC, I.getType(), DL);
if (isa<UndefValue>(C))
return;
// Propagate constant value
markConstant(&I, C);
- }
+ } else if (!OpSt.isUnknown())
+ markOverdefined(&I);
}
void SCCPSolver::visitExtractValueInst(ExtractValueInst &EVI) {
// ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
// discover a concrete value later.
- if (ValueState[&EVI].isOverdefined())
+ if (isOverdefined(ValueState[&EVI]))
return;
// If this returns a struct, mark all elements over defined, we don't track
@@ -913,7 +870,7 @@ void SCCPSolver::visitInsertValueInst(InsertValueInst &IVI) {
// ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
// discover a concrete value later.
- if (ValueState[&IVI].isOverdefined())
+ if (isOverdefined(ValueState[&IVI]))
return;
// If this has more than one index, we can't handle it, drive all results to
@@ -952,14 +909,14 @@ void SCCPSolver::visitSelectInst(SelectInst &I) {
// ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
// discover a concrete value later.
- if (ValueState[&I].isOverdefined())
+ if (isOverdefined(ValueState[&I]))
return;
LatticeVal CondValue = getValueState(I.getCondition());
if (CondValue.isUnknown())
return;
- if (ConstantInt *CondCB = CondValue.getConstantInt()) {
+ if (ConstantInt *CondCB = getConstantInt(CondValue)) {
Value *OpVal = CondCB->isZero() ? I.getFalseValue() : I.getTrueValue();
mergeInValue(&I, getValueState(OpVal));
return;
@@ -972,9 +929,9 @@ void SCCPSolver::visitSelectInst(SelectInst &I) {
LatticeVal FVal = getValueState(I.getFalseValue());
// select ?, C, C -> C.
- if (TVal.isConstant() && FVal.isConstant() &&
- TVal.getConstant() == FVal.getConstant())
- return (void)markConstant(&I, FVal.getConstant());
+ if (isConstant(TVal) && isConstant(FVal) &&
+ getConstant(TVal) == getConstant(FVal))
+ return (void)markConstant(&I, getConstant(FVal));
if (TVal.isUnknown()) // select ?, undef, X -> X.
return (void)mergeInValue(&I, FVal);
@@ -990,10 +947,10 @@ void SCCPSolver::visitUnaryOperator(Instruction &I) {
LatticeVal &IV = ValueState[&I];
// ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
// discover a concrete value later.
- if (IV.isOverdefined()) return;
+ if (isOverdefined(IV)) return;
- if (V0State.isConstant()) {
- Constant *C = ConstantExpr::get(I.getOpcode(), V0State.getConstant());
+ if (isConstant(V0State)) {
+ Constant *C = ConstantExpr::get(I.getOpcode(), getConstant(V0State));
// op Y -> undef.
if (isa<UndefValue>(C))
@@ -1002,7 +959,7 @@ void SCCPSolver::visitUnaryOperator(Instruction &I) {
}
// If something is undef, wait for it to resolve.
- if (!V0State.isOverdefined())
+ if (!isOverdefined(V0State))
return;
markOverdefined(&I);
@@ -1014,11 +971,14 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
LatticeVal V2State = getValueState(I.getOperand(1));
LatticeVal &IV = ValueState[&I];
- if (IV.isOverdefined()) return;
+ if (isOverdefined(IV)) {
+ markOverdefined(&I);
+ return;
+ }
- if (V1State.isConstant() && V2State.isConstant()) {
- Constant *C = ConstantExpr::get(I.getOpcode(), V1State.getConstant(),
- V2State.getConstant());
+ if (isConstant(V1State) && isConstant(V2State)) {
+ Constant *C = ConstantExpr::get(I.getOpcode(), getConstant(V1State),
+ getConstant(V2State));
// X op Y -> undef.
if (isa<UndefValue>(C))
return;
@@ -1026,18 +986,16 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
}
// If something is undef, wait for it to resolve.
- if (!V1State.isOverdefined() && !V2State.isOverdefined()) {
-
+ if (V1State.isUnknown() || V2State.isUnknown())
return;
- }
// Otherwise, one of our operands is overdefined. Try to produce something
// better than overdefined with some tricks.
// If this is 0 / Y, it doesn't matter that the second operand is
// overdefined, and we can replace it with zero.
if (I.getOpcode() == Instruction::UDiv || I.getOpcode() == Instruction::SDiv)
- if (V1State.isConstant() && V1State.getConstant()->isNullValue())
- return (void)markConstant(IV, &I, V1State.getConstant());
+ if (isConstant(V1State) && getConstant(V1State)->isNullValue())
+ return (void)markConstant(IV, &I, getConstant(V1State));
// If this is:
// -> AND/MUL with 0
@@ -1046,9 +1004,10 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
if (I.getOpcode() == Instruction::And || I.getOpcode() == Instruction::Mul ||
I.getOpcode() == Instruction::Or) {
LatticeVal *NonOverdefVal = nullptr;
- if (!V1State.isOverdefined())
+ if (!isOverdefined(V1State))
NonOverdefVal = &V1State;
- else if (!V2State.isOverdefined())
+
+ else if (!isOverdefined(V2State))
NonOverdefVal = &V2State;
if (NonOverdefVal) {
if (NonOverdefVal->isUnknown())
@@ -1058,13 +1017,13 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
I.getOpcode() == Instruction::Mul) {
// X and 0 = 0
// X * 0 = 0
- if (NonOverdefVal->getConstant()->isNullValue())
- return (void)markConstant(IV, &I, NonOverdefVal->getConstant());
+ if (getConstant(*NonOverdefVal)->isNullValue())
+ return (void)markConstant(IV, &I, getConstant(*NonOverdefVal));
} else {
// X or -1 = -1
- if (ConstantInt *CI = NonOverdefVal->getConstantInt())
+ if (ConstantInt *CI = getConstantInt(*NonOverdefVal))
if (CI->isMinusOne())
- return (void)markConstant(IV, &I, NonOverdefVal->getConstant());
+ return (void)markConstant(IV, &I, CI);
}
}
}
@@ -1076,22 +1035,18 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
void SCCPSolver::visitCmpInst(CmpInst &I) {
// Do not cache this lookup, getValueState calls later in the function might
// invalidate the reference.
- if (ValueState[&I].isOverdefined()) return;
+ if (isOverdefined(ValueState[&I])) {
+ markOverdefined(&I);
+ return;
+ }
Value *Op1 = I.getOperand(0);
Value *Op2 = I.getOperand(1);
// For parameters, use ParamState which includes constant range info if
// available.
- auto V1Param = ParamState.find(Op1);
- ValueLatticeElement V1State = (V1Param != ParamState.end())
- ? V1Param->second
- : getValueState(Op1).toValueLattice();
-
- auto V2Param = ParamState.find(Op2);
- ValueLatticeElement V2State = V2Param != ParamState.end()
- ? V2Param->second
- : getValueState(Op2).toValueLattice();
+ auto V1State = getValueState(Op1);
+ auto V2State = getValueState(Op2);
Constant *C = V1State.getCompare(I.getPredicate(), I.getType(), V2State);
if (C) {
@@ -1104,8 +1059,8 @@ void SCCPSolver::visitCmpInst(CmpInst &I) {
}
// If operands are still unknown, wait for it to resolve.
- if (!V1State.isOverdefined() && !V2State.isOverdefined() &&
- !ValueState[&I].isConstant())
+ if ((V1State.isUnknown() || V2State.isUnknown()) &&
+ !isConstant(ValueState[&I]))
return;
markOverdefined(&I);
@@ -1114,7 +1069,7 @@ void SCCPSolver::visitCmpInst(CmpInst &I) {
// Handle getelementptr instructions. If all operands are constants then we
// can turn this into a getelementptr ConstantExpr.
void SCCPSolver::visitGetElementPtrInst(GetElementPtrInst &I) {
- if (ValueState[&I].isOverdefined()) return;
+ if (isOverdefined(ValueState[&I])) return;
SmallVector<Constant*, 8> Operands;
Operands.reserve(I.getNumOperands());
@@ -1124,11 +1079,15 @@ void SCCPSolver::visitGetElementPtrInst(GetElementPtrInst &I) {
if (State.isUnknown())
return; // Operands are not resolved yet.
- if (State.isOverdefined())
+ if (isOverdefined(State))
return (void)markOverdefined(&I);
- assert(State.isConstant() && "Unknown state!");
- Operands.push_back(State.getConstant());
+ if (Constant *C = getConstant(State)) {
+ Operands.push_back(C);
+ continue;
+ }
+
+ return (void)markOverdefined(&I);
}
Constant *Ptr = Operands[0];
@@ -1150,16 +1109,17 @@ void SCCPSolver::visitStoreInst(StoreInst &SI) {
// ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
// discover a concrete value later.
- if (ValueState[&SI].isOverdefined())
+ if (isOverdefined(ValueState[&SI]))
return;
GlobalVariable *GV = cast<GlobalVariable>(SI.getOperand(1));
DenseMap<GlobalVariable*, LatticeVal>::iterator I = TrackedGlobals.find(GV);
- if (I == TrackedGlobals.end() || I->second.isOverdefined()) return;
+ if (I == TrackedGlobals.end())
+ return;
// Get the value we are storing into the global, then merge it.
mergeInValue(I->second, GV, getValueState(SI.getOperand(0)));
- if (I->second.isOverdefined())
+ if (isOverdefined(I->second))
TrackedGlobals.erase(I); // No need to keep tracking this!
}
@@ -1172,7 +1132,7 @@ void SCCPSolver::visitLoadInst(LoadInst &I) {
// ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
// discover a concrete value later.
- if (ValueState[&I].isOverdefined())
+ if (isOverdefined(ValueState[&I]))
return;
LatticeVal PtrVal = getValueState(I.getOperand(0));
@@ -1180,10 +1140,10 @@ void SCCPSolver::visitLoadInst(LoadInst &I) {
LatticeVal &IV = ValueState[&I];
- if (!PtrVal.isConstant() || I.isVolatile())
+ if (!isConstant(PtrVal) || I.isVolatile())
return (void)markOverdefined(IV, &I);
- Constant *Ptr = PtrVal.getConstant();
+ Constant *Ptr = getConstant(PtrVal);
// load null is undefined.
if (isa<ConstantPointerNull>(Ptr)) {
@@ -1224,8 +1184,8 @@ void SCCPSolver::visitCallSite(CallSite CS) {
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
if (II->getIntrinsicID() == Intrinsic::ssa_copy) {
- if (ValueState[I].isOverdefined())
- return;
+ if (isOverdefined(ValueState[I]))
+ return (void)markOverdefined(I);
auto *PI = getPredicateInfoFor(I);
if (!PI)
@@ -1262,7 +1222,7 @@ void SCCPSolver::visitCallSite(CallSite CS) {
LatticeVal &IV = ValueState[I];
if (PBranch->TrueEdge && Cmp->getPredicate() == CmpInst::ICMP_EQ) {
addAdditionalUser(CmpOp1, I);
- if (OriginalVal.isConstant())
+ if (isConstant(OriginalVal))
mergeInValue(IV, I, OriginalVal);
else
mergeInValue(IV, I, EqVal);
@@ -1270,7 +1230,7 @@ void SCCPSolver::visitCallSite(CallSite CS) {
}
if (!PBranch->TrueEdge && Cmp->getPredicate() == CmpInst::ICMP_NE) {
addAdditionalUser(CmpOp1, I);
- if (OriginalVal.isConstant())
+ if (isConstant(OriginalVal))
mergeInValue(IV, I, OriginalVal);
else
mergeInValue(IV, I, EqVal);
@@ -1302,13 +1262,13 @@ void SCCPSolver::visitCallSite(CallSite CS) {
if (State.isUnknown())
return; // Operands are not resolved yet.
- if (State.isOverdefined())
+ if (isOverdefined(State))
return (void)markOverdefined(I);
- assert(State.isConstant() && "Unknown state!");
- Operands.push_back(State.getConstant());
+ assert(isConstant(State) && "Unknown state!");
+ Operands.push_back(getConstant(State));
}
- if (getValueState(I).isOverdefined())
+ if (isOverdefined(getValueState(I)))
return;
// If we can constant fold this, mark the result of the call as a
@@ -1346,24 +1306,10 @@ void SCCPSolver::visitCallSite(CallSite CS) {
if (auto *STy = dyn_cast<StructType>(AI->getType())) {
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
LatticeVal CallArg = getStructValueState(*CAI, i);
- mergeInValue(getStructValueState(&*AI, i), &*AI, CallArg);
+ mergeInValue(getStructValueState(&*AI, i), &*AI, CallArg, false);
}
- } else {
- // Most other parts of the Solver still only use the simpler value
- // lattice, so we propagate changes for parameters to both lattices.
- ValueLatticeElement ConcreteArgument =
- isa<Argument>(*CAI) ? getParamState(*CAI)
- : getValueState(*CAI).toValueLattice();
- bool ParamChanged = getParamState(&*AI).mergeIn(ConcreteArgument, DL);
- bool ValueChanged =
- mergeInValue(&*AI, toLatticeVal(ConcreteArgument, AI->getType()));
- // Add argument to work list, if the state of a parameter changes but
- // ValueState does not change (because it is already overdefined there),
- // We have to take changes in ParamState into account, as it is used
- // when evaluating Cmp instructions.
- if (!ValueChanged && ParamChanged)
- pushToWorkList(ValueState[&*AI], &*AI);
- }
+ } else
+ mergeInValue(&*AI, getValueState(*CAI), false);
}
}
@@ -1421,7 +1367,7 @@ void SCCPSolver::Solve() {
// since all of its users will have already been marked as overdefined.
// Update all of the users of this instruction's value.
//
- if (I->getType()->isStructTy() || !getValueState(I).isOverdefined())
+ if (I->getType()->isStructTy() || !isOverdefined(getValueState(I)))
markUsersAsChanged(I);
}
@@ -1600,24 +1546,24 @@ static bool tryToReplaceWithConstant(SCCPSolver &Solver, Value *V) {
Constant *Const = nullptr;
if (V->getType()->isStructTy()) {
std::vector<LatticeVal> IVs = Solver.getStructLatticeValueFor(V);
- if (llvm::any_of(IVs,
- [](const LatticeVal &LV) { return LV.isOverdefined(); }))
+ if (any_of(IVs, [](const LatticeVal &LV) { return isOverdefined(LV); }))
return false;
std::vector<Constant *> ConstVals;
auto *ST = cast<StructType>(V->getType());
for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i) {
LatticeVal V = IVs[i];
- ConstVals.push_back(V.isConstant()
- ? V.getConstant()
+ ConstVals.push_back(isConstant(V)
+ ? Solver.getConstant(V)
: UndefValue::get(ST->getElementType(i)));
}
Const = ConstantStruct::get(ST, ConstVals);
} else {
const LatticeVal &IV = Solver.getLatticeValueFor(V);
- if (IV.isOverdefined())
+ if (isOverdefined(IV))
return false;
- Const = IV.isConstant() ? IV.getConstant() : UndefValue::get(V->getType());
+ Const =
+ isConstant(IV) ? Solver.getConstant(IV) : UndefValue::get(V->getType());
}
assert(Const && "Constant is nullptr here!");
@@ -1650,7 +1596,8 @@ static bool runSCCP(Function &F, const DataLayout &DL,
const TargetLibraryInfo *TLI) {
LLVM_DEBUG(dbgs() << "SCCP on function '" << F.getName() << "'\n");
SCCPSolver Solver(
- DL, [TLI](Function &F) -> const TargetLibraryInfo & { return *TLI; });
+ DL, [TLI](Function &F) -> const TargetLibraryInfo & { return *TLI; },
+ F.getContext());
// Mark the first block of the function as being executable.
Solver.MarkBlockExecutable(&F.front());
@@ -1793,9 +1740,9 @@ static void findReturnsToZap(Function &F,
if (U->getType()->isStructTy()) {
return all_of(
Solver.getStructLatticeValueFor(U),
- [](const LatticeVal &LV) { return !LV.isOverdefined(); });
+ [](const LatticeVal &LV) { return !isOverdefined(LV); });
}
- return !Solver.getLatticeValueFor(U).isOverdefined();
+ return !isOverdefined(Solver.getLatticeValueFor(U));
}) &&
"We can only zap functions where all live users have a concrete value");
@@ -1852,7 +1799,7 @@ bool llvm::runIPSCCP(
Module &M, const DataLayout &DL,
std::function<const TargetLibraryInfo &(Function &)> GetTLI,
function_ref<AnalysisResultsForFn(Function &)> getAnalysis) {
- SCCPSolver Solver(DL, GetTLI);
+ SCCPSolver Solver(DL, GetTLI, M.getContext());
// Loop over all functions, marking arguments to those with their addresses
// taken or that are external as overdefined.
@@ -2038,7 +1985,7 @@ bool llvm::runIPSCCP(
const MapVector<Function*, LatticeVal> &RV = Solver.getTrackedRetVals();
for (const auto &I : RV) {
Function *F = I.first;
- if (I.second.isOverdefined() || F->getReturnType()->isVoidTy())
+ if (isOverdefined(I.second) || F->getReturnType()->isVoidTy())
continue;
findReturnsToZap(*F, ReturnsToZap, Solver);
}
@@ -2063,8 +2010,8 @@ bool llvm::runIPSCCP(
for (DenseMap<GlobalVariable*, LatticeVal>::const_iterator I = TG.begin(),
E = TG.end(); I != E; ++I) {
GlobalVariable *GV = I->first;
- assert(!I->second.isOverdefined() &&
- "Overdefined values should have been taken out of the map!");
+ if (isOverdefined(I->second))
+ continue;
LLVM_DEBUG(dbgs() << "Found that GV '" << GV->getName()
<< "' is constant!\n");
while (!GV->use_empty()) {
diff --git a/llvm/test/Transforms/SCCP/ip-constant-ranges.ll b/llvm/test/Transforms/SCCP/ip-constant-ranges.ll
index 08de8dba4046..dbaedaa739bf 100644
--- a/llvm/test/Transforms/SCCP/ip-constant-ranges.ll
+++ b/llvm/test/Transforms/SCCP/ip-constant-ranges.ll
@@ -230,7 +230,7 @@ define i32 @caller6() {
; CHECK-NEXT: %call.1 = call i32 @callee6.1(i32 30)
; CHECK-NEXT: %call.2 = call i32 @callee6.1(i32 43)
; CHECK-NEXT: ret i32 2
-
+;
%call.1 = call i32 @callee6.1(i32 30)
%call.2 = call i32 @callee6.1(i32 43)
%res = add i32 %call.1, %call.2
diff --git a/llvm/test/Transforms/SCCP/pr45185-range-predinfo.ll b/llvm/test/Transforms/SCCP/pr45185-range-predinfo.ll
new file mode 100644
index 000000000000..b264ca0558ca
--- /dev/null
+++ b/llvm/test/Transforms/SCCP/pr45185-range-predinfo.ll
@@ -0,0 +1,59 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -ipsccp -S %s | FileCheck %s
+
+;Test for PR45185.
+
+define void @spam([4 x [24 x float]]* %arg) {
+; CHECK-LABEL: @spam(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[TMP:%.*]] = getelementptr inbounds [4 x [24 x float]], [4 x [24 x float]]* [[ARG:%.*]], i64 0, i64 0, i64 0
+; CHECK-NEXT: call void @blam(i32 0, float* nonnull [[TMP]])
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [4 x [24 x float]], [4 x [24 x float]]* [[ARG]], i64 0, i64 1, i64 0
+; CHECK-NEXT: call void @blam(i32 1, float* nonnull [[TMP1]])
+; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds [4 x [24 x float]], [4 x [24 x float]]* [[ARG]], i64 0, i64 2, i64 0
+; CHECK-NEXT: call void @blam(i32 2, float* nonnull [[TMP2]])
+; CHECK-NEXT: ret void
+;
+bb:
+ %tmp = getelementptr inbounds [4 x [24 x float]], [4 x [24 x float]]* %arg, i64 0, i64 0, i64 0
+ call void @blam(i32 0, float* nonnull %tmp)
+ %tmp1 = getelementptr inbounds [4 x [24 x float]], [4 x [24 x float]]* %arg, i64 0, i64 1, i64 0
+ call void @blam(i32 1, float* nonnull %tmp1)
+ %tmp2 = getelementptr inbounds [4 x [24 x float]], [4 x [24 x float]]* %arg, i64 0, i64 2, i64 0
+ call void @blam(i32 2, float* nonnull %tmp2)
+ ret void
+}
+
+; Make sure we do not incorrectly eliminate the checks in @blam.
+define internal void @blam(i32 %arg, float* nocapture %arg1) {
+; CHECK-LABEL: define {{.*}} @blam(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[TMP:%.*]] = icmp eq i32 [[ARG:%.*]], 0
+; CHECK-NEXT: br i1 [[TMP]], label [[BB2:%.*]], label [[BB3:%.*]]
+; CHECK: bb2:
+; CHECK-NEXT: br label [[BB5:%.*]]
+; CHECK: bb3:
+; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[ARG]], 2
+; CHECK-NEXT: br i1 [[TMP4]], label [[BB5]], label [[BB6:%.*]]
+; CHECK: bb5:
+; CHECK-NEXT: ret void
+; CHECK: bb6:
+; CHECK-NEXT: ret void
+;
+bb:
+ %tmp = icmp eq i32 %arg, 0
+ br i1 %tmp, label %bb2, label %bb3
+
+bb2: ; preds = %bb
+ br label %bb5
+
+bb3: ; preds = %bb
+ %tmp4 = icmp eq i32 %arg, 2
+ br i1 %tmp4, label %bb5, label %bb6
+
+bb5: ; preds = %bb3, %bb2
+ ret void
+
+bb6: ; preds = %bb3
+ ret void
+}
diff --git a/llvm/test/Transforms/SCCP/resolvedundefsin-tracked-fn.ll b/llvm/test/Transforms/SCCP/resolvedundefsin-tracked-fn.ll
index 0fa465d09fd5..d56c91061cad 100644
--- a/llvm/test/Transforms/SCCP/resolvedundefsin-tracked-fn.ll
+++ b/llvm/test/Transforms/SCCP/resolvedundefsin-tracked-fn.ll
@@ -40,9 +40,7 @@ define internal i32 @test1_k(i8 %h, i32 %i) {
; CHECK-NEXT: [[CONV:%.*]] = sext i32 [[TMP0]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = inttoptr i64 [[CONV]] to %t1*
; CHECK-NEXT: [[CALL:%.*]] = call i1 @test1_g(%t1* [[TMP1]], i32 0)
-; CHECK-NEXT: [[FROMBOOL_1:%.*]] = zext i1 false to i8
-; CHECK-NEXT: [[TOBOOL_1:%.*]] = trunc i8 [[FROMBOOL_1]] to i1
-; CHECK-NEXT: call void @use.1(i1 [[TOBOOL_1]])
+; CHECK-NEXT: call void @use.1(i1 false)
; CHECK-NEXT: ret i32 undef
;
entry:
@@ -119,9 +117,7 @@ define internal i32 @test2_k(i8 %h, i32 %i) {
; CHECK-NEXT: [[CONV:%.*]] = sext i32 [[TMP0]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = inttoptr i64 [[CONV]] to %t1*
; CHECK-NEXT: [[CALL:%.*]] = call i1 @test3_g(%t1* [[TMP1]], i32 0)
-; CHECK-NEXT: [[FROMBOOL:%.*]] = icmp slt i1 false, true
-; CHECK-NEXT: [[ADD:%.*]] = add i1 [[FROMBOOL]], [[FROMBOOL]]
-; CHECK-NEXT: call void @use.1(i1 [[FROMBOOL]])
+; CHECK-NEXT: call void @use.1(i1 false)
; CHECK-NEXT: ret i32 undef
;
entry:
@@ -393,7 +389,6 @@ define void @test3() {
; CHECK-NEXT: [[CMP25474:%.*]] = icmp sgt i32 [[TMP2]], 0
; CHECK-NEXT: br i1 [[CMP25474]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
; CHECK: for.body:
-; CHECK-NEXT: [[DIV30:%.*]] = sdiv i32 0, [[SUB19]]
; CHECK-NEXT: ret void
; CHECK: for.end:
; CHECK-NEXT: ret void
More information about the llvm-commits
mailing list