18#include <mlir/Analysis/DataFlow/DeadCodeAnalysis.h>
19#include <mlir/IR/Value.h>
21#include <llvm/Support/Debug.h>
24#include <unordered_set>
26#define DEBUG_TYPE "llzk-constrain-ref-lattice"
30using namespace component;
32using namespace polymorphic;
45std::pair<ConstrainRefLatticeValue, mlir::ChangeResult>
48 auto res = mlir::ChangeResult::NoChange;
49 if (newVal.isScalar()) {
50 res = newVal.translateScalar(translation);
52 for (
auto &elem : newVal.getArrayValue()) {
53 auto [newElem, elemRes] = elem->translate(translation);
61std::pair<ConstrainRefLatticeValue, mlir::ChangeResult>
68std::pair<ConstrainRefLatticeValue, mlir::ChangeResult>
74 std::vector<size_t> currIdxs {0};
75 for (
unsigned i = 0; i < indices.size(); i++) {
76 auto &idx = indices[i];
79 std::vector<size_t> newIdxs;
80 ensure(idx.isIndex() || idx.isIndexRange(),
"wrong type of index for array");
84 currIdxs.begin(), currIdxs.end(), std::back_inserter(newIdxs),
85 [&currDim, &idxVal](
size_t j) { return j * currDim + idxVal; }
88 auto [low, high] = idx.getIndexRange();
91 currIdxs.begin(), currIdxs.end(), std::back_inserter(newIdxs),
92 [&currDim, &idxVal](
size_t j) { return j * currDim + idxVal; }
99 std::vector<int64_t> newArrayDims;
103 newArrayDims.push_back(dim);
106 if (newArrayDims.empty()) {
109 for (
auto idx : currIdxs) {
112 return {extractedVal, mlir::ChangeResult::Change};
116 for (
auto chunkStart : currIdxs) {
117 for (
size_t i = 0; i < chunkSz; i++) {
121 return {extractedVal, mlir::ChangeResult::Change};
124 auto currVal = *
this;
125 auto res = mlir::ChangeResult::NoChange;
126 for (
auto &idx : indices) {
128 auto [newVal, transformRes] = currVal.elementwiseTransform(transform);
129 currVal = std::move(newVal);
132 return {currVal, res};
137 auto res = mlir::ChangeResult::NoChange;
142 for (
auto &[ref, val] : translation) {
143 auto it = currVal.find(ref);
144 if (it != currVal.end()) {
151std::pair<ConstrainRefLatticeValue, mlir::ChangeResult>
156 auto res = mlir::ChangeResult::NoChange;
157 if (newVal.isScalar()) {
159 for (
auto &ref : newVal.getScalarValue()) {
160 auto [_, inserted] = indexed.insert(transform(ref));
162 res |= mlir::ChangeResult::Change;
165 newVal.getScalarValue() = indexed;
167 for (
auto &elem : newVal.getArrayValue()) {
168 auto [newElem, elemRes] = elem->elementwiseTransform(transform);
173 return {newVal, res};
184 if (
auto blockArg = mlir::dyn_cast<mlir::BlockArgument>(val)) {
186 }
else if (
auto defOp = val.getDefiningOp()) {
187 if (
auto feltConst = mlir::dyn_cast<FeltConstantOp>(defOp)) {
189 }
else if (
auto constIdx = mlir::dyn_cast<mlir::arith::ConstantIndexOp>(defOp)) {
191 }
else if (
auto readConst = mlir::dyn_cast<ConstReadOp>(defOp)) {
195 return mlir::failure();
199 os <<
"ConstrainRefLattice { ";
200 for (
auto mit = valMap.begin(); mit != valMap.end();) {
201 auto &[val, latticeVal] = *mit;
202 os <<
"\n (" << val <<
") => " << latticeVal;
204 if (mit != valMap.end()) {
214 auto res = mlir::ChangeResult::NoChange;
216 for (
auto &[v, s] : rhs) {
223 auto it = valMap.find(v);
224 if (it != valMap.end()) {
229 if (mlir::succeeded(sourceRef)) {
236 auto op = this->getPoint().get<mlir::Operation *>();
237 if (
auto retOp = mlir::dyn_cast<function::ReturnOp>(op)) {
238 if (i >= retOp.getNumOperands()) {
239 llvm::report_fatal_error(
"return value requested is out of range");
This file implements (LLZK-tailored) dense data-flow analysis using the data-flow analysis framework.
Defines an index into an LLZK object.
A value at a given point of the ConstrainRefLattice.
mlir::ChangeResult insert(const ConstrainRef &rhs)
Directly insert the ref into this value.
ConstrainRefLatticeValue(ScalarTy s)
std::pair< ConstrainRefLatticeValue, mlir::ChangeResult > extract(const std::vector< ConstrainRefIndex > &indices) const
Perform an array.extract or array.read operation, depending on how many indices are provided.
mlir::ChangeResult translateScalar(const TranslationMap &translation)
Translate this value using the translation map, assuming this value is a scalar.
std::pair< ConstrainRefLatticeValue, mlir::ChangeResult > referenceField(SymbolLookupResult< component::FieldDefOp > fieldRef) const
Add the given fieldRef to the constrain refs contained within this value.
ConstrainRefLatticeValue()
std::pair< ConstrainRefLatticeValue, mlir::ChangeResult > translate(const TranslationMap &translation) const
For the refs contained in this value, translate them given the translation map and return the transfo...
virtual std::pair< ConstrainRefLatticeValue, mlir::ChangeResult > elementwiseTransform(llvm::function_ref< ConstrainRef(const ConstrainRef &)> transform) const
Perform a recursive transformation over all elements of this value and return a new value with the mo...
A lattice for use in dense analysis.
ConstrainRefLatticeValue getOrDefault(mlir::Value v) const
ConstrainRefLatticeValue getReturnValue(unsigned i) const
mlir::DenseMap< mlir::Value, ConstrainRefLatticeValue > ValueMap
static mlir::FailureOr< ConstrainRef > getSourceRef(mlir::Value val)
If val is the source of other values (i.e., a block argument from the function args or a constant),...
mlir::ChangeResult setValues(const ValueMap &rhs)
void print(mlir::raw_ostream &os) const override
mlir::ChangeResult setValue(mlir::Value v, const ConstrainRefLatticeValue &rhs)
Defines a reference to a llzk object within a constrain function call.
size_t getNumArrayDims() const
mlir::ChangeResult updateScalar(const ScalarTy &rhs)
int64_t getArrayDim(unsigned i) const
std::variant< ScalarTy, ArrayTy > & getValue()
mlir::ChangeResult update(const Derived &rhs)
Union this value with that of rhs.
mlir::ChangeResult foldAndUpdate(const ConstrainRefLatticeValue &rhs)
const ConstrainRefLatticeValue & getElemFlatIdx(unsigned i) const
const ScalarTy & getScalarValue() const
void print(mlir::raw_ostream &os) const
mlir::raw_ostream & operator<<(mlir::raw_ostream &os, const ConstrainRef &rhs)
void ensure(bool condition, llvm::Twine errMsg)
int64_t fromAPInt(llvm::APInt i)
std::unordered_map< ConstrainRef, ConstrainRefLatticeValue, ConstrainRef::Hash > TranslationMap