23#include <mlir/Analysis/DataFlowFramework.h>
24#include <mlir/Dialect/Arith/IR/Arith.h>
25#include <mlir/Pass/AnalysisManager.h>
27#include <llvm/ADT/ArrayRef.h>
28#include <llvm/ADT/DynamicAPInt.h>
29#include <llvm/ADT/EquivalenceClasses.h>
30#include <llvm/ADT/TypeSwitch.h>
33#include <unordered_set>
43 using IndexRange = std::pair<llvm::DynamicAPInt, llvm::DynamicAPInt>;
56 return std::holds_alternative<SymbolLookupResult<component::MemberDefOp>>(index) ||
57 std::holds_alternative<component::MemberDefOp>(index);
60 ensure(
isMember(),
"SourceRefIndex: member requested but not contained");
61 if (std::holds_alternative<component::MemberDefOp>(index)) {
62 return std::get<component::MemberDefOp>(index);
64 return std::get<SymbolLookupResult<component::MemberDefOp>>(index).get();
67 bool isIndex()
const {
return std::holds_alternative<llvm::DynamicAPInt>(index); }
69 ensure(
isIndex(),
"SourceRefIndex: index requested but not contained");
70 return std::get<llvm::DynamicAPInt>(index);
73 bool isIndexRange()
const {
return std::holds_alternative<IndexRange>(index); }
76 return std::get<IndexRange>(index);
80 void print(mlir::raw_ostream &os)
const;
91 return index == rhs.index;
115static inline mlir::raw_ostream &
operator<<(mlir::raw_ostream &os,
const SourceRefIndex &rhs) {
134 using Path = std::vector<SourceRefIndex>;
140 enum class SortCategory {
150 template <
typename OpT>
static mlir::Value getSingleResultValue(OpT op) {
151 ensure(op,
"SourceRef requires a non-null operation");
152 ensure(op->getNumResults() == 1,
"SourceRef expects a single-result operation");
153 return op->getResult(0);
156 static mlir::Value getRootResultValue(mlir::OpResult result) {
159 felt::FeltConstantOp, mlir::arith::ConstantIndexOp, mlir::arith::ConstantIntOp,
160 polymorphic::ConstReadOp>(result.getOwner()),
161 "SourceRef rooted OpResult constructors must not be used for constant values"
166 template <
typename OpT> mlir::FailureOr<OpT> getDefiningOp()
const {
167 if (
auto op = llvm::dyn_cast_if_present<OpT>(value.getDefiningOp())) {
170 return mlir::failure();
173 SourceRef(mlir::Value sourceValue,
bool isConstantStorage,
Path sourcePath = {})
174 : value(sourceValue), path(std::move(sourcePath)), constant(isConstantStorage) {
175 ensure(value !=
nullptr,
"SourceRef requires a non-null value");
176 ensure(!constant || this->path.empty(),
"constant SourceRef cannot have a path");
179 Path &getPathMut() {
return path; }
180 const void *getAsOpaquePointer()
const {
return value.getAsOpaquePointer(); }
181 SortCategory getSortCategory()
const;
182 llvm::StringRef getTemplateConstantName()
const;
183 std::strong_ordering compareWithinCategory(
const SourceRef &rhs, SortCategory category)
const;
187 static std::vector<SourceRef>
191 static std::vector<SourceRef>
196 static std::vector<SourceRef>
203 :
SourceRef(getSingleResultValue(createOp), false, p) {}
205 :
SourceRef(getSingleResultValue(nondet), false, p) {}
207 :
SourceRef(getRootResultValue(rootResult), false, p) {}
212 : SourceRef(getSingleResultValue(c), true) {}
214 : SourceRef(getSingleResultValue(c), true) {}
216 : SourceRef(getSingleResultValue(c), true) {}
221 return isConstant() && llvm::isa_and_present<felt::FeltConstantOp>(value.getDefiningOp());
225 llvm::isa_and_present<mlir::arith::ConstantIndexOp>(value.getDefiningOp());
228 return isConstant() && llvm::isa_and_present<polymorphic::ConstReadOp>(value.getDefiningOp());
244 mlir::FailureOr<mlir::Value>
getRoot()
const {
248 return mlir::failure();
254 return mlir::failure();
257 if (
auto blockArg = llvm::dyn_cast<mlir::BlockArgument>(value)) {
260 return mlir::failure();
264 if (succeeded(blockArg)) {
265 return blockArg->getArgNumber();
267 return mlir::failure();
272 return getDefiningOp<component::CreateStructOp>();
276 mlir::FailureOr<NonDetOp>
getNonDetOp()
const {
return getDefiningOp<NonDetOp>(); }
279 mlir::FailureOr<function::CallOp>
getCallOp()
const {
return getDefiningOp<function::CallOp>(); }
282 auto feltConst = getDefiningOp<felt::FeltConstantOp>();
283 if (succeeded(feltConst)) {
284 llvm::APInt i = feltConst->getValue();
287 return mlir::failure();
290 auto indexConst = getDefiningOp<mlir::arith::ConstantIndexOp>();
291 if (succeeded(indexConst)) {
292 return llvm::DynamicAPInt(indexConst->value());
294 return mlir::failure();
298 if (succeeded(feltVal)) {
302 if (succeeded(indexVal)) {
305 return mlir::failure();
315 mlir::FailureOr<std::vector<SourceRefIndex>>
getSuffix(
const SourceRef &prefix)
const;
328 return mlir::failure();
331 copy.getPathMut().pop_back();
336 std::vector<SourceRef>
341 return mlir::failure();
344 copy.getPathMut().push_back(r);
348 mlir::FailureOr<SourceRef>
createChild(
const SourceRef &other)
const {
350 if (failed(idxVal)) {
351 return mlir::failure();
356 [[deprecated(
"Use getPath() instead")]]
361 llvm::ArrayRef<SourceRefIndex>
getPath()
const {
return path; }
363 void print(mlir::raw_ostream &os)
const;
368 bool operator!=(
const SourceRef &rhs)
const {
return !(*
this == rhs); }
374 size_t operator()(
const SourceRef &val)
const;
377 friend struct llvm::DenseMapInfo<SourceRef>;
389class SourceRefSet :
public std::unordered_set<SourceRef, SourceRef::Hash> {
390 using Base = std::unordered_set<SourceRef, SourceRef::Hash>;
402 "SourceRefSet must satisfy the ScalarLatticeValue requirements"
409template <>
struct DenseMapInfo<
llzk::SourceRef> {
411 return llzk::SourceRef(mlir::BlockArgument(
reinterpret_cast<mlir::detail::ValueImpl *
>(1)));
414 return llzk::SourceRef(mlir::BlockArgument(
reinterpret_cast<mlir::detail::ValueImpl *
>(2)));
418 return llvm::hash_value(ref.getAsOpaquePointer());
This file implements helper methods for constructing DynamicAPInts.
void print(llvm::raw_ostream &os) const
Defines an index into an LLZK object.
std::strong_ordering operator<=>(const SourceRefIndex &rhs) const
bool operator==(const SourceRefIndex &rhs) const
bool isIndexRange() const
SourceRefIndex(const llvm::DynamicAPInt &i)
SourceRefIndex(const llvm::APInt &low, const llvm::APInt &high)
SourceRefIndex(const llvm::APInt &i)
llvm::DynamicAPInt getIndex() const
void print(mlir::raw_ostream &os) const
IndexRange getIndexRange() const
component::MemberDefOp getMember() const
SourceRefIndex(SymbolLookupResult< component::MemberDefOp > f)
SourceRefIndex(IndexRange r)
SourceRefIndex(int64_t i)
SourceRefIndex(component::MemberDefOp f)
SourceRefSet & join(const SourceRefSet &rhs)
friend mlir::raw_ostream & operator<<(mlir::raw_ostream &os, const SourceRefSet &rhs)
A reference to a "source", which is the base value from which other SSA values are derived.
bool isIntegerVal() const
bool isBlockArgument() const
mlir::FailureOr< SourceRef > createChild(const SourceRefIndex &r) const
std::vector< SourceRef > getAllChildren(mlir::SymbolTableCollection &tables, mlir::ModuleOp mod) const
Get all direct children of this SourceRef, assuming this ref is not a scalar.
mlir::FailureOr< std::vector< SourceRefIndex > > getSuffix(const SourceRef &prefix) const
If prefix is a valid prefix of this reference, return the suffix that remains after removing the pref...
mlir::FailureOr< SourceRef > getParentPrefix() const
Create a new reference that is the immediate prefix of this reference if possible.
mlir::FailureOr< function::CallOp > getCallOp() const
void print(mlir::raw_ostream &os) const
bool isCallResult() const
bool operator==(const SourceRef &rhs) const
mlir::FailureOr< component::CreateStructOp > getCreateStructOp() const
bool isConstantFelt() const
SourceRef(felt::FeltConstantOp c)
SourceRef(component::CreateStructOp createOp, Path p={})
llvm::ArrayRef< SourceRefIndex > getPath() const
bool isValidPrefix(const SourceRef &prefix) const
Returns true iff prefix is a valid prefix of this reference.
std::strong_ordering operator<=>(const SourceRef &rhs) const
SourceRef(mlir::BlockArgument b, Path p={})
mlir::FailureOr< llvm::DynamicAPInt > getConstantFeltValue() const
bool isConstantIndex() const
std::vector< SourceRefIndex > Path
static std::vector< SourceRef > getAllSourceRefs(mlir::SymbolTableCollection &tables, mlir::ModuleOp mod, const SourceRef &root)
Produce all possible SourceRefs that are present starting from the given root.
mlir::FailureOr< llvm::DynamicAPInt > getConstantValue() const
mlir::FailureOr< unsigned > getInputNum() const
mlir::FailureOr< NonDetOp > getNonDetOp() const
llvm::ArrayRef< SourceRefIndex > getPieces() const
SourceRef(mlir::arith::ConstantIndexOp c)
mlir::FailureOr< mlir::BlockArgument > getBlockArgument() const
SourceRef(NonDetOp nondet, Path p={})
SourceRef(mlir::OpResult rootResult, Path p={})
mlir::FailureOr< SourceRef > createChild(const SourceRef &other) const
mlir::FailureOr< llvm::DynamicAPInt > getConstantIndexValue() const
mlir::FailureOr< SourceRef > translate(const SourceRef &prefix, const SourceRef &other) const
Create a new reference with prefix replaced with other iff prefix is a valid prefix for this referenc...
mlir::FailureOr< mlir::Value > getConstant() const
SourceRef(polymorphic::ConstReadOp c)
bool isTemplateConstant() const
bool isTypeVarVal() const
bool operator!=(const SourceRef &rhs) const
mlir::FailureOr< mlir::Value > getRoot() const
bool isConstantInt() const
bool isCreateStructOp() const
mlir::Type getType() const
ExpressionValue mod(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
void ensure(bool condition, const llvm::Twine &errMsg)
DynamicAPInt toDynamicAPInt(StringRef str)
Interval operator<<(const Interval &lhs, const Interval &rhs)
static bool isEqual(const llzk::SourceRef &lhs, const llzk::SourceRef &rhs)
static unsigned getHashValue(const llzk::SourceRef &ref)
static llzk::SourceRef getTombstoneKey()
static llzk::SourceRef getEmptyKey()
size_t operator()(const SourceRefIndex &c) const
size_t operator()(const SourceRef &val) const