/// Print the constant value.
void print(raw_ostream &os) const;
- /// The pessimistic value state of the constant value is unknown.
- static ConstantValue getPessimisticValueState(Value value) { return {}; }
+ /// The state where the constant value is unknown.
+ static ConstantValue getUnknownConstant() { return {}; }
/// The union with another constant value is null if they are different, and
/// the same if they are the same.
void visitOperation(Operation *op,
ArrayRef<const Lattice<ConstantValue> *> operands,
ArrayRef<Lattice<ConstantValue> *> results) override;
+
+ void setToEntryState(Lattice<ConstantValue> *lattice) override;
};
} // end namespace dataflow
/// Join the lattice across control-flow or callgraph edges.
virtual ChangeResult join(const AbstractDenseLattice &rhs) = 0;
-
- /// Reset the dense lattice to a pessimistic value. This occurs when the
- /// analysis cannot reason about the data-flow.
- virtual ChangeResult reset() = 0;
};
//===----------------------------------------------------------------------===//
const AbstractDenseLattice *getLatticeFor(ProgramPoint dependent,
ProgramPoint point);
- /// Mark the dense lattice as having reached its pessimistic fixpoint and
- /// propagate an update if it changed.
- void reset(AbstractDenseLattice *lattice) {
- propagateIfChanged(lattice, lattice->reset());
- }
+ /// Set the dense lattice at control flow entry point and propagate an update
+ /// if it changed.
+ virtual void setToEntryState(AbstractDenseLattice *lattice) = 0;
/// Join a lattice with another and propagate an update if it changed.
void join(AbstractDenseLattice *lhs, const AbstractDenseLattice &rhs) {
return getOrCreate<LatticeT>(point);
}
+ /// Set the dense lattice at control flow entry point and propagate an update
+ /// if it changed.
+ virtual void setToEntryState(LatticeT *lattice) = 0;
+ void setToEntryState(AbstractDenseLattice *lattice) override {
+ setToEntryState(static_cast<LatticeT *>(lattice));
+ }
+
private:
/// Type-erased wrappers that convert the abstract dense lattice to a derived
/// lattice and invoke the virtual hooks operating on the derived lattice.
/// Create a maximal range ([0, uint_max(t)] / [int_min(t), int_max(t)])
/// range that is used to mark the value as unable to be analyzed further,
/// where `t` is the type of `value`.
- static IntegerValueRange getPessimisticValueState(Value value);
+ static IntegerValueRange getMaxRange(Value value);
/// Create an integer value range lattice value.
IntegerValueRange(ConstantIntRanges value) : value(std::move(value)) {}
public:
using SparseDataFlowAnalysis::SparseDataFlowAnalysis;
+ /// At an entry point, we cannot reason about interger value ranges.
+ void setToEntryState(IntegerValueRangeLattice *lattice) override {
+ propagateIfChanged(lattice, lattice->join(IntegerValueRange::getMaxRange(
+ lattice->getPoint())));
+ }
+
/// Visit an operation. Invoke the transfer function on each operation that
/// implements `InferIntRangeInterface`.
void visitOperation(Operation *op,
/// Lattices can only be created for values.
AbstractSparseLattice(Value value) : AnalysisState(value) {}
+ /// Return the program point this lattice is located at.
+ Value getPoint() const { return AnalysisState::getPoint().get<Value>(); }
+
/// Join the information contained in 'rhs' into this lattice. Returns
/// if the value of the lattice changed.
virtual ChangeResult join(const AbstractSparseLattice &rhs) = 0;
- /// Mark the lattice element as having reached a pessimistic fixpoint. This
- /// means that the lattice may potentially have conflicting value states, and
- /// only the most conservative value should be relied on.
- virtual ChangeResult markPessimisticFixpoint() = 0;
-
/// When the lattice gets updated, propagate an update to users of the value
/// using its use-def chain to subscribed analyses.
void onUpdate(DataFlowSolver *solver) const override;
template <typename ValueT>
class Lattice : public AbstractSparseLattice {
public:
- /// Construct a lattice with a known value.
- explicit Lattice(Value value)
- : AbstractSparseLattice(value),
- knownValue(ValueT::getPessimisticValueState(value)) {}
+ using AbstractSparseLattice::AbstractSparseLattice;
+
+ /// Return the program point this lattice is located at.
+ Value getPoint() const { return point.get<Value>(); }
/// Return the value held by this lattice. This requires that the value is
/// initialized.
ValueT &getValue() {
assert(!isUninitialized() && "expected known lattice element");
- return *optimisticValue;
+ return *value;
}
const ValueT &getValue() const {
return const_cast<Lattice<ValueT> *>(this)->getValue();
}
/// Returns true if the value of this lattice hasn't yet been initialized.
- bool isUninitialized() const override { return !optimisticValue.has_value(); }
+ bool isUninitialized() const override { return !value.has_value(); }
/// Join the information contained in the 'rhs' lattice into this
/// lattice. Returns if the state of the current lattice changed.
ChangeResult join(const ValueT &rhs) {
// If the current lattice is uninitialized, copy the rhs value.
if (isUninitialized()) {
- optimisticValue = rhs;
+ value = rhs;
return ChangeResult::Change;
}
// Otherwise, join rhs with the current optimistic value.
- ValueT newValue = ValueT::join(*optimisticValue, rhs);
- assert(ValueT::join(newValue, *optimisticValue) == newValue &&
+ ValueT newValue = ValueT::join(*value, rhs);
+ assert(ValueT::join(newValue, *value) == newValue &&
"expected `join` to be monotonic");
assert(ValueT::join(newValue, rhs) == newValue &&
"expected `join` to be monotonic");
// Update the current optimistic value if something changed.
- if (newValue == optimisticValue)
+ if (newValue == value)
return ChangeResult::NoChange;
- optimisticValue = newValue;
- return ChangeResult::Change;
- }
-
- /// Mark the lattice element as having reached a pessimistic fixpoint. This
- /// means that the lattice may potentially have conflicting value states,
- /// and only the conservatively known value state should be relied on.
- ChangeResult markPessimisticFixpoint() override {
- if (optimisticValue == knownValue)
- return ChangeResult::NoChange;
-
- // For this fixed point, we take whatever we knew to be true and set that
- // to our optimistic value.
- optimisticValue = knownValue;
+ value = newValue;
return ChangeResult::Change;
}
/// Print the lattice element.
void print(raw_ostream &os) const override {
- os << "[";
- knownValue.print(os);
- os << ", ";
- if (optimisticValue)
- optimisticValue->print(os);
+ if (value)
+ value->print(os);
else
os << "<NULL>";
- os << "]";
}
private:
- /// The value that is conservatively known to be true.
- ValueT knownValue;
/// The currently computed value that is optimistically assumed to be true,
/// or None if the lattice element is uninitialized.
- Optional<ValueT> optimisticValue;
+ Optional<ValueT> value;
};
//===----------------------------------------------------------------------===//
const AbstractSparseLattice *getLatticeElementFor(ProgramPoint point,
Value value);
- /// Mark the given lattice elements as having reached their pessimistic
- /// fixpoints and propagate an update if any changed.
- void markAllPessimisticFixpoint(ArrayRef<AbstractSparseLattice *> lattices);
+ /// Set the given lattice element(s) at control flow entry point(s).
+ virtual void setToEntryState(AbstractSparseLattice *lattice) = 0;
+ void setAllToEntryStates(ArrayRef<AbstractSparseLattice *> lattices);
/// Join the lattice element and propagate and update if it changed.
void join(AbstractSparseLattice *lhs, const AbstractSparseLattice &rhs);
const RegionSuccessor &successor,
ArrayRef<StateT *> argLattices,
unsigned firstIndex) {
- markAllPessimisticFixpoint(argLattices.take_front(firstIndex));
- markAllPessimisticFixpoint(argLattices.drop_front(
+ setAllToEntryStates(argLattices.take_front(firstIndex));
+ setAllToEntryStates(argLattices.drop_front(
firstIndex + successor.getSuccessorInputs().size()));
}
AbstractSparseDataFlowAnalysis::getLatticeElementFor(point, value));
}
- /// Mark the lattice elements of a range of values as having reached their
- /// pessimistic fixpoint.
- void markAllPessimisticFixpoint(ArrayRef<StateT *> lattices) {
- AbstractSparseDataFlowAnalysis::markAllPessimisticFixpoint(
+ /// Set the given lattice element(s) at control flow entry point(s).
+ virtual void setToEntryState(StateT *lattice) = 0;
+ void setAllToEntryStates(ArrayRef<StateT *> lattices) {
+ AbstractSparseDataFlowAnalysis::setAllToEntryStates(
{reinterpret_cast<AbstractSparseLattice *const *>(lattices.begin()),
lattices.size()});
}
argLattices.size()},
firstIndex);
}
+ void setToEntryState(AbstractSparseLattice *lattice) override {
+ return setToEntryState(reinterpret_cast<StateT *>(lattice));
+ }
};
} // end namespace dataflow
/// Create the analysis state at the given program point.
AnalysisState(ProgramPoint point) : point(point) {}
+ /// Returns the program point this static is located at.
+ ProgramPoint getPoint() const { return point; }
+
/// Returns true if the analysis state is uninitialized.
virtual bool isUninitialized() const = 0;
// folds as the desire here is for simulated execution, and not general
// folding.
if (op->getNumRegions()) {
- markAllPessimisticFixpoint(results);
+ setAllToEntryStates(results);
return;
}
SmallVector<OpFoldResult, 8> foldResults;
foldResults.reserve(op->getNumResults());
if (failed(op->fold(constantOperands, foldResults))) {
- markAllPessimisticFixpoint(results);
+ setAllToEntryStates(results);
return;
}
if (foldResults.empty()) {
op->setOperands(originalOperands);
op->setAttrs(originalAttrs);
- markAllPessimisticFixpoint(results);
+ setAllToEntryStates(results);
return;
}
}
}
}
+
+void SparseConstantPropagation::setToEntryState(
+ Lattice<ConstantValue> *lattice) {
+ propagateIfChanged(lattice,
+ lattice->join(ConstantValue::getUnknownConstant()));
+}
// If not all return sites are known, then conservatively assume we can't
// reason about the data-flow.
if (!predecessors->allPredecessorsKnown())
- return reset(after);
+ return setToEntryState(after);
for (Operation *predecessor : predecessors->getKnownPredecessors())
join(after, *getLatticeFor(op, predecessor));
return;
// If not all callsites are known, conservatively mark all lattices as
// having reached their pessimistic fixpoints.
if (!callsites->allPredecessorsKnown())
- return reset(after);
+ return setToEntryState(after);
for (Operation *callsite : callsites->getKnownPredecessors()) {
// Get the dense lattice before the callsite.
if (Operation *prev = callsite->getPrevNode())
return visitRegionBranchOperation(block, branch, after);
// Otherwise, we can't reason about the data-flow.
- return reset(after);
+ return setToEntryState(after);
}
// Join the state with the state after the block's predecessors.
using namespace mlir;
using namespace mlir::dataflow;
-IntegerValueRange IntegerValueRange::getPessimisticValueState(Value value) {
+IntegerValueRange IntegerValueRange::getMaxRange(Value value) {
unsigned width = ConstantIntRanges::getStorageBitwidth(value.getType());
APInt umin = APInt::getMinValue(width);
APInt umax = APInt::getMaxValue(width);
auto value = point.get<Value>();
auto *cv = solver->getOrCreateState<Lattice<ConstantValue>>(value);
if (!constant)
- return solver->propagateIfChanged(cv, cv->markPessimisticFixpoint());
+ return solver->propagateIfChanged(
+ cv, cv->join(ConstantValue::getUnknownConstant()));
Dialect *dialect;
if (auto *parent = value.getDefiningOp())
// integer results
bool hasIntegerResult = false;
for (auto it : llvm::zip(results, op->getResults())) {
- if (std::get<1>(it).getType().isIntOrIndex()) {
+ Value value = std::get<1>(it);
+ if (value.getType().isIntOrIndex()) {
hasIntegerResult = true;
} else {
- propagateIfChanged(std::get<0>(it),
- std::get<0>(it)->markPessimisticFixpoint());
+ IntegerValueRangeLattice *lattice = std::get<0>(it);
+ propagateIfChanged(lattice,
+ lattice->join(IntegerValueRange::getMaxRange(value)));
}
}
if (!hasIntegerResult)
auto inferrable = dyn_cast<InferIntRangeInterface>(op);
if (!inferrable)
- return markAllPessimisticFixpoint(results);
+ return setAllToEntryStates(results);
LLVM_DEBUG(llvm::dbgs() << "Inferring ranges for " << *op << "\n");
SmallVector<ConstantIntRanges> argRanges(
if (isYieldedResult && oldRange.has_value() &&
!(lattice->getValue() == *oldRange)) {
LLVM_DEBUG(llvm::dbgs() << "Loop variant loop result detected\n");
- changed |= lattice->markPessimisticFixpoint();
+ changed |= lattice->join(IntegerValueRange::getMaxRange(v));
}
propagateIfChanged(lattice, changed);
};
});
if (isYieldedValue && oldRange && !(lattice->getValue() == *oldRange)) {
LLVM_DEBUG(llvm::dbgs() << "Loop variant loop result detected\n");
- changed |= lattice->markPessimisticFixpoint();
+ changed |= lattice->join(IntegerValueRange::getMaxRange(v));
}
propagateIfChanged(lattice, changed);
};
if (region.empty())
continue;
for (Value argument : region.front().getArguments())
- markAllPessimisticFixpoint(getLatticeElement(argument));
+ setAllToEntryStates(getLatticeElement(argument));
}
return initializeRecursively(top);
// If not all return sites are known, then conservatively assume we can't
// reason about the data-flow.
if (!predecessors->allPredecessorsKnown())
- return markAllPessimisticFixpoint(resultLattices);
+ return setAllToEntryStates(resultLattices);
for (Operation *predecessor : predecessors->getKnownPredecessors())
for (auto it : llvm::zip(predecessor->getOperands(), resultLattices))
join(std::get<1>(it), *getLatticeElementFor(op, std::get<0>(it)));
// If not all callsites are known, conservatively mark all lattices as
// having reached their pessimistic fixpoints.
if (!callsites->allPredecessorsKnown())
- return markAllPessimisticFixpoint(argLattices);
+ return setAllToEntryStates(argLattices);
for (Operation *callsite : callsites->getKnownPredecessors()) {
auto call = cast<CallOpInterface>(callsite);
for (auto it : llvm::zip(call.getArgOperands(), argLattices))
if (Value operand = operands[it.index()]) {
join(it.value(), *getLatticeElementFor(block, operand));
} else {
- // Conservatively mark internally produced arguments as having reached
- // their pessimistic fixpoint.
- markAllPessimisticFixpoint(it.value());
+ // Conservatively consider internally produced arguments as entry
+ // points.
+ setAllToEntryStates(it.value());
}
}
} else {
- return markAllPessimisticFixpoint(argLattices);
+ return setAllToEntryStates(argLattices);
}
}
}
if (!operands) {
// We can't reason about the data-flow.
- return markAllPessimisticFixpoint(lattices);
+ return setAllToEntryStates(lattices);
}
ValueRange inputs = predecessors->getSuccessorInputs(op);
return state;
}
-void AbstractSparseDataFlowAnalysis::markAllPessimisticFixpoint(
+void AbstractSparseDataFlowAnalysis::setAllToEntryStates(
ArrayRef<AbstractSparseLattice *> lattices) {
for (AbstractSparseLattice *lattice : lattices)
- propagateIfChanged(lattice, lattice->markPessimisticFixpoint());
+ setToEntryState(lattice);
}
void AbstractSparseDataFlowAnalysis::join(AbstractSparseLattice *lhs,
constant, constant->join(ConstantValue(value, op->getDialect())));
return success();
}
- markAllPessimisticFixpoint(op->getResults());
+ setAllToUnknownConstants(op->getResults());
for (Region ®ion : op->getRegions())
- markAllPessimisticFixpoint(region.getArguments());
+ setAllToUnknownConstants(region.getArguments());
return success();
}
- /// Mark the constant values of all given values as having reached a
- /// pessimistic fixpoint.
- void markAllPessimisticFixpoint(ValueRange values) {
+ /// Set all given values as not constants.
+ void setAllToUnknownConstants(ValueRange values) {
for (Value value : values) {
- auto *constantValue = getOrCreate<Lattice<ConstantValue>>(value);
- propagateIfChanged(constantValue,
- constantValue->markPessimisticFixpoint());
+ auto *constant = getOrCreate<Lattice<ConstantValue>>(value);
+ propagateIfChanged(constant,
+ constant->join(ConstantValue::getUnknownConstant()));
}
}
};
/// This lattice represents a single underlying value for an SSA value.
class UnderlyingValue {
public:
- /// The pessimistic underlying value of a value is itself.
- static UnderlyingValue getPessimisticValueState(Value value) {
- return {value};
- }
-
/// Create an underlying value state with a known underlying value.
- UnderlyingValue(Value underlyingValue = {})
- : underlyingValue(underlyingValue) {}
+ UnderlyingValue(Value underlyingValue) : underlyingValue(underlyingValue) {}
/// Returns the underlying value.
Value getUnderlyingValue() const { return underlyingValue; }
/// go to the pessimistic value.
static UnderlyingValue join(const UnderlyingValue &lhs,
const UnderlyingValue &rhs) {
- return lhs.underlyingValue == rhs.underlyingValue ? lhs : UnderlyingValue();
+ return lhs.underlyingValue == rhs.underlyingValue ? lhs : Value();
}
/// Compare underlying values.
/// The lattice is always initialized.
bool isUninitialized() const override { return false; }
- /// Mark the lattice as having reached its pessimistic fixpoint. That is, the
- /// last modifications of all memory resources are unknown.
- ChangeResult reset() override {
+ /// Clear all modifications.
+ ChangeResult reset() {
if (lastMods.empty())
return ChangeResult::NoChange;
lastMods.clear();
/// resource, then its reaching definition is set to the written value.
void visitOperation(Operation *op, const LastModification &before,
LastModification *after) override;
+
+ /// At an entry point, the last modifications of all memory resources are
+ /// unknown.
+ void setToEntryState(LastModification *lattice) override {
+ propagateIfChanged(lattice, lattice->reset());
+ }
};
/// Define the lattice class explicitly to provide a type ID.
void visitOperation(Operation *op,
ArrayRef<const UnderlyingValueLattice *> operands,
ArrayRef<UnderlyingValueLattice *> results) override {
- markAllPessimisticFixpoint(results);
+ setAllToEntryStates(results);
+ }
+
+ /// At an entry point, the underlying value of a value is itself.
+ void setToEntryState(UnderlyingValueLattice *lattice) override {
+ propagateIfChanged(lattice,
+ lattice->join(UnderlyingValue{lattice->getPoint()}));
}
};
} // end anonymous namespace
// If we can't reason about the memory effects, then conservatively assume we
// can't deduce anything about the last modifications.
if (!memory)
- return reset(after);
+ return setToEntryState(after);
SmallVector<MemoryEffects::EffectInstance> effects;
memory.getEffects(effects);
// If we see an effect on anything other than a value, assume we can't
// deduce anything about the last modifications.
if (!value)
- return reset(after);
+ return setToEntryState(after);
value = getMostUnderlyingValue(value, [&](Value value) {
return getOrCreateFor<UnderlyingValueLattice>(op, value);