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);
107 for (
auto chunkStart : currIdxs) {
108 for (
size_t i = 0; i < chunkSz; i++) {
109 (void)extractedVal.getElemFlatIdx(i).update(
getElemFlatIdx(chunkStart + i));
113 return {extractedVal, mlir::ChangeResult::Change};
115 auto currVal = *
this;
116 auto res = mlir::ChangeResult::NoChange;
117 for (
auto &idx : indices) {
119 auto [newVal, transformRes] = currVal.elementwiseTransform(transform);
120 currVal = std::move(newVal);
123 return {currVal, res};
128 auto res = mlir::ChangeResult::NoChange;
133 for (
auto &[ref, val] : translation) {
134 auto it = currVal.find(ref);
135 if (it != currVal.end()) {
142std::pair<ConstrainRefLatticeValue, mlir::ChangeResult>
147 auto res = mlir::ChangeResult::NoChange;
148 if (newVal.isScalar()) {
150 for (
auto &ref : newVal.getScalarValue()) {
151 auto [_, inserted] = indexed.insert(transform(ref));
153 res |= mlir::ChangeResult::Change;
156 newVal.getScalarValue() = indexed;
158 for (
auto &elem : newVal.getArrayValue()) {
159 auto [newElem, elemRes] = elem->elementwiseTransform(transform);
164 return {newVal, res};
175 if (
auto blockArg = mlir::dyn_cast<mlir::BlockArgument>(val)) {
177 }
else if (
auto defOp = val.getDefiningOp()) {
178 if (
auto feltConst = mlir::dyn_cast<FeltConstantOp>(defOp)) {
180 }
else if (
auto constIdx = mlir::dyn_cast<mlir::arith::ConstantIndexOp>(defOp)) {
182 }
else if (
auto readConst = mlir::dyn_cast<ConstReadOp>(defOp)) {
186 return mlir::failure();
190 os <<
"ConstrainRefLattice { ";
191 for (
auto mit = valMap.begin(); mit != valMap.end();) {
192 auto &[val, latticeVal] = *mit;
193 os <<
"\n (" << val <<
") => " << latticeVal;
195 if (mit != valMap.end()) {
205 auto res = mlir::ChangeResult::NoChange;
207 for (
auto &[v, s] : rhs) {
214 auto it = valMap.find(v);
215 if (it == valMap.end()) {
217 if (mlir::succeeded(sourceRef)) {
226 auto op = this->getPoint().get<mlir::Operation *>();
227 if (
auto retOp = mlir::dyn_cast<function::ReturnOp>(op)) {
228 if (i >= retOp.getNumOperands()) {
229 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.
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 ConstrainRefLatticeValue &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