LLZK 3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
LLZKTransformationPassPipelines.cpp
Go to the documentation of this file.
1//===-- LLZKTransformationPassPipelines.cpp ---------------------*- C++ -*-===//
2//
3// Part of the LLZK Project, under the Apache License v2.0.
4// See LICENSE.txt for license information.
5// Copyright 2025 Veridise Inc.
6// SPDX-License-Identifier: Apache-2.0
7//
8//===----------------------------------------------------------------------===//
13//===----------------------------------------------------------------------===//
14
16
19
20#include <mlir/Pass/PassManager.h>
21#include <mlir/Pass/PassRegistry.h>
22#include <mlir/Transforms/Passes.h>
23
24#include <utility>
25
26using namespace mlir;
27
28namespace llzk {
29
30//===----------------------------------------------------------------------===//
31// Pipeline implementation.
32//===----------------------------------------------------------------------===//
33
34namespace {
35
36template <typename NestedPassOptionT>
37inline std::unique_ptr<Pass> createConfiguredPass(const NestedPassOptionT &options) {
38 return options.getValue().createPass();
39}
40
41void buildFullStructInliningPipelineImpl(
42 OpPassManager &pm, polymorphic::FlatteningPassOptions flattening, bool arrayToScalar,
43 bool podToScalar, std::unique_ptr<Pass> inliningPass
44) {
45 // default to `main-as-root` if unspecified to avoid leaving parameterized templates
46 // that cause the later struct inlining pass to crash
47 if (flattening.cleanupMode == polymorphic::FlatteningCleanupMode::Unspecified) {
49 }
50 pm.addPass(polymorphic::createFlatteningPass(flattening));
51
52 // Run pod-to-scalar first because it is able to split `pod.type` used as array element type
53 // (into parallel arrays) so it should be able to fully remove all `pod.type` usages.
54 if (podToScalar) {
55 pm.addPass(pod::createPodToScalarPass());
56 }
57 if (arrayToScalar) {
59 }
60 // Canonicalize to remove known-condition `scf.if` regions so struct inlining
61 // can link "@compute" calls to struct members.
62 pm.addPass(mlir::createCanonicalizerPass());
63 pm.addPass(std::move(inliningPass));
64
65 // Remove struct and member definitions that are no longer used after inlining.
67 UnusedDeclarationEliminationPassOptions {.removeStructs = true}
68 ));
69}
70
71void buildFullPolyLoweringPipelineImpl(
72 OpPassManager &pm, polymorphic::FlatteningPassOptions flattening, bool arrayToScalar,
73 bool podToScalar, std::unique_ptr<Pass> inliningPass, std::unique_ptr<Pass> polyLoweringPass
74) {
75 // 1. Struct flattening and inlining
76 buildFullStructInliningPipelineImpl(
77 pm, flattening, arrayToScalar, podToScalar, std::move(inliningPass)
78 );
79 // 2. Degree lowering
80 pm.addPass(std::move(polyLoweringPass));
81 // 3. Cleanup
83}
84
85} // namespace
86
91
96
97void buildProductProgramPipeline(OpPassManager &pm) {
99 pm.addPass(createFuseProductLoopsPass());
100}
101
103 buildFullStructInliningPipelineImpl(
104 pm, cfg.flattening, cfg.arrayToScalar, cfg.podToScalar,
106 );
107}
108
109void buildFullInliningPipeline(OpPassManager &pm, const FullStructInliningConfig &cfg) {
110 // Inline free-function bodies before struct cleanup so their struct uses
111 // participate in flattening and keep the referenced definitions alive.
112 pm.addPass(createInlineFreeFunctionsPass());
113 buildFullStructInliningPipelineImpl(
114 pm, cfg.flattening, cfg.arrayToScalar, cfg.podToScalar,
116 );
117}
118
119void buildFullPolyLoweringPipeline(OpPassManager &pm, const FullPolyLoweringConfig &cfg) {
120 buildFullPolyLoweringPipelineImpl(
125 );
126}
127
128//===----------------------------------------------------------------------===//
129// Pipeline registration.
130//===----------------------------------------------------------------------===//
131
133 PassPipelineRegistration<>(
134 "llzk-remove-unnecessary-ops",
135 "Remove unnecessary operations, such as redundant reads or repeated constraints",
137 );
138
139 PassPipelineRegistration<>(
140 "llzk-remove-unnecessary-ops-and-defs",
141 "Remove unnecessary operations, member definitions, and struct definitions",
143 );
144
145 PassPipelineRegistration<>(
146 "llzk-product-program",
147 "Convert @compute/@constrain functions to @product function and perform alignment",
149 );
150
151 PassPipelineRegistration<FullStructInliningOptions>(
152 "llzk-full-struct-inlining",
153 "Run flattening and inlining of all struct definitions into the `main` struct. This "
154 "pipeline uses the `main-as-root` cleanup mode in the flattening pass by default. It "
155 "is not recommended to override this cleanup mode because other cleanup modes may "
156 "leave behind parameterized templates that later cause `llzk-inline-structs` to crash.",
157 [](OpPassManager &pm, const FullStructInliningOptions &opts) {
158 auto flattening = opts.flattening.getValue().createOptions();
159 buildFullStructInliningPipelineImpl(
160 pm, flattening->createPassOptions(), opts.arrayToScalar, opts.podToScalar,
161 createConfiguredPass(opts.inlining)
162 );
163 }
164 );
165
166 PassPipelineRegistration<FullStructInliningOptions>(
167 "llzk-full-inlining",
168 "Run free function inlining, flattening, and struct inlining. This is the "
169 "recommended pipeline before any downstream pass that does not understand `function.call`.",
170 [](OpPassManager &pm, const FullStructInliningOptions &opts) {
171 auto flattening = opts.flattening.getValue().createOptions();
172 // Inline free-function bodies before struct cleanup so their struct uses
173 // participate in flattening and keep the referenced definitions alive.
174 pm.addPass(createInlineFreeFunctionsPass());
175 buildFullStructInliningPipelineImpl(
176 pm, flattening->createPassOptions(), opts.arrayToScalar, opts.podToScalar,
177 createConfiguredPass(opts.inlining)
178 );
179 }
180 );
181
182 PassPipelineRegistration<FullPolyLoweringOptions>(
183 "llzk-full-poly-lowering",
184 "Run flattening and inlining of all struct definitions into the `main` struct, then lower "
185 "polynomial constraints to a given max degree, and finally remove unnecessary operations and "
186 "definitions. This pipeline uses the `main-as-root` cleanup mode in the flattening pass by "
187 "default. It is not recommended to override this cleanup mode because other cleanup modes "
188 "may leave behind parameterized templates that later cause `llzk-inline-structs` to crash.",
189 [](OpPassManager &pm, const FullPolyLoweringOptions &opts) {
190 auto structInlining = opts.structInlining.getValue().createOptions();
191 auto flattening = structInlining->flattening.getValue().createOptions();
192 buildFullPolyLoweringPipelineImpl(
193 pm, flattening->createPassOptions(), structInlining->arrayToScalar,
194 structInlining->podToScalar, createConfiguredPass(structInlining->inlining),
195 createConfiguredPass(opts.polyLowering)
196 );
197 }
198 );
199}
200
201} // namespace llzk
std::unique_ptr<::mlir::Pass > createArrayToScalarPass()
std::unique_ptr<::mlir::Pass > createInlineStructsPass()
std::unique_ptr<::mlir::Pass > createPodToScalarPass()
std::unique_ptr<::mlir::Pass > createFlatteningPass()
void buildRemoveUnnecessaryOpsAndDefsPipeline(mlir::OpPassManager &pm)
std::unique_ptr<::mlir::Pass > createInlineFreeFunctionsPass()
std::unique_ptr<::mlir::Pass > createPolyLoweringPass()
std::unique_ptr<::mlir::Pass > createUnusedDeclarationEliminationPass()
void buildProductProgramPipeline(OpPassManager &pm)
std::unique_ptr<::mlir::Pass > createFuseProductLoopsPass()
void buildFullStructInliningPipeline(OpPassManager &pm, const FullStructInliningConfig &cfg)
void buildFullPolyLoweringPipeline(OpPassManager &pm, const FullPolyLoweringConfig &cfg)
std::unique_ptr<::mlir::Pass > createComputeConstrainToProductPass()
std::unique_ptr<::mlir::Pass > createRedundantOperationEliminationPass()
void buildFullInliningPipeline(OpPassManager &pm, const FullStructInliningConfig &cfg)
std::unique_ptr<::mlir::Pass > createRedundantReadAndWriteEliminationPass()
void buildRemoveUnnecessaryOpsPipeline(mlir::OpPassManager &pm)
Pure C++ configuration for the full polynomial lowering pipeline.
CLI Option configuration for the full polynomial lowering pipeline.
Pure C++ configuration for the full struct inlining pipeline.
polymorphic::FlatteningPassOptions flattening
component::InlineStructsPassOptions inlining
CLI Option configuration for the full struct inlining pipeline.