LLZK 3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
LLZKTransformationPasses.td
Go to the documentation of this file.
1//===-- LLZKTransformationPasses.td ------------------------*- tablegen -*-===//
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//===----------------------------------------------------------------------===//
9
10#ifndef LLZK_TRANSFORMATION_PASSES_TD
11#define LLZK_TRANSFORMATION_PASSES_TD
12
13include "llzk/Pass/PassBase.td"
14
15def RedundantReadAndWriteEliminationPass
16 : LLZKPass<"llzk-duplicate-read-write-elim"> {
17 let summary = "Remove redundant reads and writes";
18 let description = [{
19 Remove redundant or unnecessary reads and writes to struct members, arrays,
20 globals, and RAM. Global writes are removed when they are overwritten or
21 write an already-known value. RAM stores require the same translated address
22 SSA value.
23
24 Struct-member accesses match only when the base, member, table offset,
25 affine map metadata, and translated affine operands match. Omitted
26 member-read offsets and member writes denote the current row.
27
28 Stateful reads are reused when the current analysis state proves the read
29 observes the same value. Writes and stores update that known state, while
30 unknown or non-read state effects invalidate it.
31 }];
32}
33
34def RedundantOperationEliminationPass : LLZKPass<"llzk-duplicate-op-elim"> {
35 let summary = "Remove redundant operations";
36 let description = [{
37 Remove equivalent memory-effect-free operations and duplicate LLZK constraints.
38
39 Pass should be run after `llzk-duplicate-read-write-elim` for maximum effect.
40 }];
41}
42
43def UnusedDeclarationEliminationPass
44 : LLZKPass<"llzk-unused-declaration-elim"> {
45 let summary = "Remove unused member and struct declarations";
46 let description = [{
47 Remove member and struct declarations that are unused within the current compilation
48 unit. Note that this pass may cause linking issues with external modules that
49 depend on any unused member and struct declarations from this compilation unit.
50
51 Pass should be run after `llzk-duplicate-read-write-elim`
52 and `llzk-duplicate-op-elim` for maximum effect.
53 }];
54 let options = [Option<"removeStructs", "remove-structs", "bool",
55 /* default */ "false",
56 "Whether to remove unused struct definitions as well. "
57 "Requires module to declare a Main component, "
58 "otherwise all components will appear unused.">,
59 ];
60}
61
62def RemoveUnusedDiscardableAllocationsPass
63 : LLZKPass<"llzk-remove-unused-discardable-allocations"> {
64 let summary = "Remove unread discardable allocations and their dead stores";
65 let description = [{
66 Remove ops with the selected allocator operation name when they are marked with
67 `MemAlloc<DiscardableAllocationResource>`, the allocation has no reads, and every direct user is
68 a discardable allocation accessor that can be erased as a dead store.
69 }];
70 let options = [Option<
71 "allocatorOpName", "allocator-op", "std::string",
72 /* default */ "\"\"",
73 "Operation name of the discardable allocator to remove">];
74}
75
76def PolyLoweringPass : LLZKPass<"llzk-poly-lowering-pass"> {
77 let summary =
78 "Lower the degree of all polynomial equations to a specified maximum";
79 let description = [{
80 Rewrites constraint expressions into an (observationally) equivalent system where the degree of
81 every polynomial is less than or equal to the specified maximum.
82
83 High-degree subexpressions are factored into auxiliary struct members. The pass also recurses
84 through degree-neutral roots such as `felt.add`, `felt.sub`, and `felt.neg`, so composite
85 equality operands and struct constrain call arguments satisfy their degree bounds.
86
87 The pass expects an already-flattened, straight-line `constrain` body. Run `llzk-flatten` or
88 another control-flow lowering pass before this pass; nested-region, successor-bearing, or
89 multi-block constrain functions are rejected instead of being rewritten with
90 component-lifetime auxiliary members. Compute functions may contain control flow; auxiliary
91 computations and writes are materialized on every return path.
92
93 This pass is best used on already-flattened input as part of the `-llzk-full-poly-lowering`
94 pipeline, which includes additional cleanup passes to ensure correctness and optimal
95 performance.
96 }];
97 let options = [Option<"maxDegree", "max-degree", "unsigned",
98 /* default */ "2",
99 "Maximum degree of constraint polynomials "
100 "(default 2, minimum 2)">,
101 ];
102}
103
104def ComputeConstrainToProductPass
105 : LLZKPass<"llzk-compute-constrain-to-product"> {
106 let summary = "Replace separate `@compute` and `@constrain` functions in a "
107 "struct with a single `@product` function";
108 let description = summary;
109 let options = [Option<"rootStruct", "root-struct", "std::string",
110 /* default */ "\"Main\"",
111 "Root struct at which to start alignment "
112 "(default to `@Main`)">];
113}
114
115def FuseProductControlFlowPass : LLZKPass<"llzk-fuse-product-control-flow"> {
116 let summary =
117 "Fuse matching compute/constrain control flow in a `@product` function";
118 let description =
119 "Fuse matching witness/constraint loops in a `@product` function";
120}
121
122def EnforceNoMemberOverwritePass : LLZKPass<"llzk-enforce-no-overwrite"> {
123 let summary = "Checks that every struct member is written exactly once";
124 let description = [{
125 This pass currently reports an error if any struct member may not be written
126 exactly once (i.e. overwritten or left uninitialized), and does not
127 attempt to perform any repairs (e.g. SSA-ifying overwritten struct
128 members, or default-initializing unwritten members). This pass
129 overapproximates conditionals, and can result in false positives.
130 }];
131}
132
133def InlineFreeFunctionsPass : LLZKPass<"llzk-inline-free-functions"> {
134 let summary = "Inline calls to free functions";
135 let description = [{
136 Inlines `function.call` operations inside `function.def` bodies when the
137 target is a free `function.def` directly inside the pass's root
138 `builtin.module` or within a nested module or template if every symbol
139 reference in the function can be resolved from the root module. Calls
140 to other nested functions, included functions, and calls outside
141 `function.def` bodies are left unchanged.
142
143 After inlining, free functions that have no remaining symbol uses anywhere
144 in the module are erased. This cleanup applies to every non-external free
145 function within the pass's root module, regardless of its symbol visibility
146 or whether any call to it was inlined.
147
148 Inlining is best effort: free functions that participate in a call
149 cycle are skipped (inlining one would re-materialize its calls
150 forever). If inlining a callee fails, its remaining calls are left in
151 place with a warning while processing continues with other callees.
152 }];
153}
154
155def WhileToForPass : LLZKPass<"llzk-while-to-for"> {
156 let summary =
157 "Converts scf.while loops to equivalent scf.for loops when possible";
158 let description =
159 "This pass identifies scf.while loops that have an "
160 "induction variable and a uniform step, and converts them "
161 "to equivalent scf.for loops, which are preferred by some "
162 "analyses. This pass may introduce some spurious felt/index casts which "
163 "should be cleaned up by --canonicalize.";
164}
165
166#endif // LLZK_TRANSFORMATION_PASSES_TD