20#include <mlir/Analysis/DataFlow/DeadCodeAnalysis.h>
21#include <mlir/IR/Value.h>
23#include <llvm/Support/Debug.h>
26#include <unordered_set>
28#define DEBUG_TYPE "llzk-constrain-ref-lattice"
35using namespace component;
38using namespace polymorphic;
51std::pair<SourceRefLatticeValue, mlir::ChangeResult>
54 auto res = mlir::ChangeResult::NoChange;
55 if (newVal.isScalar()) {
56 res = newVal.translateScalar(translation);
58 for (
auto &elem : newVal.getArrayValue()) {
59 auto [newElem, elemRes] = elem->translate(translation);
67mlir::FailureOr<std::pair<SourceRefLatticeValue, mlir::ChangeResult>>
70 auto transform = [&idx](
const SourceRef &r) -> mlir::FailureOr<SourceRef> {
71 return r.createChild(idx);
76mlir::FailureOr<std::pair<SourceRefLatticeValue, mlir::ChangeResult>>
79 auto transform = [&idx](
const SourceRef &r) -> mlir::FailureOr<SourceRef> {
80 return r.createChild(idx);
85mlir::FailureOr<std::pair<SourceRefLatticeValue, mlir::ChangeResult>>
91 std::vector<size_t> currIdxs {0};
92 for (
unsigned i = 0; i < indices.size(); i++) {
93 const auto &idx = indices[i];
96 std::vector<size_t> newIdxs;
97 ensure(idx.isIndex() || idx.isIndexRange(),
"wrong type of index for array");
99 int64_t idxVal(idx.getIndex());
101 currIdxs.begin(), currIdxs.end(), std::back_inserter(newIdxs),
102 [&currDim, &idxVal](
size_t j) { return j * currDim + idxVal; }
105 auto [low, high] = idx.getIndexRange();
106 int64_t lowInt(low), highInt(high);
107 for (int64_t idxVal = lowInt; idxVal < highInt; idxVal++) {
109 currIdxs.begin(), currIdxs.end(), std::back_inserter(newIdxs),
110 [&currDim, &idxVal](
size_t j) { return j * currDim + idxVal; }
117 std::vector<int64_t> newArrayDims;
121 newArrayDims.push_back(dim);
124 if (newArrayDims.empty()) {
127 for (
auto idx : currIdxs) {
130 return std::make_pair(extractedVal, mlir::ChangeResult::Change);
134 for (
auto chunkStart : currIdxs) {
135 for (
size_t i = 0; i < chunkSz; i++) {
139 return std::make_pair(extractedVal, mlir::ChangeResult::Change);
142 auto currVal = *
this;
143 auto res = mlir::ChangeResult::NoChange;
144 for (
const auto &idx : indices) {
145 auto transform = [&idx](
const SourceRef &r) -> mlir::FailureOr<SourceRef> {
146 return r.createChild(idx);
148 auto transformedVal = currVal.elementwiseTransform(transform);
149 if (failed(transformedVal)) {
150 return mlir::failure();
152 auto [newVal, transformRes] = *transformedVal;
153 currVal = std::move(newVal);
156 return std::make_pair(currVal, res);
161 auto res = mlir::ChangeResult::NoChange;
169 for (
const SourceRef &currRef : currVal) {
170 for (
const auto &[prefix, replacementVal] : translation) {
171 if (currRef.isValidPrefix(prefix)) {
172 for (
const SourceRef &replacementPrefix : replacementVal.foldToScalar()) {
173 auto translatedRefRes = currRef.translate(prefix, replacementPrefix);
174 if (succeeded(translatedRefRes)) {
175 res |=
insert(*translatedRefRes);
184mlir::FailureOr<std::pair<SourceRefLatticeValue, mlir::ChangeResult>>
186 llvm::function_ref<mlir::FailureOr<SourceRef>(
const SourceRef &)> transform
189 auto res = mlir::ChangeResult::NoChange;
190 if (newVal.isScalar()) {
192 for (
const auto &ref : newVal.getScalarValue()) {
193 auto transformedRef = transform(ref);
194 if (failed(transformedRef)) {
195 return mlir::failure();
197 auto [_, inserted] = indexed.insert(*transformedRef);
199 res |= mlir::ChangeResult::Change;
202 newVal.getScalarValue() = indexed;
204 for (
auto &elem : newVal.getArrayValue()) {
205 auto transformedElem = elem->elementwiseTransform(transform);
206 if (failed(transformedElem)) {
207 return mlir::failure();
209 auto [newElem, elemRes] = *transformedElem;
210 (*elem) = std::move(newElem);
214 return std::make_pair(newVal, res);
225 if (
auto blockArg = llvm::dyn_cast<mlir::BlockArgument>(val)) {
227 }
else if (
auto *defOp = val.getDefiningOp()) {
228 if (
auto feltConst = llvm::dyn_cast<FeltConstantOp>(defOp)) {
230 }
else if (
auto constIdx = llvm::dyn_cast<mlir::arith::ConstantIndexOp>(defOp)) {
232 }
else if (
auto readConst = llvm::dyn_cast<ConstReadOp>(defOp)) {
234 }
else if (
auto structNew = llvm::dyn_cast<CreateStructOp>(defOp)) {
236 }
else if (
auto nonDet = llvm::dyn_cast<NonDetOp>(defOp)) {
238 }
else if (
auto createArray = llvm::dyn_cast<CreateArrayOp>(defOp)) {
239 return SourceRef(createArray->getResult(0));
240 }
else if (
auto newPod = llvm::dyn_cast<NewPodOp>(defOp)) {
242 }
else if (llvm::isa<function::CallOp>(defOp)) {
243 auto callResult = llvm::dyn_cast<mlir::OpResult>(val);
244 ensure(callResult !=
nullptr,
"function.call value should be an OpResult");
248 return mlir::failure();
252 if (
auto asVal = llvm::dyn_cast_if_present<Value>(v)) {
254 if (mlir::succeeded(sourceRef)) {
266 llvm::report_fatal_error(
"meet operation is not supported for SourceRefLattice");
267 return ChangeResult::NoChange;
271 os <<
"SourceRefLattice { " << value <<
" }";
275 return value.setValue(newValue);
286raw_ostream &
operator<<(raw_ostream &os, llvm::PointerUnion<mlir::Value, mlir::Operation *> ptr) {
287 if (
auto asVal = llvm::dyn_cast_if_present<Value>(ptr)) {
289 }
else if (
auto *asOp = llvm::dyn_cast_if_present<Operation *>(ptr)) {
292 os <<
"<<null PointerUnion>>";
Defines an index into an LLZK object.
A value at a given point of the SourceRefLattice.
mlir::FailureOr< std::pair< SourceRefLatticeValue, mlir::ChangeResult > > referencePodRecord(mlir::StringAttr recordName) const
Add the given pod recordName to the SourceRefs contained within this value.
mlir::FailureOr< std::pair< SourceRefLatticeValue, mlir::ChangeResult > > referenceMember(SymbolLookupResult< component::MemberDefOp > memberRef) const
Add the given memberRef to the SourceRefs contained within this value.
virtual mlir::FailureOr< std::pair< SourceRefLatticeValue, mlir::ChangeResult > > elementwiseTransform(llvm::function_ref< mlir::FailureOr< SourceRef >(const SourceRef &)> transform) const
Perform a recursive transformation over all elements of this value and return a new value with the mo...
mlir::ChangeResult insert(const SourceRef &rhs)
Directly insert the ref into this value.
std::pair< SourceRefLatticeValue, mlir::ChangeResult > translate(const TranslationMap &translation) const
For the refs contained in this value, translate them given the translation map and return the transfo...
mlir::FailureOr< std::pair< SourceRefLatticeValue, mlir::ChangeResult > > extract(const std::vector< SourceRefIndex > &indices) const
Perform an array.extract or array.read operation, depending on how many indices are provided.
SourceRefLatticeValue(ScalarTy s)
mlir::ChangeResult translateScalar(const TranslationMap &translation)
Translate this value using the translation map, assuming this value is a scalar.
Sparse SSA-value lattice for SourceRef propagation.
mlir::ChangeResult join(const AbstractSparseLattice &rhs) override
mlir::ChangeResult setValue(const LatticeValue &newValue)
mlir::ChangeResult meet(const AbstractSparseLattice &rhs) override
static SourceRefLatticeValue getDefaultValue(ValueTy v)
void print(mlir::raw_ostream &os) const override
static mlir::FailureOr< SourceRef > getSourceRef(mlir::Value val)
If val is the source of other values (i.e., a block argument, an allocation-like op result,...
llvm::PointerUnion< mlir::Value, mlir::Operation * > ValueTy
SourceRefLatticeValue LatticeValue
A reference to a "source", which is the base value from which other SSA values are derived.
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 SourceRefLatticeValue &rhs)
const ScalarTy & getScalarValue() const
const SourceRefLatticeValue & getElemFlatIdx(size_t i) const
void print(mlir::raw_ostream &os) const
raw_ostream & operator<<(raw_ostream &os, llvm::PointerUnion< mlir::Value, mlir::Operation * > ptr)
void ensure(bool condition, const llvm::Twine &errMsg)
Interval operator<<(const Interval &lhs, const Interval &rhs)
std::unordered_map< SourceRef, SourceRefLatticeValue, SourceRef::Hash > TranslationMap