24#include <mlir/Analysis/DataFlowFramework.h>
25#include <mlir/Dialect/Arith/IR/Arith.h>
26#include <mlir/Pass/AnalysisManager.h>
28#include <llvm/ADT/ArrayRef.h>
29#include <llvm/ADT/DynamicAPInt.h>
30#include <llvm/ADT/EquivalenceClasses.h>
31#include <llvm/ADT/TypeSwitch.h>
34#include <unordered_set>
44 using IndexRange = std::pair<llvm::DynamicAPInt, llvm::DynamicAPInt>;
58 return std::holds_alternative<SymbolLookupResult<component::MemberDefOp>>(index) ||
59 std::holds_alternative<component::MemberDefOp>(index);
62 ensure(
isMember(),
"SourceRefIndex: member requested but not contained");
63 if (std::holds_alternative<component::MemberDefOp>(index)) {
64 return std::get<component::MemberDefOp>(index);
66 return std::get<SymbolLookupResult<component::MemberDefOp>>(index).get();
69 bool isPodRecord()
const {
return std::holds_alternative<mlir::StringAttr>(index); }
72 return std::get<mlir::StringAttr>(index);
76 bool isIndex()
const {
return std::holds_alternative<llvm::DynamicAPInt>(index); }
78 ensure(
isIndex(),
"SourceRefIndex: index requested but not contained");
79 return std::get<llvm::DynamicAPInt>(index);
82 bool isIndexRange()
const {
return std::holds_alternative<IndexRange>(index); }
85 return std::get<IndexRange>(index);
89 void print(mlir::raw_ostream &os)
const;
100 return index == rhs.index;
125 llvm::DynamicAPInt, IndexRange>
129static inline mlir::raw_ostream &
operator<<(mlir::raw_ostream &os,
const SourceRefIndex &rhs) {
148 using Path = std::vector<SourceRefIndex>;
154 enum class SortCategory : std::uint8_t {
164 template <
typename OpT>
static mlir::Value getSingleResultValue(OpT op) {
165 ensure(op,
"SourceRef requires a non-null operation");
166 ensure(op->getNumResults() == 1,
"SourceRef expects a single-result operation");
167 return op->getResult(0);
170 static mlir::Value getRootResultValue(mlir::OpResult result) {
173 felt::FeltConstantOp, mlir::arith::ConstantIndexOp, mlir::arith::ConstantIntOp,
174 polymorphic::ConstReadOp>(result.getOwner()),
175 "SourceRef rooted OpResult constructors must not be used for constant values"
180 template <
typename OpT> mlir::FailureOr<OpT> getDefiningOp()
const {
181 if (
auto op = llvm::dyn_cast_if_present<OpT>(value.getDefiningOp())) {
184 return mlir::failure();
187 SourceRef(mlir::Value sourceValue,
bool isConstantStorage,
Path sourcePath = {})
188 : value(sourceValue), path(std::move(sourcePath)), constant(isConstantStorage) {
189 ensure(value !=
nullptr,
"SourceRef requires a non-null value");
190 ensure(!constant || this->path.empty(),
"constant SourceRef cannot have a path");
193 Path &getPathMut() {
return path; }
194 const void *getAsOpaquePointer()
const {
return value.getAsOpaquePointer(); }
195 SortCategory getSortCategory()
const;
196 llvm::StringRef getTemplateConstantName()
const;
197 std::strong_ordering compareWithinCategory(
const SourceRef &rhs, SortCategory category)
const;
201 static std::vector<SourceRef>
205 static std::vector<SourceRef>
210 static std::vector<SourceRef>
218 :
SourceRef(getSingleResultValue(createOp), false, std::move(p)) {}
220 :
SourceRef(getSingleResultValue(nondet), false, std::move(p)) {}
222 :
SourceRef(getRootResultValue(rootResult), false, std::move(p)) {}
227 : SourceRef(getSingleResultValue(c), true) {}
229 : SourceRef(getSingleResultValue(c), true) {}
231 : SourceRef(getSingleResultValue(c), true) {}
236 return isConstant() && llvm::isa_and_present<felt::FeltConstantOp>(value.getDefiningOp());
240 llvm::isa_and_present<mlir::arith::ConstantIndexOp>(value.getDefiningOp());
243 return isConstant() && llvm::isa_and_present<polymorphic::ConstReadOp>(value.getDefiningOp());
259 mlir::FailureOr<mlir::Value>
getRoot()
const {
263 return mlir::failure();
269 return mlir::failure();
272 if (
auto blockArg = llvm::dyn_cast<mlir::BlockArgument>(value)) {
275 return mlir::failure();
279 if (succeeded(blockArg)) {
280 return blockArg->getArgNumber();
282 return mlir::failure();
287 return getDefiningOp<component::CreateStructOp>();
291 mlir::FailureOr<NonDetOp>
getNonDetOp()
const {
return getDefiningOp<NonDetOp>(); }
294 mlir::FailureOr<function::CallOp>
getCallOp()
const {
return getDefiningOp<function::CallOp>(); }
297 auto feltConst = getDefiningOp<felt::FeltConstantOp>();
298 if (succeeded(feltConst)) {
299 llvm::APInt i = feltConst->getValue();
302 return mlir::failure();
305 auto indexConst = getDefiningOp<mlir::arith::ConstantIndexOp>();
306 if (succeeded(indexConst)) {
307 return llvm::DynamicAPInt(indexConst->value());
309 return mlir::failure();
313 if (succeeded(feltVal)) {
317 if (succeeded(indexVal)) {
320 return mlir::failure();
333 mlir::FailureOr<std::vector<SourceRefIndex>>
getSuffix(
const SourceRef &prefix)
const;
346 return mlir::failure();
349 copy.getPathMut().pop_back();
354 std::vector<SourceRef>
359 return mlir::failure();
362 copy.getPathMut().push_back(r);
366 mlir::FailureOr<SourceRef>
createChild(
const SourceRef &other)
const {
368 if (failed(idxVal)) {
369 return mlir::failure();
374 [[deprecated(
"Use getPath() instead")]]
379 llvm::ArrayRef<SourceRefIndex>
getPath()
const {
return path; }
381 void print(mlir::raw_ostream &os)
const;
386 bool operator!=(
const SourceRef &rhs)
const {
return !(*
this == rhs); }
392 size_t operator()(
const SourceRef &val)
const;
395 friend struct llvm::DenseMapInfo<SourceRef>;
407class SourceRefSet :
public std::unordered_set<SourceRef, SourceRef::Hash> {
408 using Base = std::unordered_set<SourceRef, SourceRef::Hash>;
420 "SourceRefSet must satisfy the ScalarLatticeValue requirements"
427template <>
struct DenseMapInfo<
llzk::SourceRef> {
429 return llzk::SourceRef(mlir::BlockArgument(
reinterpret_cast<mlir::detail::ValueImpl *
>(1)));
432 return llzk::SourceRef(mlir::BlockArgument(
reinterpret_cast<mlir::detail::ValueImpl *
>(2)));
436 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
mlir::StringAttr getPodRecordNameAttr() 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
bool overlaps(const SourceRefIndex &rhs) const
Return true when these path components select any common storage.
component::MemberDefOp getMember() const
SourceRefIndex(mlir::StringAttr recordName)
SourceRefIndex(SymbolLookupResult< component::MemberDefOp > f)
SourceRefIndex(IndexRange r)
SourceRefIndex(int64_t i)
SourceRefIndex(component::MemberDefOp f)
llvm::StringRef getPodRecordName() const
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
bool overlaps(const SourceRef &rhs) const
Return true when both references select overlapping storage at the same path depth.
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