28#include <mlir/Dialect/Arith/IR/Arith.h>
29#include <mlir/Dialect/SCF/IR/SCF.h>
30#include <mlir/IR/IRMapping.h>
31#include <mlir/IR/Verifier.h>
32#include <mlir/Interfaces/SideEffectInterfaces.h>
34#include <llvm/ADT/DenseSet.h>
35#include <llvm/ADT/TypeSwitch.h>
38#define GEN_PASS_DEF_CONSTRAINTFLATTENINGPASS
51class ConstraintElaborator {
55 SymbolTableCollection tables;
60 std::optional<ConstraintStorage> storage;
63 llvm::DenseSet<Operation *> nonSignalReads;
64 SmallVector<FuncDefOp> activeCalls;
66 static bool aggregate(Type type) {
return isa<array::ArrayType, pod::PodType>(type); }
70 auto found = frame.find(
source);
71 assert(found != frame.end() &&
"missing source binding");
72 const auto *value = std::get_if<Value>(&found->second);
73 assert(value && *value &&
"expected a scalar SSA binding");
78 FailureOr<Value> readStorage(Value value, ArrayRef<Attribute> path, Type type, Operation *site) {
79 while (!path.empty()) {
80 if (
auto arrayType = dyn_cast<array::ArrayType>(value.getType())) {
81 unsigned rank = arrayType.getShape().size();
82 if (path.size() < rank) {
83 return constraintError(site,
"storage path does not identify a scalar leaf");
85 SmallVector<Value> indices;
86 for (Attribute step : path.take_front(rank)) {
87 auto index = dyn_cast<IntegerAttr>(step);
92 arith::ConstantIndexOp::create(builder, site->getLoc(), index.getInt())
96 builder, site->getLoc(), arrayType.getElementType(), value, indices
98 path = path.drop_front(rank);
101 auto podType = dyn_cast<pod::PodType>(value.getType());
102 auto name = dyn_cast<StringAttr>(path.front());
103 if (!podType || !name) {
106 auto recordType = podType.getRecord(name.getValue(), [site] {
107 return site->emitError(CONSTRAINT_DIAGNOSTIC_PREFIX);
109 if (failed(recordType)) {
113 path = path.drop_front();
115 if (value.getType() != type) {
118 auto info = storage->describe(value, site);
122 if (!isa<StructType>(type) && !info->signal) {
123 nonSignalReads.insert(value.getDefiningOp());
128 FailureOr<Value> load(AccessPath path, Operation *site) {
129 return bindings.load(
130 path, site, [
this](Value root, ArrayRef<Attribute> pathSteps, Type type, Operation *at) {
131 return readStorage(root, pathSteps, type, at);
137 FailureOr<BoundValue> copy(
BoundValue source, Operation *site, Value input = {}) {
138 auto *path = std::get_if<AccessPath>(&
source);
142 auto target = bindings.create(path->
type, input);
143 if (failed(transfer(target, *path, site))) {
149 LogicalResult transfer(AccessPath target, AccessPath
source, Operation *site) {
150 return bindings.transfer(
152 [
this](Value root, ArrayRef<Attribute> pathSteps, Type type, Operation *at) {
153 return readStorage(root, pathSteps, type, at);
159 LogicalResult assign(AccessPath target,
BoundValue source, Operation *site) {
160 if (
auto *value = std::get_if<Value>(&
source)) {
161 bindings.store(target, *value);
164 return transfer(target, std::get<AccessPath>(
source), site);
168 FailureOr<AccessPath>
169 arrayPath(Value
source, ValueRange indices,
Environment &frame, Operation *site) {
170 auto path = std::get<AccessPath>(frame.lookup(
source));
171 for (Value index : indices) {
172 auto coordinate = facts.integer(scalar(index, frame));
174 return constraintError(site,
"array path requires compile-time indices");
176 auto selected = bindings.select(path, builder.getIndexAttr(*coordinate), site);
177 if (failed(selected)) {
186 FailureOr<AccessPath> podPath(Value
source, StringRef name,
Environment &frame, Operation *site) {
187 auto path = std::get<AccessPath>(frame.lookup(
source));
188 return bindings.select(path, builder.getStringAttr(name), site);
192 LogicalResult readPath(Value result, AccessPath path,
Environment &frame, Operation *site) {
193 if (aggregate(path.
type)) {
195 if (failed(copied)) {
198 frame[result] = *copied;
201 auto value = load(path, site);
205 frame[result] = *value;
210 LogicalResult writePath(AccessPath path, Value value,
Environment &frame, Operation *site) {
211 if (failed(bindings.writable(path, site))) {
214 return assign(path, frame.lookup(value), site);
218 LogicalResult arrayNew(array::CreateArrayOp op,
Environment &frame) {
219 auto path = bindings.create(op.getType());
225 return bindings.elements(path, op, [
this, &op, &frame, &next](AccessPath item) {
226 return assign(item, frame.lookup(op.
getElements()[next++]), op);
231 LogicalResult podNew(pod::NewPodOp op,
Environment &frame) {
232 auto path = bindings.create(op.getType());
235 auto field = podPath(op.
getResult(), record.name, frame, op);
236 if (failed(field) || failed(assign(*field, frame.lookup(record.value), op))) {
244 LogicalResult memberRead(MemberReadOp op,
Environment &frame) {
246 return constraintError(op,
"member read requires concrete non-column component storage");
250 auto emitted = llvm::cast<MemberReadOp>(builder.clone(*op, mapping));
251 auto info = storage->describe(emitted.getResult(), op);
255 if (aggregate(op.getType())) {
256 frame[op.getResult()] = bindings.create(info->memberType, {}, emitted.getResult());
258 frame[op.getResult()] = emitted.getResult();
259 if (!isa<StructType>(op.getType()) && !info->signal) {
260 nonSignalReads.insert(emitted);
267 LogicalResult globalRead(global::GlobalReadOp op,
Environment &frame) {
271 return constraintError(op,
"global read requires an initialized constant");
273 Attribute initial =
definition->get().getInitialValue();
274 if (!aggregate(op.getType())) {
275 auto value = constant(initial, op);
279 frame[op.getResult()] = *value;
282 auto values = dyn_cast<ArrayAttr>(initial);
283 if (!values || !isa<array::ArrayType>(op.getType())) {
284 return constraintError(op,
"unsupported aggregate global initializer");
286 auto path = bindings.create(op.getType());
287 frame[op.getResult()] = path;
289 return bindings.walk(path, op, [
this, &op, values, &next](AccessPath item) -> LogicalResult {
290 if (next >= values.size()) {
291 return constraintError(op,
"global initializer does not match aggregate leaves");
293 auto value = constant(values[next++], op);
297 bindings.store(item, *value);
303 FailureOr<Value> constant(Attribute attribute, Operation *site) {
304 if (
auto felt = dyn_cast<felt::FeltConstAttr>(attribute)) {
307 if (
auto integer = dyn_cast<IntegerAttr>(attribute)) {
308 return Value(arith::ConstantOp::create(builder, site->getLoc(), integer));
314 FailureOr<IRMapping> scalarMapping(Operation &op,
const Environment &frame) {
316 for (Value operand : op.getOperands()) {
317 if (aggregate(operand.getType())) {
320 mapping.map(operand, scalar(operand, frame));
327 static bool isFieldExpression(Operation &op) {
329 felt::FeltConstantOp, felt::AddFeltOp, felt::SubFeltOp, felt::MulFeltOp, felt::NegFeltOp>(
336 static bool isIntegerExpression(Operation &op) {
337 return !op.getNumRegions() && op.getNumResults() && isMemoryEffectFree(&op) &&
338 llvm::all_of(op.getResultTypes(), [](Type type) {
339 return isa<IndexType, IntegerType>(type);
345 LogicalResult emitStructural(Operation &op, IRMapping &mapping,
Environment &frame) {
346 Operation *emitted = builder.clone(op, mapping);
347 for (
auto [
source, result] : llvm::zip_equal(op.getResults(), emitted->getResults())) {
348 if (
auto constant = dyn_cast_or_null<IntegerAttr>(facts.known(result))) {
349 frame[
source] = Value(arith::ConstantOp::create(builder, op.getLoc(), constant));
351 if (
auto conversion = dyn_cast<cast::FeltToIndexOp>(emitted);
352 conversion && !isMemoryEffectFree(conversion)) {
353 return constraintError(&op,
"assert cast requires a statically valid index conversion");
365 LogicalResult evaluateNonNative(Operation &op,
Environment &frame) {
366 if (op.getNumRegions() || !op.getNumResults() || !isMemoryEffectFree(&op) ||
367 !llvm::all_of(op.getResultTypes(), [](Type type) { return isa<felt::FeltType>(type); })) {
368 return constraintError(&op,
"lower non-native operations before constraint flattening");
370 auto mapping = scalarMapping(op, frame);
371 if (failed(mapping)) {
377 if (
auto shift = dyn_cast<felt::ShlFeltOp>(op); shift &&
378 !facts.known(mapping->lookup(shift.getLhs())) &&
379 facts.known(mapping->lookup(shift.getRhs()))) {
380 Value lhs = mapping->lookup(shift.getLhs());
381 auto one = felt::FeltConstAttr::get(
382 op.getContext(), llvm::DynamicAPInt(1), llvm::cast<felt::FeltType>(shift.getType())
385 Operation *factor = builder.clone(op, *mapping);
386 auto constant = dyn_cast_or_null<felt::FeltConstAttr>(facts.known(factor->getResult(0)));
388 return constraintError(&op,
"lower non-native operations before constraint flattening");
391 frame[shift.getResult()] =
395 Operation *emitted = builder.clone(op, *mapping);
396 for (
auto [
source, result] : llvm::zip_equal(op.getResults(), emitted->getResults())) {
397 auto constant = dyn_cast_or_null<felt::FeltConstAttr>(facts.known(result));
398 if (!constant || constant.getType() != result.getType()) {
399 return constraintError(&op,
"lower non-native operations before constraint flattening");
408 LogicalResult emit(Operation &op,
Environment &frame) {
409 if (
auto assertion = dyn_cast<boolean::AssertOp>(op)) {
410 auto condition = facts.integer(scalar(assertion.getCondition(), frame));
411 return condition && *condition ? success()
414 bool equality = isa<constrain::EmitEqualityOp>(op);
415 if (equality && !isa<felt::FeltType>(op.getOperand(0).getType())) {
416 return constraintError(&op,
"equality constraints require scalar felt operands");
418 bool structural = isIntegerExpression(op) || isa<cast::FeltToIndexOp>(op);
419 if (!(equality || structural || isFieldExpression(op) || isa<cast::IntToFeltOp>(op))) {
420 if (op.hasTrait<function::NotFieldNative>() || isa<felt::DivFeltOp>(op)) {
421 return evaluateNonNative(op, frame);
423 if (isa<constrain::EmitContainmentOp>(op)) {
425 &op,
"unsupported operation 'constrain.in': containment constraints require lowering "
426 "before constraint flattening"
429 if (llvm::any_of(op.getResultTypes(), [](Type type) { return isa<FloatType>(type); })) {
431 &op,
"unsupported: floating-point results are not supported in flattened constraints"
435 &op,
"unsupported operation '" + op.getName().getStringRef() +
436 "': expected a supported field expression or pure integer computation"
439 auto mapping = scalarMapping(op, frame);
440 if (failed(mapping)) {
444 return emitStructural(op, *mapping, frame);
446 Operation *emitted = builder.clone(op, *mapping);
447 for (
auto [
source, result] : llvm::zip_equal(op.getResults(), emitted->getResults())) {
453 static void bind(ValueRange arguments, ArrayRef<BoundValue> values,
Environment &frame) {
454 for (
auto [argument, value] : llvm::zip_equal(arguments, values)) {
455 frame[argument] = value;
461 LogicalResult invoke(
462 FuncDefOp callee, ArrayRef<BoundValue> arguments, Operation *site,
463 SmallVectorImpl<BoundValue> &results
466 return constraintError(site,
"callee must be concrete, defined, and single-block");
468 if (llvm::is_contained(activeCalls, callee)) {
471 if (callee.getNumArguments() != arguments.size()) {
474 if (activeCalls.size() >= 256) {
478 for (
auto [parameter, argument] : llvm::zip_equal(callee.getArguments(), arguments)) {
479 frame[parameter] = argument;
480 if (
const auto *path = std::get_if<AccessPath>(&argument)) {
481 bindings.protect(*path);
484 activeCalls.push_back(callee);
485 auto status = expand(callee.
getBody().front(), frame, results);
486 activeCalls.pop_back();
487 for (
const auto &argument : arguments) {
488 if (
const auto *path = std::get_if<AccessPath>(&argument)) {
489 bindings.unprotect(*path);
496 LogicalResult call(CallOp op,
Environment &frame) {
497 SmallVector<BoundValue> arguments;
499 arguments.push_back(frame.lookup(argument));
503 auto info = storage->describe(std::get<Value>(arguments.front()), op);
507 auto owner = info->definition;
508 target = owner ? owner.getConstrainFuncOp() : FuncDefOp();
514 target = found->get();
516 SmallVector<BoundValue> results;
517 if (failed(invoke(target, arguments, op, results))) {
520 if (results.size() != op.getNumResults()) {
523 bind(op.getResults(), results, frame);
528 LogicalResult branch(scf::IfOp op,
Environment &frame) {
529 auto condition = facts.integer(scalar(op.getCondition(), frame));
532 op,
"symbolic i1 condition requires an explicit field selector representation"
535 auto ®ion = *condition ? op.getThenRegion() : op.getElseRegion();
536 SmallVector<BoundValue> results;
537 if (!region.empty() && failed(expand(region.front(), frame, results))) {
540 bind(op.getResults(), results, frame);
545 LogicalResult forLoop(scf::ForOp op,
Environment &frame) {
546 auto lower = facts.integer(scalar(op.getLowerBound(), frame));
547 auto upper = facts.integer(scalar(op.getUpperBound(), frame));
548 auto step = facts.integer(scalar(op.getStep(), frame));
549 if (!lower || !upper || !step || *step <= 0 || op.getUnsignedCmp()) {
550 return constraintError(op,
"requires signed static for bounds and a positive step");
552 SmallVector<BoundValue> carried;
553 for (Value value : op.getInitArgs()) {
554 carried.push_back(frame.lookup(value));
556 for (int64_t i = *lower; i < *upper;) {
557 frame[op.getInductionVar()] = Value(
558 arith::ConstantOp::create(
559 builder, op.getLoc(), builder.getIntegerAttr(op.getInductionVar().getType(), i)
562 bind(op.getRegionIterArgs(), carried, frame);
564 if (failed(expand(*op.getBody(), frame, carried))) {
572 bind(op.getResults(), carried, frame);
577 LogicalResult whileLoop(scf::WhileOp op,
Environment &frame) {
579 return constraintError(op,
"cannot execute an always-true while loop");
581 SmallVector<BoundValue> carried;
582 for (Value value : op.getInits()) {
583 carried.push_back(frame.lookup(value));
586 bind(op.getBeforeArguments(), carried, frame);
587 SmallVector<BoundValue> condition;
588 if (failed(expand(op.getBefore().front(), frame, condition))) {
591 auto test = facts.integer(std::get<Value>(condition.front()));
593 return constraintError(op,
"while condition must be statically known");
595 carried.assign(condition.begin() + 1, condition.end());
599 bind(op.getAfterArguments(), carried, frame);
601 if (failed(expand(op.getAfter().front(), frame, carried))) {
605 bind(op.getResults(), carried, frame);
610 template <
typename ReadOp> LogicalResult arrayRead(ReadOp op,
Environment &frame) {
611 auto path = arrayPath(op.getArrRef(), op.getIndices(), frame, op);
615 return readPath(op.getResult(), *path, frame, op);
619 template <
typename WriteOp> LogicalResult arrayWrite(WriteOp op,
Environment &frame) {
620 auto path = arrayPath(op.getArrRef(), op.getIndices(), frame, op);
624 return writePath(*path, op.getRvalue(), frame, op);
628 LogicalResult podRead(pod::ReadPodOp op,
Environment &frame) {
633 return readPath(op.
getResult(), *path, frame, op);
637 LogicalResult podWrite(pod::WritePodOp op,
Environment &frame) {
642 return writePath(*path, op.
getValue(), frame, op);
646 LogicalResult arrayLength(array::ArrayLengthOp op,
Environment &frame) {
647 auto path = std::get<AccessPath>(frame.lookup(op.
getArrRef()));
648 auto type = dyn_cast<array::ArrayType>(path.
type);
649 auto dimension = facts.integer(scalar(op.
getDim(), frame));
650 if (!type || !dimension || *dimension < 0 || uint64_t(*dimension) >= type.getShape().size()) {
651 return constraintError(op,
"array dimension must be statically known and in bounds");
653 int64_t size = type.getShape()[*dimension];
657 frame[op.getResult()] = Value(arith::ConstantIndexOp::create(builder, op.getLoc(), size));
662 LogicalResult select(arith::SelectOp op,
Environment &frame) {
663 auto condition = facts.integer(scalar(op.getCondition(), frame));
666 op,
"symbolic select requires an explicit field selector representation"
669 frame[op.getResult()] = frame.lookup(*condition ? op.getTrueValue() : op.getFalseValue());
675 LogicalResult dispatch(Operation &op,
Environment &frame) {
676 return llvm::TypeSwitch<Operation *, LogicalResult>(&op)
677 .Case<scf::IfOp>([
this, &frame](
auto control) {
return branch(control, frame); })
678 .Case<scf::ForOp>([
this, &frame](
auto control) {
return forLoop(control, frame); })
679 .Case<scf::WhileOp>([
this, &frame](
auto control) {
return whileLoop(control, frame); })
680 .Case<CallOp>([
this, &frame](
auto function) {
return call(function, frame); })
681 .Case<arith::SelectOp>([
this, &frame](
auto choice) {
return select(choice, frame); })
682 .Case<UnifiableCastOp>([&frame](
auto conversion) {
683 frame[conversion.getResult()] = frame.lookup(conversion.getInput());
686 .Case<global::GlobalReadOp>([
this, &frame](
auto read) {
return globalRead(read, frame); })
687 .Case<MemberReadOp>([
this, &frame](
auto read) {
return memberRead(read, frame); })
688 .Case<MemberWriteOp>([](
auto write) {
689 return constraintError(write,
"cannot write to original component storage");
691 .Case<array::CreateArrayOp>([
this, &frame](
auto allocation) {
692 return arrayNew(allocation, frame);
694 .Case<NonDetOp>([
this, &frame](
auto allocation) {
695 if (!aggregate(allocation.getType())) {
696 return emit(*allocation, frame);
699 frame[allocation.getResult()] = bindings.create(allocation.getType());
702 .Case<pod::NewPodOp>([
this, &frame](
auto allocation) {
return podNew(allocation, frame); })
703 .Case<array::ReadArrayOp, array::ExtractArrayOp>([
this, &frame](
auto read) {
704 return arrayRead(read, frame);
706 .Case<array::WriteArrayOp, array::InsertArrayOp>([
this, &frame](
auto write) {
707 return arrayWrite(write, frame);
709 .Case<pod::ReadPodOp>([
this, &frame](
auto read) {
return podRead(read, frame); })
710 .Case<pod::WritePodOp>([
this, &frame](
auto write) {
return podWrite(write, frame); })
711 .Case<array::ArrayLengthOp>([
this, &frame](
auto length) {
712 return arrayLength(length, frame);
713 }).Default([
this, &frame](Operation *ordinary) {
return emit(*ordinary, frame); });
717 LogicalResult expand(Block &block,
Environment &frame, SmallVectorImpl<BoundValue> &results) {
718 for (Operation &op : block) {
719 if (isa<ReturnOp, scf::YieldOp, scf::ConditionOp>(op)) {
720 for (Value value : op.getOperands()) {
721 results.push_back(frame.lookup(value));
725 if (failed(dispatch(op, frame))) {
729 return constraintError(block.getParentOp(),
"missing supported terminator");
734 LogicalResult validateOperation(Operation &op) {
735 if (op.getNumRegions()) {
736 return constraintError(&op,
"regions are unsupported in flattened constraints");
738 if (isFieldExpression(op) || isa<constrain::EmitEqualityOp>(op)) {
739 auto fieldType = [](Type type) {
return isa<felt::FeltType>(type); };
740 if (llvm::all_of(op.getOperandTypes(), fieldType) &&
741 llvm::all_of(op.getResultTypes(), fieldType)) {
745 &op,
"constraint expressions require scalar felt operands and results"
748 if (
auto constant = dyn_cast<arith::ConstantOp>(op)) {
749 Type type = constant.getType();
750 if (type.isIndex() || type.isInteger(1)) {
754 if (
auto conversion = dyn_cast<cast::IntToFeltOp>(op)) {
756 if (matchPattern(conversion.getValue(),
m_Constant(&literal)) && isa<IntegerAttr>(literal)) {
757 if (!isMemoryEffectFree(conversion) && !facts.known(conversion.getResult())) {
758 return constraintError(&op,
"assert cast requires a statically valid field conversion");
762 return constraintError(&op,
"field conversion requires a compile-time integer");
764 if (isa<array::ReadArrayOp, array::ExtractArrayOp>(op)) {
765 ValueRange indices = llvm::cast<array::ArrayAccessOpInterface>(op).getIndices();
766 for (Value index : indices) {
767 if (!index.getDefiningOp<arith::ConstantOp>()) {
768 return constraintError(&op,
"array path requires compile-time indices");
773 if (
auto read = dyn_cast<MemberReadOp>(op)) {
774 if (read.getTableOffset()) {
775 return constraintError(&op,
"member read requires concrete non-column component storage");
779 if (isa<pod::ReadPodOp>(op)) {
782 if (isIntegerExpression(op)) {
783 return constraintError(&op,
"structural operation requires a compile-time value");
786 &op,
"unsupported operation in flattened constraints: '" + op.getName().getStringRef() +
"'"
791 LogicalResult validateOutput() {
792 for (Operation &op : llvm::make_early_inc_range(llvm::reverse(output.front()))) {
795 bool foldedIndexCast = isa<cast::FeltToIndexOp>(op) && facts.known(op.getResult(0));
796 if (op.use_empty() &&
797 (foldedIndexCast || isMemoryEffectFree(&op) ||
798 isa<MemberReadOp, array::ReadArrayOp, array::ExtractArrayOp, pod::ReadPodOp>(op))) {
802 for (Operation &op : output.front()) {
803 if (failed(validateOperation(op))) {
806 if (nonSignalReads.contains(&op)) {
808 &op,
"live unresolved non-signal scalar storage; algebraic elimination is required"
816 LogicalResult commit(FuncDefOp
source) {
818 original.takeBody(
source.getBody());
819 source.getBody().takeBody(output);
820 if (failed(verify(
source))) {
821 output.takeBody(
source.getBody());
822 source.getBody().takeBody(original);
829 explicit ConstraintElaborator(ModuleOp root)
830 : module(root), builder(root.getContext()), bindings(root.getContext()) {}
833 LogicalResult run() {
842 storage.emplace(module, main, builder, tables, facts);
843 auto source = main.getConstrainFuncOp();
845 return constraintError(main,
"main must have a concrete single-block constrain function");
847 output.push_back(
new Block());
848 SmallVector<BoundValue> arguments;
849 for (
auto [i, argument] : llvm::enumerate(
source.getArguments())) {
850 Value emitted = output.front().addArgument(argument.getType(), argument.getLoc());
851 if (aggregate(argument.getType())) {
852 arguments.push_back(bindings.create(argument.getType(), argument, emitted));
854 arguments.push_back(emitted);
857 builder.setInsertionPointToEnd(&output.front());
858 SmallVector<BoundValue> results;
859 if (failed(invoke(
source, arguments,
source, results)) || failed(validateOutput())) {
868 using Base = llzk::polymorphic::impl::ConstraintFlatteningPassBase<PassImpl>;
871 void runOnOperation()
override {
872 if (failed(ConstraintElaborator(getOperation()).run())) {
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation and configuration files Object form shall mean any form resulting from mechanical transformation or translation of a Source including but not limited to compiled object generated and conversions to other media types Work shall mean the work of whether in Source or Object made available under the as indicated by a copyright notice that is included in or attached to the whether in Source or Object that is based or other modifications as a an original work of authorship For the purposes of this Derivative Works shall not include works that remain separable or merely the Work and Derivative Works thereof Contribution shall mean any work of including the original version of the Work and any modifications or additions to that Work or Derivative Works that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner For the purposes of this definition
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation source
::mlir::TypedValue<::llzk::array::ArrayType > getArrRef()
::mlir::TypedValue<::mlir::IndexType > getDim()
::mlir::TypedValue<::llzk::array::ArrayType > getResult()
::mlir::Operation::operand_range getElements()
static ReadArrayOp create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Type result, ::mlir::Value arr_ref, ::mlir::ValueRange indices)
::mlir::TypedValue<::llzk::component::StructType > getComponent()
::std::optional<::mlir::Attribute > getTableOffset()
static FeltConstantOp create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Type result, ::llzk::felt::FeltConstAttr value)
static MulFeltOp create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Type result, ::mlir::Value lhs, ::mlir::Value rhs)
bool calleeIsStructConstrain()
Return true iff the callee function name is FUNC_NAME_CONSTRAIN within a StructDefOp.
::mlir::SymbolRefAttr getCalleeAttr()
::mlir::Operation::operand_range getArgOperands()
::mlir::Region & getBody()
static ReturnOp create(::mlir::OpBuilder &builder, ::mlir::Location location)
::mlir::SymbolRefAttr getNameRefAttr()
::mlir::SmallVector<::llzk::pod::RecordValue > getInitializedRecordValues()
::mlir::TypedValue<::llzk::pod::PodType > getResult()
::llvm::StringRef getRecordName()
::mlir::TypedValue<::mlir::Type > getResult()
::mlir::TypedValue<::llzk::pod::PodType > getPodRef()
static ReadPodOp create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Type result, ::mlir::Value pod_ref, ::mlir::StringAttr record_name)
::mlir::TypedValue<::mlir::Type > getValue()
::mlir::TypedValue<::llzk::pod::PodType > getPodRef()
::llvm::StringRef getRecordName()
Bind scalar leaves without constructing a shadow array or POD object.
Evaluate scalar dependencies of structural decisions, assertions, and constant arithmetic.
int main(int argc, char **argv)
Common interface for constant parameter-like symbol operations that can be defined within a TemplateO...
mlir::LogicalResult constraintError(mlir::Operation *site, const llvm::Twine &message)
Emit the common diagnostic prefix for constraint expansion and storage helpers.
std::variant< mlir::Value, AccessPath > BoundValue
Scalar expressions are SSA; aggregates are paths, never emitted allocations.
llvm::DenseMap< mlir::Value, BoundValue > Environment
bool isInvariantTrueCondition(mlir::Value condition)
Prove a Boolean condition true without any loop-carried bindings.
bool hasNextStaticIteration(int64_t current, int64_t upper, int64_t step)
Whether another signed iteration exists after current, for current < upper and a positive step.
bool isInTemplate(Operation *op)
mlir::FailureOr< SymbolLookupResultUntyped > lookupTopLevelSymbol(mlir::SymbolTableCollection &tables, mlir::SymbolRefAttr symbol, mlir::Operation *origin, bool reportMissing=true)
ConstantCapture m_Constant()
FailureOr< SymbolLookupResult< StructDefOp > > getRootStructDef(SymbolTableCollection &tables, Operation *lookupFrom, StringRef symbolPath)