[SCCP] Use ValueLatticeElement instead of LatticeVal (NFCI)

This patch switches SCCP to use ValueLatticeElement for lattice values,
instead of the local LatticeVal, as first step to enable integer range support.

This patch does not make use of constant ranges for additional operations
and the only difference for now is that integer constants are represented by
single element ranges. To preserve the existing behavior, the following helpers
are used

* isConstant(LV): returns true when LV is either a constant or a constant range with a single element. This should return true in the same cases where LV.isConstant() returned true previously.
* getConstant(LV): returns a constant if LV is either a constant or a constant range with a single element. This should return a constant in the same cases as LV.getConstant() previously.
* getConstantInt(LV): same as getConstant, but additionally casted to ConstantInt.

Reviewers: davide, efriedma, mssimpso

Reviewed By: efriedma

Differential Revision: https://reviews.llvm.org/D60582
This commit is contained in:
Florian Hahn 2020-03-12 11:26:07 +00:00
parent f31f22ef0f
commit f1ac5d2263
3 changed files with 165 additions and 223 deletions

View File

@ -74,91 +74,26 @@ STATISTIC(IPNumGlobalConst, "Number of globals found to be constant by IPSCCP");
namespace {
/// LatticeVal class - This class represents the different 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,
// Use ValueLatticeElement as LatticeVal.
using LatticeVal = ValueLatticeElement;
/// constant - This LLVM Value has a specific constant value.
constant,
// 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());
}
/// 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 different 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;
}
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 @@ public:
}
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 @@ public:
}
// 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 @@ private:
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 @@ private:
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 different 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,7 +1184,7 @@ void SCCPSolver::visitCallSite(CallSite CS) {
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
if (II->getIntrinsicID() == Intrinsic::ssa_copy) {
if (ValueState[I].isOverdefined())
if (isOverdefined(ValueState[I]))
return;
auto *PI = getPredicateInfoFor(I);
@ -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 @@ CallOverdefined:
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 @@ CallOverdefined:
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()) {

View File

@ -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

View File

@ -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