LLZK 3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
LowerBoolQuantifiersPass.cpp
Go to the documentation of this file.
1//===-- LowerBoolQuantifiersPass.cpp ---------------------------*- 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//===----------------------------------------------------------------------===//
13//===----------------------------------------------------------------------===//
14
22#include <mlir/Dialect/Arith/IR/Arith.h>
23#include <mlir/Dialect/SCF/IR/SCF.h>
24#include <mlir/IR/IRMapping.h>
25#include <mlir/Transforms/GreedyPatternRewriteDriver.h>
26
27// Include the generated base pass class definitions.
28namespace llzk::boolean {
29#define GEN_PASS_DEF_LOWERBOOLQUANTIFIERSPASS
31} // namespace llzk::boolean
33using namespace mlir;
34using namespace llzk;
35using namespace llzk::array;
36using namespace llzk::boolean;
38namespace {
39
40
41static Value buildQuantifierIterValue(
42 Location loc, Value sort, ArrayType sortType, Value index, PatternRewriter &rewriter
43) {
44 if (sortType.getDimensionSizes().size() == 1) {
45 return ReadArrayOp::create(rewriter, loc, sort, ValueRange {index});
46 }
47
48 Type iterType = getQuantifierOpDomainIterType(sortType);
49 return ExtractArrayOp::create(rewriter, loc, iterType, sort, ValueRange {index});
50}
53template <typename QuantifierOp, typename CombineOp>
54static LogicalResult
55lowerQuantifier(QuantifierOp op, PatternRewriter &rewriter, bool initialValue) {
56 PatternRewriter::InsertionGuard guard(rewriter);
57 Location loc = op.getLoc();
58 auto sortType = cast<ArrayType>(op.getSort().getType());
59
60 Value lowerBound = arith::ConstantIndexOp::create(rewriter, loc, 0);
61 Value upperBound = ArrayLengthOp::create(rewriter, loc, op.getSort(), lowerBound);
62 Value step = arith::ConstantIndexOp::create(rewriter, loc, 1);
63 Value init = arith::ConstantIntOp::create(rewriter, loc, rewriter.getI1Type(), initialValue);
64
65 auto loop = scf::ForOp::create(rewriter, loc, lowerBound, upperBound, step, ValueRange {init});
67
68 Block &loopBody = *loop.getBody();
69 if (!loopBody.empty()) {
70 rewriter.eraseOp(&loopBody.back());
71 }
72
73 rewriter.setInsertionPointToStart(&loopBody);
74 Value iterValue =
75 buildQuantifierIterValue(loc, op.getSort(), sortType, loop.getInductionVar(), rewriter);
76
77 IRMapping mapping;
78 mapping.map(op.getBody()->getArgument(0), iterValue);
79 for (Operation &nestedOp : op.getBody()->without_terminator()) {
80 rewriter.clone(nestedOp, mapping);
81 }
82
83 auto yieldOp = cast<YieldOp>(op.getBody()->getTerminator());
84 Value predicate = mapping.lookupOrDefault(yieldOp.getValue());
85 Value combined = CombineOp::create(rewriter, loc, loop.getRegionIterArg(0), predicate);
86 scf::YieldOp::create(rewriter, loc, combined);
87
88 rewriter.replaceOp(op, loop.getResults());
89 return success();
90}
92class LowerForAllOp : public OpRewritePattern<ForAllOp> {
93public:
94 using OpRewritePattern<ForAllOp>::OpRewritePattern;
95
96 LogicalResult matchAndRewrite(ForAllOp op, PatternRewriter &rewriter) const override {
97 return lowerQuantifier<ForAllOp, AndBoolOp>(op, rewriter, /*initialValue=*/true);
98 }
99};
100
101class LowerExistsOp : public OpRewritePattern<ExistsOp> {
102public:
103 using OpRewritePattern<ExistsOp>::OpRewritePattern;
104
105 LogicalResult matchAndRewrite(ExistsOp op, PatternRewriter &rewriter) const override {
106 return lowerQuantifier<ExistsOp, OrBoolOp>(op, rewriter, /*initialValue=*/false);
107 }
108};
109
110class PassImpl : public llzk::boolean::impl::LowerBoolQuantifiersPassBase<PassImpl> {
111 using Base = LowerBoolQuantifiersPassBase<PassImpl>;
112
113public:
114 using Base::Base;
115
116 void runOnOperation() override {
117 RewritePatternSet patterns(&getContext());
118 patterns.add<LowerForAllOp, LowerExistsOp>(&getContext());
119
120 if (failed(applyPatternsGreedily(getOperation(), std::move(patterns)))) {
121 signalPassFailure();
122 }
123 }
124};
125
126} // namespace
static ArrayLengthOp create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Type length, ::mlir::Value arr_ref, ::mlir::Value dim)
Definition Ops.cpp.inc:155
::llvm::ArrayRef<::mlir::Attribute > getDimensionSizes() const
static ExtractArrayOp create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Type result, ::mlir::Value arr_ref, ::mlir::ValueRange indices)
Definition Ops.cpp.inc:1050
static ReadArrayOp create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Type result, ::mlir::Value arr_ref, ::mlir::ValueRange indices)
Definition Ops.cpp.inc:1758
mlir::Type getQuantifierOpDomainIterType(llzk::array::ArrayType arr)
Extracts the type used for a quantifier op block argument.
Definition Utils.h:20
OpTy preserveDiscardableAttrs(mlir::Operation *src, OpTy dst)
Copy discardable attributes from src to dst.