LLZK
3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Toggle main menu visibility
Loading...
Searching...
No Matches
SpecializedMemoryPasses.h
Go to the documentation of this file.
1
//===-- SpecializedMemoryPasses.h - Targeted SROA / mem2reg -----*- 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
//===----------------------------------------------------------------------===//
16
//===----------------------------------------------------------------------===//
17
18
#pragma once
19
20
#include "
llzk/Util/Walk.h
"
21
22
#include <mlir/Analysis/DataLayoutAnalysis.h>
23
#include <mlir/Dialect/SCF/IR/SCF.h>
24
#include <mlir/IR/Builders.h>
25
#include <mlir/IR/Dominance.h>
26
#include <mlir/Interfaces/MemorySlotInterfaces.h>
27
#include <mlir/Pass/Pass.h>
28
#include <mlir/Pass/PassManager.h>
29
#include <mlir/Transforms/Mem2Reg.h>
30
#include <mlir/Transforms/Passes.h>
31
#include <mlir/Transforms/SROA.h>
32
33
#include <llvm/ADT/SmallVector.h>
34
35
namespace
llzk
{
36
40
template
<
typename
AllocOpTy>
41
struct
SpecializedSROA
: mlir::PassWrapper<SpecializedSROA<AllocOpTy>, mlir::OperationPass<>> {
42
43
mlir::StringRef
getArgument
()
const override
{
return
"llzk-specialized-sroa"
; }
44
45
mlir::StringRef
getDescription
()
const override
{
46
return
"Scalar replacement of aggregates for a specific allocator op type"
;
47
}
48
49
void
runOnOperation
()
override
{
50
mlir::Operation *scopeOp = this->getOperation();
51
52
auto
&dataLayoutAnalysis = this->
template
getAnalysis<mlir::DataLayoutAnalysis>();
53
const
mlir::DataLayout &dataLayout = dataLayoutAnalysis.getAtOrAbove(scopeOp);
54
55
bool
changed =
false
;
56
57
for
(mlir::Region ®ion : scopeOp->getRegions()) {
58
if
(region.getBlocks().empty()) {
59
continue
;
60
}
61
62
mlir::OpBuilder builder(®ion.front(), region.front().begin());
63
64
auto
allocators = walkCollectMapped<AllocOpTy>(region, [](
auto
allocator) {
65
return
mlir::DestructurableAllocationOpInterface(allocator);
66
});
67
68
if
(mlir::succeeded(mlir::tryToDestructureMemorySlots(allocators, builder, dataLayout))) {
69
changed =
true
;
70
}
71
}
72
73
if
(!changed) {
74
this->markAllAnalysesPreserved();
75
}
76
}
77
};
78
79
// Pass factory for `SpecializedSROA`.
80
template
<
typename
AllocOpTy>
81
std::unique_ptr<SpecializedSROA<AllocOpTy>>
createSpecializedSROAPass
() {
82
return
std::make_unique<SpecializedSROA<AllocOpTy>>();
83
}
84
88
template
<
typename
AllocOpTy>
89
struct
SpecializedMem2Reg
90
: mlir::PassWrapper<SpecializedMem2Reg<AllocOpTy>, mlir::OperationPass<>> {
91
92
mlir::StringRef
getArgument
()
const override
{
return
"llzk-specialized-mem2reg"
; }
93
94
mlir::StringRef
getDescription
()
const override
{
95
return
"Promotes memory slots of a specific allocator op type into values"
;
96
}
97
98
void
runOnOperation
()
override
{
99
mlir::Operation *scopeOp = this->getOperation();
100
101
auto
&dataLayoutAnalysis = this->
template
getAnalysis<mlir::DataLayoutAnalysis>();
102
const
mlir::DataLayout &dataLayout = dataLayoutAnalysis.getAtOrAbove(scopeOp);
103
auto
&dominance = this->
template
getAnalysis<mlir::DominanceInfo>();
104
105
bool
changed =
false
;
106
107
for
(mlir::Region ®ion : scopeOp->getRegions()) {
108
if
(region.getBlocks().empty()) {
109
continue
;
110
}
111
112
mlir::OpBuilder builder(®ion.front(), region.front().begin());
113
114
auto
allocators = walkCollectMapped<AllocOpTy>(region, [](
auto
allocator) {
115
return
mlir::PromotableAllocationOpInterface(allocator);
116
});
117
118
auto
promoteRes = mlir::tryToPromoteMemorySlots(allocators, builder, dataLayout, dominance);
119
if
(mlir::succeeded(promoteRes)) {
120
changed =
true
;
121
}
122
}
123
124
if
(!changed) {
125
this->markAllAnalysesPreserved();
126
}
127
}
128
};
129
130
// Pass factory for `SpecializedMem2Reg`.
131
template
<
typename
AllocOpTy>
132
std::unique_ptr<SpecializedMem2Reg<AllocOpTy>>
createSpecializedMem2RegPass
() {
133
return
std::make_unique<SpecializedMem2Reg<AllocOpTy>>();
134
}
135
136
namespace
detail {
137
141
class
RemoveDeadValuesWorkaroundPass
142
:
public
mlir::PassWrapper<RemoveDeadValuesWorkaroundPass, mlir::OperationPass<>> {
143
public
:
144
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(
RemoveDeadValuesWorkaroundPass
)
145
146
llvm
::StringRef
getArgument
()
const override
{
return
"remove-dead-values"
; }
147
llvm::StringRef
getDescription
()
const override
{
return
"Remove dead values"
; }
148
149
void
runOnOperation
() final {
150
mlir::Operation *scopeOp = this->getOperation();
151
152
// Pre-pass: add a trivial block to empty `else` regions so upstream pass code can handle them.
153
scopeOp->walk([](mlir::scf::IfOp ifOp) {
154
if
(ifOp.getElseRegion().empty()) {
155
mlir::Block &elseBlock = ifOp.getElseRegion().emplaceBlock();
156
mlir::OpBuilder builder(ifOp.getContext());
157
builder.setInsertionPointToEnd(&elseBlock);
158
builder.create<mlir::scf::YieldOp>(ifOp.getLoc());
159
}
160
});
161
162
mlir::OpPassManager pm(scopeOp->getName().getStringRef());
163
pm.addPass(mlir::createRemoveDeadValuesPass());
164
if
(mlir::failed(runPipeline(pm, scopeOp))) {
165
signalPassFailure();
166
}
167
168
// Post-pass: remove trivial `else` blocks that are left behind.
169
scopeOp->walk([](mlir::scf::IfOp ifOp) {
170
if
(ifOp.getResults().empty()) {
171
mlir::Region &elseRegion = ifOp.getElseRegion();
172
if
(!llvm::hasSingleElement(elseRegion)) {
173
return
;
174
}
175
mlir::Block &elseBlock = elseRegion.front();
176
if
(!llvm::hasSingleElement(elseBlock)) {
177
return
;
178
}
179
if
(!llvm::isa<mlir::scf::YieldOp>(elseBlock.front())) {
180
return
;
181
}
182
elseRegion.dropAllReferences();
183
elseBlock.clear();
184
elseRegion.getBlocks().clear();
185
}
186
});
187
}
188
};
189
190
}
// namespace detail
191
192
inline
std::unique_ptr<mlir::Pass>
createRemoveDeadValuesWorkaroundPass
() {
193
return
std::make_unique<detail::RemoveDeadValuesWorkaroundPass>();
194
}
195
196
}
// namespace llzk
Walk.h
llzk::detail::RemoveDeadValuesWorkaroundPass
A workaround wrapper around MLIR's remove-dead-values pass that normalizes empty scf....
Definition
SpecializedMemoryPasses.h:142
llzk::detail::RemoveDeadValuesWorkaroundPass::runOnOperation
void runOnOperation() final
Definition
SpecializedMemoryPasses.h:149
llzk::detail::RemoveDeadValuesWorkaroundPass::getDescription
llvm::StringRef getDescription() const override
Definition
SpecializedMemoryPasses.h:147
llzk::detail::RemoveDeadValuesWorkaroundPass::getArgument
llvm::StringRef getArgument() const override
Definition
SpecializedMemoryPasses.h:146
llvm
Definition
SourceRefLattice.cpp:411
llzk
Definition
AnalysisPassEnums.cpp:19
llzk::createRemoveDeadValuesWorkaroundPass
std::unique_ptr< mlir::Pass > createRemoveDeadValuesWorkaroundPass()
Definition
SpecializedMemoryPasses.h:192
llzk::createSpecializedMem2RegPass
std::unique_ptr< SpecializedMem2Reg< AllocOpTy > > createSpecializedMem2RegPass()
Definition
SpecializedMemoryPasses.h:132
llzk::createSpecializedSROAPass
std::unique_ptr< SpecializedSROA< AllocOpTy > > createSpecializedSROAPass()
Definition
SpecializedMemoryPasses.h:81
llzk::SpecializedMem2Reg
A variant of the MLIR mem2reg pass that only promotes memory slots belonging to allocators of type Al...
Definition
SpecializedMemoryPasses.h:90
llzk::SpecializedMem2Reg::runOnOperation
void runOnOperation() override
Definition
SpecializedMemoryPasses.h:98
llzk::SpecializedMem2Reg::getArgument
mlir::StringRef getArgument() const override
Definition
SpecializedMemoryPasses.h:92
llzk::SpecializedMem2Reg::getDescription
mlir::StringRef getDescription() const override
Definition
SpecializedMemoryPasses.h:94
llzk::SpecializedSROA
A variant of the MLIR sroa pass that only destructures memory slots belonging to allocators of type A...
Definition
SpecializedMemoryPasses.h:41
llzk::SpecializedSROA::getDescription
mlir::StringRef getDescription() const override
Definition
SpecializedMemoryPasses.h:45
llzk::SpecializedSROA::runOnOperation
void runOnOperation() override
Definition
SpecializedMemoryPasses.h:49
llzk::SpecializedSROA::getArgument
mlir::StringRef getArgument() const override
Definition
SpecializedMemoryPasses.h:43
include
llzk
Transforms
SpecializedMemoryPasses.h
Generated by
1.17.0
Copyright 2025 Veridise Inc. under the Apache License v2.0. Copyright 2026 Project LLZK under the Apache License v2.0.