mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-18 18:42:46 +02:00
Revert "[SCCP] Use ValueLatticeElement instead of LatticeVal (NFCI)"
This commit is likely causing clang-with-lto-ubuntu to fail http://lab.llvm.org:8011/builders/clang-with-lto-ubuntu/builds/16052 Also causes PR45185. This reverts commit f1ac5d2263f8419b865cc78ba1f5c8694970fb6b.
This commit is contained in:
parent
8e802d9c40
commit
f18b2707d7
@ -74,26 +74,91 @@ STATISTIC(IPNumGlobalConst, "Number of globals found to be constant by IPSCCP");
|
||||
|
||||
namespace {
|
||||
|
||||
// Use ValueLatticeElement as LatticeVal.
|
||||
using LatticeVal = ValueLatticeElement;
|
||||
/// 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,
|
||||
|
||||
// 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());
|
||||
}
|
||||
/// constant - This LLVM Value has a specific constant value.
|
||||
constant,
|
||||
|
||||
// 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());
|
||||
}
|
||||
/// 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();
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@ -105,6 +170,8 @@ 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.
|
||||
@ -159,8 +226,6 @@ 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)});
|
||||
@ -180,9 +245,8 @@ public:
|
||||
}
|
||||
|
||||
SCCPSolver(const DataLayout &DL,
|
||||
std::function<const TargetLibraryInfo &(Function &)> GetTLI,
|
||||
LLVMContext &Ctx)
|
||||
: DL(DL), GetTLI(std::move(GetTLI)), Ctx(Ctx) {}
|
||||
std::function<const TargetLibraryInfo &(Function &)> GetTLI)
|
||||
: DL(DL), GetTLI(std::move(GetTLI)) {}
|
||||
|
||||
/// 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.
|
||||
@ -318,50 +382,23 @@ public:
|
||||
}
|
||||
|
||||
// isStructLatticeConstant - Return true if all the lattice values
|
||||
// corresponding to elements of the structure are constants,
|
||||
// corresponding to elements of the structure are not overdefined,
|
||||
// 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 (!isConstant(LV))
|
||||
if (LV.isOverdefined())
|
||||
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 (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))
|
||||
if (IV.isOverdefined())
|
||||
return OverdefinedInstWorkList.push_back(V);
|
||||
InstWorkList.push_back(V);
|
||||
}
|
||||
@ -396,29 +433,22 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mergeInValue(Value *V, LatticeVal MergeWithV, bool Widen = true) {
|
||||
bool mergeInValue(Value *V, LatticeVal MergeWithV) {
|
||||
assert(!V->getType()->isStructTy() &&
|
||||
"non-structs should use markConstant");
|
||||
return mergeInValue(ValueState[V], V, MergeWithV, Widen);
|
||||
return mergeInValue(ValueState[V], V, MergeWithV);
|
||||
}
|
||||
|
||||
/// getValueState - Return the LatticeVal object that corresponds to the
|
||||
@ -462,6 +492,18 @@ 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.
|
||||
@ -617,7 +659,7 @@ void SCCPSolver::getFeasibleSuccessors(Instruction &TI,
|
||||
}
|
||||
|
||||
LatticeVal BCValue = getValueState(BI->getCondition());
|
||||
ConstantInt *CI = getConstantInt(BCValue);
|
||||
ConstantInt *CI = BCValue.getConstantInt();
|
||||
if (!CI) {
|
||||
// Overdefined condition variables, and branches on unfoldable constant
|
||||
// conditions, mean the branch could go either way.
|
||||
@ -643,7 +685,7 @@ void SCCPSolver::getFeasibleSuccessors(Instruction &TI,
|
||||
return;
|
||||
}
|
||||
LatticeVal SCValue = getValueState(SI->getCondition());
|
||||
ConstantInt *CI = getConstantInt(SCValue);
|
||||
ConstantInt *CI = SCValue.getConstantInt();
|
||||
|
||||
if (!CI) { // Overdefined or unknown condition?
|
||||
// All destinations are executable!
|
||||
@ -661,7 +703,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 = dyn_cast_or_null<BlockAddress>(getConstant(IBRValue));
|
||||
BlockAddress *Addr = IBRValue.getBlockAddress();
|
||||
if (!Addr) { // Overdefined or unknown condition?
|
||||
// All destinations are executable!
|
||||
if (!IBRValue.isUnknown())
|
||||
@ -728,9 +770,8 @@ void SCCPSolver::visitPHINode(PHINode &PN) {
|
||||
if (PN.getType()->isStructTy())
|
||||
return (void)markOverdefined(&PN);
|
||||
|
||||
if (isOverdefined(getValueState(&PN))) {
|
||||
return (void)markOverdefined(&PN);
|
||||
}
|
||||
if (getValueState(&PN).isOverdefined())
|
||||
return; // Quick exit
|
||||
|
||||
// Super-extra-high-degree PHI nodes are unlikely to ever be marked constant,
|
||||
// and slow us down a lot. Just mark them overdefined.
|
||||
@ -750,11 +791,11 @@ void SCCPSolver::visitPHINode(PHINode &PN) {
|
||||
if (!isEdgeFeasible(PN.getIncomingBlock(i), PN.getParent()))
|
||||
continue;
|
||||
|
||||
if (isOverdefined(IV)) // PHI node becomes overdefined!
|
||||
if (IV.isOverdefined()) // PHI node becomes overdefined!
|
||||
return (void)markOverdefined(&PN);
|
||||
|
||||
if (!OperandVal) { // Grab the first value.
|
||||
OperandVal = getConstant(IV);
|
||||
OperandVal = IV.getConstant();
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -764,7 +805,7 @@ void SCCPSolver::visitPHINode(PHINode &PN) {
|
||||
|
||||
// Check to see if there are two different constants merging, if so, the PHI
|
||||
// node is overdefined.
|
||||
if (getConstant(IV) != OperandVal)
|
||||
if (IV.getConstant() != OperandVal)
|
||||
return (void)markOverdefined(&PN);
|
||||
}
|
||||
|
||||
@ -781,7 +822,7 @@ void SCCPSolver::visitReturnInst(ReturnInst &I) {
|
||||
|
||||
// ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
|
||||
// discover a concrete value later.
|
||||
if (isOverdefined(ValueState[&I]))
|
||||
if (ValueState[&I].isOverdefined())
|
||||
return;
|
||||
|
||||
Function *F = I.getParent()->getParent();
|
||||
@ -822,25 +863,27 @@ 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 (isOverdefined(ValueState[&I]))
|
||||
if (ValueState[&I].isOverdefined())
|
||||
return;
|
||||
|
||||
LatticeVal OpSt = getValueState(I.getOperand(0));
|
||||
if (Constant *OpC = getConstant(OpSt)) {
|
||||
if (OpSt.isOverdefined()) // Inherit overdefinedness of operand
|
||||
markOverdefined(&I);
|
||||
else if (OpSt.isConstant()) {
|
||||
// Fold the constant as we build.
|
||||
Constant *C = ConstantFoldCastOperand(I.getOpcode(), OpC, I.getType(), DL);
|
||||
Constant *C = ConstantFoldCastOperand(I.getOpcode(), OpSt.getConstant(),
|
||||
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 (isOverdefined(ValueState[&EVI]))
|
||||
if (ValueState[&EVI].isOverdefined())
|
||||
return;
|
||||
|
||||
// If this returns a struct, mark all elements over defined, we don't track
|
||||
@ -870,7 +913,7 @@ void SCCPSolver::visitInsertValueInst(InsertValueInst &IVI) {
|
||||
|
||||
// ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
|
||||
// discover a concrete value later.
|
||||
if (isOverdefined(ValueState[&IVI]))
|
||||
if (ValueState[&IVI].isOverdefined())
|
||||
return;
|
||||
|
||||
// If this has more than one index, we can't handle it, drive all results to
|
||||
@ -909,14 +952,14 @@ void SCCPSolver::visitSelectInst(SelectInst &I) {
|
||||
|
||||
// ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
|
||||
// discover a concrete value later.
|
||||
if (isOverdefined(ValueState[&I]))
|
||||
if (ValueState[&I].isOverdefined())
|
||||
return;
|
||||
|
||||
LatticeVal CondValue = getValueState(I.getCondition());
|
||||
if (CondValue.isUnknown())
|
||||
return;
|
||||
|
||||
if (ConstantInt *CondCB = getConstantInt(CondValue)) {
|
||||
if (ConstantInt *CondCB = CondValue.getConstantInt()) {
|
||||
Value *OpVal = CondCB->isZero() ? I.getFalseValue() : I.getTrueValue();
|
||||
mergeInValue(&I, getValueState(OpVal));
|
||||
return;
|
||||
@ -929,9 +972,9 @@ void SCCPSolver::visitSelectInst(SelectInst &I) {
|
||||
LatticeVal FVal = getValueState(I.getFalseValue());
|
||||
|
||||
// select ?, C, C -> C.
|
||||
if (isConstant(TVal) && isConstant(FVal) &&
|
||||
getConstant(TVal) == getConstant(FVal))
|
||||
return (void)markConstant(&I, getConstant(FVal));
|
||||
if (TVal.isConstant() && FVal.isConstant() &&
|
||||
TVal.getConstant() == FVal.getConstant())
|
||||
return (void)markConstant(&I, FVal.getConstant());
|
||||
|
||||
if (TVal.isUnknown()) // select ?, undef, X -> X.
|
||||
return (void)mergeInValue(&I, FVal);
|
||||
@ -947,10 +990,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 (isOverdefined(IV)) return;
|
||||
if (IV.isOverdefined()) return;
|
||||
|
||||
if (isConstant(V0State)) {
|
||||
Constant *C = ConstantExpr::get(I.getOpcode(), getConstant(V0State));
|
||||
if (V0State.isConstant()) {
|
||||
Constant *C = ConstantExpr::get(I.getOpcode(), V0State.getConstant());
|
||||
|
||||
// op Y -> undef.
|
||||
if (isa<UndefValue>(C))
|
||||
@ -959,7 +1002,7 @@ void SCCPSolver::visitUnaryOperator(Instruction &I) {
|
||||
}
|
||||
|
||||
// If something is undef, wait for it to resolve.
|
||||
if (!isOverdefined(V0State))
|
||||
if (!V0State.isOverdefined())
|
||||
return;
|
||||
|
||||
markOverdefined(&I);
|
||||
@ -971,14 +1014,11 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
|
||||
LatticeVal V2State = getValueState(I.getOperand(1));
|
||||
|
||||
LatticeVal &IV = ValueState[&I];
|
||||
if (isOverdefined(IV)) {
|
||||
markOverdefined(&I);
|
||||
return;
|
||||
}
|
||||
if (IV.isOverdefined()) return;
|
||||
|
||||
if (isConstant(V1State) && isConstant(V2State)) {
|
||||
Constant *C = ConstantExpr::get(I.getOpcode(), getConstant(V1State),
|
||||
getConstant(V2State));
|
||||
if (V1State.isConstant() && V2State.isConstant()) {
|
||||
Constant *C = ConstantExpr::get(I.getOpcode(), V1State.getConstant(),
|
||||
V2State.getConstant());
|
||||
// X op Y -> undef.
|
||||
if (isa<UndefValue>(C))
|
||||
return;
|
||||
@ -986,16 +1026,18 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
|
||||
}
|
||||
|
||||
// If something is undef, wait for it to resolve.
|
||||
if (V1State.isUnknown() || V2State.isUnknown())
|
||||
if (!V1State.isOverdefined() && !V2State.isOverdefined()) {
|
||||
|
||||
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 (isConstant(V1State) && getConstant(V1State)->isNullValue())
|
||||
return (void)markConstant(IV, &I, getConstant(V1State));
|
||||
if (V1State.isConstant() && V1State.getConstant()->isNullValue())
|
||||
return (void)markConstant(IV, &I, V1State.getConstant());
|
||||
|
||||
// If this is:
|
||||
// -> AND/MUL with 0
|
||||
@ -1004,10 +1046,9 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
|
||||
if (I.getOpcode() == Instruction::And || I.getOpcode() == Instruction::Mul ||
|
||||
I.getOpcode() == Instruction::Or) {
|
||||
LatticeVal *NonOverdefVal = nullptr;
|
||||
if (!isOverdefined(V1State))
|
||||
if (!V1State.isOverdefined())
|
||||
NonOverdefVal = &V1State;
|
||||
|
||||
else if (!isOverdefined(V2State))
|
||||
else if (!V2State.isOverdefined())
|
||||
NonOverdefVal = &V2State;
|
||||
if (NonOverdefVal) {
|
||||
if (NonOverdefVal->isUnknown())
|
||||
@ -1017,13 +1058,13 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
|
||||
I.getOpcode() == Instruction::Mul) {
|
||||
// X and 0 = 0
|
||||
// X * 0 = 0
|
||||
if (getConstant(*NonOverdefVal)->isNullValue())
|
||||
return (void)markConstant(IV, &I, getConstant(*NonOverdefVal));
|
||||
if (NonOverdefVal->getConstant()->isNullValue())
|
||||
return (void)markConstant(IV, &I, NonOverdefVal->getConstant());
|
||||
} else {
|
||||
// X or -1 = -1
|
||||
if (ConstantInt *CI = getConstantInt(*NonOverdefVal))
|
||||
if (ConstantInt *CI = NonOverdefVal->getConstantInt())
|
||||
if (CI->isMinusOne())
|
||||
return (void)markConstant(IV, &I, CI);
|
||||
return (void)markConstant(IV, &I, NonOverdefVal->getConstant());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1035,18 +1076,22 @@ 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 (isOverdefined(ValueState[&I])) {
|
||||
markOverdefined(&I);
|
||||
return;
|
||||
}
|
||||
if (ValueState[&I].isOverdefined()) return;
|
||||
|
||||
Value *Op1 = I.getOperand(0);
|
||||
Value *Op2 = I.getOperand(1);
|
||||
|
||||
// For parameters, use ParamState which includes constant range info if
|
||||
// available.
|
||||
auto V1State = getValueState(Op1);
|
||||
auto V2State = getValueState(Op2);
|
||||
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();
|
||||
|
||||
Constant *C = V1State.getCompare(I.getPredicate(), I.getType(), V2State);
|
||||
if (C) {
|
||||
@ -1059,8 +1104,8 @@ void SCCPSolver::visitCmpInst(CmpInst &I) {
|
||||
}
|
||||
|
||||
// If operands are still unknown, wait for it to resolve.
|
||||
if ((V1State.isUnknown() || V2State.isUnknown()) &&
|
||||
!isConstant(ValueState[&I]))
|
||||
if (!V1State.isOverdefined() && !V2State.isOverdefined() &&
|
||||
!ValueState[&I].isConstant())
|
||||
return;
|
||||
|
||||
markOverdefined(&I);
|
||||
@ -1069,7 +1114,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 (isOverdefined(ValueState[&I])) return;
|
||||
if (ValueState[&I].isOverdefined()) return;
|
||||
|
||||
SmallVector<Constant*, 8> Operands;
|
||||
Operands.reserve(I.getNumOperands());
|
||||
@ -1079,15 +1124,11 @@ void SCCPSolver::visitGetElementPtrInst(GetElementPtrInst &I) {
|
||||
if (State.isUnknown())
|
||||
return; // Operands are not resolved yet.
|
||||
|
||||
if (isOverdefined(State))
|
||||
if (State.isOverdefined())
|
||||
return (void)markOverdefined(&I);
|
||||
|
||||
if (Constant *C = getConstant(State)) {
|
||||
Operands.push_back(C);
|
||||
continue;
|
||||
}
|
||||
|
||||
return (void)markOverdefined(&I);
|
||||
assert(State.isConstant() && "Unknown state!");
|
||||
Operands.push_back(State.getConstant());
|
||||
}
|
||||
|
||||
Constant *Ptr = Operands[0];
|
||||
@ -1109,17 +1150,16 @@ void SCCPSolver::visitStoreInst(StoreInst &SI) {
|
||||
|
||||
// ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
|
||||
// discover a concrete value later.
|
||||
if (isOverdefined(ValueState[&SI]))
|
||||
if (ValueState[&SI].isOverdefined())
|
||||
return;
|
||||
|
||||
GlobalVariable *GV = cast<GlobalVariable>(SI.getOperand(1));
|
||||
DenseMap<GlobalVariable*, LatticeVal>::iterator I = TrackedGlobals.find(GV);
|
||||
if (I == TrackedGlobals.end())
|
||||
return;
|
||||
if (I == TrackedGlobals.end() || I->second.isOverdefined()) return;
|
||||
|
||||
// Get the value we are storing into the global, then merge it.
|
||||
mergeInValue(I->second, GV, getValueState(SI.getOperand(0)));
|
||||
if (isOverdefined(I->second))
|
||||
if (I->second.isOverdefined())
|
||||
TrackedGlobals.erase(I); // No need to keep tracking this!
|
||||
}
|
||||
|
||||
@ -1132,7 +1172,7 @@ void SCCPSolver::visitLoadInst(LoadInst &I) {
|
||||
|
||||
// ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
|
||||
// discover a concrete value later.
|
||||
if (isOverdefined(ValueState[&I]))
|
||||
if (ValueState[&I].isOverdefined())
|
||||
return;
|
||||
|
||||
LatticeVal PtrVal = getValueState(I.getOperand(0));
|
||||
@ -1140,10 +1180,10 @@ void SCCPSolver::visitLoadInst(LoadInst &I) {
|
||||
|
||||
LatticeVal &IV = ValueState[&I];
|
||||
|
||||
if (!isConstant(PtrVal) || I.isVolatile())
|
||||
if (!PtrVal.isConstant() || I.isVolatile())
|
||||
return (void)markOverdefined(IV, &I);
|
||||
|
||||
Constant *Ptr = getConstant(PtrVal);
|
||||
Constant *Ptr = PtrVal.getConstant();
|
||||
|
||||
// load null is undefined.
|
||||
if (isa<ConstantPointerNull>(Ptr)) {
|
||||
@ -1184,7 +1224,7 @@ void SCCPSolver::visitCallSite(CallSite CS) {
|
||||
|
||||
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
|
||||
if (II->getIntrinsicID() == Intrinsic::ssa_copy) {
|
||||
if (isOverdefined(ValueState[I]))
|
||||
if (ValueState[I].isOverdefined())
|
||||
return;
|
||||
|
||||
auto *PI = getPredicateInfoFor(I);
|
||||
@ -1222,7 +1262,7 @@ void SCCPSolver::visitCallSite(CallSite CS) {
|
||||
LatticeVal &IV = ValueState[I];
|
||||
if (PBranch->TrueEdge && Cmp->getPredicate() == CmpInst::ICMP_EQ) {
|
||||
addAdditionalUser(CmpOp1, I);
|
||||
if (isConstant(OriginalVal))
|
||||
if (OriginalVal.isConstant())
|
||||
mergeInValue(IV, I, OriginalVal);
|
||||
else
|
||||
mergeInValue(IV, I, EqVal);
|
||||
@ -1230,7 +1270,7 @@ void SCCPSolver::visitCallSite(CallSite CS) {
|
||||
}
|
||||
if (!PBranch->TrueEdge && Cmp->getPredicate() == CmpInst::ICMP_NE) {
|
||||
addAdditionalUser(CmpOp1, I);
|
||||
if (isConstant(OriginalVal))
|
||||
if (OriginalVal.isConstant())
|
||||
mergeInValue(IV, I, OriginalVal);
|
||||
else
|
||||
mergeInValue(IV, I, EqVal);
|
||||
@ -1262,13 +1302,13 @@ CallOverdefined:
|
||||
|
||||
if (State.isUnknown())
|
||||
return; // Operands are not resolved yet.
|
||||
if (isOverdefined(State))
|
||||
if (State.isOverdefined())
|
||||
return (void)markOverdefined(I);
|
||||
assert(isConstant(State) && "Unknown state!");
|
||||
Operands.push_back(getConstant(State));
|
||||
assert(State.isConstant() && "Unknown state!");
|
||||
Operands.push_back(State.getConstant());
|
||||
}
|
||||
|
||||
if (isOverdefined(getValueState(I)))
|
||||
if (getValueState(I).isOverdefined())
|
||||
return;
|
||||
|
||||
// If we can constant fold this, mark the result of the call as a
|
||||
@ -1306,10 +1346,24 @@ 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, false);
|
||||
mergeInValue(getStructValueState(&*AI, i), &*AI, CallArg);
|
||||
}
|
||||
} else
|
||||
mergeInValue(&*AI, getValueState(*CAI), 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1367,7 +1421,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() || !isOverdefined(getValueState(I)))
|
||||
if (I->getType()->isStructTy() || !getValueState(I).isOverdefined())
|
||||
markUsersAsChanged(I);
|
||||
}
|
||||
|
||||
@ -1546,24 +1600,24 @@ static bool tryToReplaceWithConstant(SCCPSolver &Solver, Value *V) {
|
||||
Constant *Const = nullptr;
|
||||
if (V->getType()->isStructTy()) {
|
||||
std::vector<LatticeVal> IVs = Solver.getStructLatticeValueFor(V);
|
||||
if (any_of(IVs, [](const LatticeVal &LV) { return isOverdefined(LV); }))
|
||||
if (llvm::any_of(IVs,
|
||||
[](const LatticeVal &LV) { return LV.isOverdefined(); }))
|
||||
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(isConstant(V)
|
||||
? Solver.getConstant(V)
|
||||
ConstVals.push_back(V.isConstant()
|
||||
? V.getConstant()
|
||||
: UndefValue::get(ST->getElementType(i)));
|
||||
}
|
||||
Const = ConstantStruct::get(ST, ConstVals);
|
||||
} else {
|
||||
const LatticeVal &IV = Solver.getLatticeValueFor(V);
|
||||
if (isOverdefined(IV))
|
||||
if (IV.isOverdefined())
|
||||
return false;
|
||||
|
||||
Const =
|
||||
isConstant(IV) ? Solver.getConstant(IV) : UndefValue::get(V->getType());
|
||||
Const = IV.isConstant() ? IV.getConstant() : UndefValue::get(V->getType());
|
||||
}
|
||||
assert(Const && "Constant is nullptr here!");
|
||||
|
||||
@ -1596,8 +1650,7 @@ 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; },
|
||||
F.getContext());
|
||||
DL, [TLI](Function &F) -> const TargetLibraryInfo & { return *TLI; });
|
||||
|
||||
// Mark the first block of the function as being executable.
|
||||
Solver.MarkBlockExecutable(&F.front());
|
||||
@ -1740,9 +1793,9 @@ static void findReturnsToZap(Function &F,
|
||||
if (U->getType()->isStructTy()) {
|
||||
return all_of(
|
||||
Solver.getStructLatticeValueFor(U),
|
||||
[](const LatticeVal &LV) { return !isOverdefined(LV); });
|
||||
[](const LatticeVal &LV) { return !LV.isOverdefined(); });
|
||||
}
|
||||
return !isOverdefined(Solver.getLatticeValueFor(U));
|
||||
return !Solver.getLatticeValueFor(U).isOverdefined();
|
||||
}) &&
|
||||
"We can only zap functions where all live users have a concrete value");
|
||||
|
||||
@ -1799,7 +1852,7 @@ bool llvm::runIPSCCP(
|
||||
Module &M, const DataLayout &DL,
|
||||
std::function<const TargetLibraryInfo &(Function &)> GetTLI,
|
||||
function_ref<AnalysisResultsForFn(Function &)> getAnalysis) {
|
||||
SCCPSolver Solver(DL, GetTLI, M.getContext());
|
||||
SCCPSolver Solver(DL, GetTLI);
|
||||
|
||||
// Loop over all functions, marking arguments to those with their addresses
|
||||
// taken or that are external as overdefined.
|
||||
@ -1985,7 +2038,7 @@ bool llvm::runIPSCCP(
|
||||
const MapVector<Function*, LatticeVal> &RV = Solver.getTrackedRetVals();
|
||||
for (const auto &I : RV) {
|
||||
Function *F = I.first;
|
||||
if (isOverdefined(I.second) || F->getReturnType()->isVoidTy())
|
||||
if (I.second.isOverdefined() || F->getReturnType()->isVoidTy())
|
||||
continue;
|
||||
findReturnsToZap(*F, ReturnsToZap, Solver);
|
||||
}
|
||||
@ -2010,8 +2063,8 @@ bool llvm::runIPSCCP(
|
||||
for (DenseMap<GlobalVariable*, LatticeVal>::const_iterator I = TG.begin(),
|
||||
E = TG.end(); I != E; ++I) {
|
||||
GlobalVariable *GV = I->first;
|
||||
if (isOverdefined(I->second))
|
||||
continue;
|
||||
assert(!I->second.isOverdefined() &&
|
||||
"Overdefined values should have been taken out of the map!");
|
||||
LLVM_DEBUG(dbgs() << "Found that GV '" << GV->getName()
|
||||
<< "' is constant!\n");
|
||||
while (!GV->use_empty()) {
|
||||
|
@ -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
|
||||
|
@ -40,7 +40,9 @@ 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: call void @use.1(i1 false)
|
||||
; 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: ret i32 undef
|
||||
;
|
||||
entry:
|
||||
@ -117,7 +119,9 @@ 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: call void @use.1(i1 false)
|
||||
; 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: ret i32 undef
|
||||
;
|
||||
entry:
|
||||
@ -389,6 +393,7 @@ 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
|
||||
|
Loading…
Reference in New Issue
Block a user