LLZK 3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
ConstraintScalarFacts.h
Go to the documentation of this file.
1//===-- ConstraintScalarFacts.h ---------------------------------*- C++ -*-===//
2//
3// Part of the LLZK Project, under the Apache License v2.0.
4// See LICENSE.txt for license information.
5// Copyright 2026 Project LLZK
6// SPDX-License-Identifier: Apache-2.0
7//
8//===----------------------------------------------------------------------===//
9
10#pragma once
11
12#include "ScalarEvaluation.h"
13
14#include <mlir/IR/Matchers.h>
15#include <mlir/Interfaces/SideEffectInterfaces.h>
16
17#include <llvm/ADT/DenseMap.h>
18#include <llvm/ADT/DenseSet.h>
19
25 llvm::DenseMap<mlir::Value, mlir::Attribute> constants;
26
28 void fold(mlir::Operation *producer) {
29 llvm::SmallVector<mlir::Attribute> operands;
30 for (mlir::Value operand : producer->getOperands()) {
31 operands.push_back(constants.lookup(operand));
32 }
33 llvm::SmallVector<mlir::OpFoldResult> results;
34 if (mlir::succeeded(evaluateScalarOperation(producer, operands, results))) {
35 for (auto [result, folded] : llvm::zip_equal(producer->getResults(), results)) {
36 constants[result] = llvm::isa<mlir::Attribute>(folded)
37 ? llvm::cast<mlir::Attribute>(folded)
38 : constants.lookup(llvm::cast<mlir::Value>(folded));
39 }
40 }
41 }
42
43public:
45 explicit ConstraintScalarFacts(mlir::MLIRContext * /*context*/) {}
46
49 mlir::Attribute known(mlir::Value value) {
50 llvm::SmallVector<std::pair<mlir::Value, bool>> pending {{value, false}};
51 llvm::DenseSet<mlir::Value> examined;
52 while (!pending.empty()) {
53 auto [current, ready] = pending.pop_back_val();
54 if (constants.contains(current)) {
55 continue;
56 }
57 mlir::Attribute literal;
58 if (mlir::matchPattern(current, mlir::m_Constant(&literal))) {
59 constants[current] = literal;
60 continue;
61 }
62 mlir::Operation *producer = current.getDefiningOp();
63 // Assert casts may have effects, but their fold hooks succeed only when the
64 // range check is satisfied. Other effectful operations remain unknown.
65 if (!producer || producer->getNumRegions() ||
66 (!mlir::isMemoryEffectFree(producer) &&
67 !llvm::isa<cast::FeltToIndexOp, cast::IntToFeltOp>(producer))) {
68 constants.try_emplace(current, mlir::Attribute());
69 continue;
70 }
71 if (!ready) {
72 if (!examined.insert(current).second) {
73 continue;
74 }
75 pending.push_back({current, true});
76 for (mlir::Value operand : producer->getOperands()) {
77 pending.push_back({operand, false});
78 }
79 continue;
80 }
81 fold(producer);
82 constants.try_emplace(current, mlir::Attribute());
83 }
84 return constants.lookup(value);
85 }
86
88 std::optional<int64_t> integer(mlir::Value value) {
89 auto attr = llvm::dyn_cast_or_null<mlir::IntegerAttr>(known(value));
90 if (!attr || !attr.getValue().isSignedIntN(64)) {
91 return std::nullopt;
92 }
93 return attr.getInt();
94 }
95};
96
99inline bool isInvariantTrueCondition(mlir::Value condition) {
100 ConstraintScalarFacts facts(condition.getContext());
101 auto value = facts.integer(condition);
102 return value && *value != 0;
103}
104
105} // namespace llzk::polymorphic::detail
Evaluate scalar dependencies of structural decisions, assertions, and constant arithmetic.
mlir::Attribute known(mlir::Value value)
Evaluate pure SSA dependencies and casts whose fold hooks prove validity.
std::optional< int64_t > integer(mlir::Value value)
Require an integer representable by concrete access paths and signed loops.
Common interface for constant parameter-like symbol operations that can be defined within a TemplateO...
mlir::LogicalResult evaluateScalarOperation(mlir::Operation *op, llvm::ArrayRef< mlir::Attribute > operands, llvm::SmallVectorImpl< mlir::OpFoldResult > &results)
Evaluate a scalar operation using caller-supplied operand constants.
bool isInvariantTrueCondition(mlir::Value condition)
Prove a Boolean condition true without any loop-carried bindings.