LLZK
3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Toggle main menu visibility
Loading...
Searching...
No Matches
ConstGlobalPropagationPass.cpp
Go to the documentation of this file.
1
//===-- ConstGlobalPropagationPass.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
15
#include "
llzk/Analysis/SymbolUseGraph.h
"
16
#include "
llzk/Dialect/Felt/IR/Ops.h
"
17
#include "
llzk/Dialect/Global/IR/Ops.h
"
18
#include "
llzk/Dialect/Global/Transforms/TransformationPasses.h
"
19
#include "
llzk/Dialect/Polymorphic/IR/Ops.h
"
20
#include "
llzk/Dialect/String/IR/Ops.h
"
21
#include "
llzk/Util/Debug.h
"
22
#include "
llzk/Util/SymbolTableLLZK.h
"
23
#include "
llzk/Util/TypeHelper.h
"
24
#include "
llzk/Util/Walk.h
"
25
26
#include <mlir/Dialect/Arith/IR/Arith.h>
27
28
#include <llvm/ADT/DenseMap.h>
29
#include <llvm/ADT/SmallVector.h>
30
31
#include <optional>
32
33
// Include the generated base pass class definitions.
34
namespace
llzk::global
{
35
#define GEN_PASS_DEF_CONSTGLOBALPROPAGATIONPASS
36
#include "
llzk/Dialect/Global/Transforms/TransformationPasses.h.inc
"
37
}
// namespace llzk::global
38
39
#define DEBUG_TYPE "llzk-const-global-propagation"
40
41
using namespace
mlir
;
42
using namespace
llzk
;
43
using namespace
llzk::global
;
44
45
namespace
{
46
47
static
Value convertToConstantValue(
GlobalReadOp
readOp, Attribute attr) {
48
OpBuilder bldr(readOp);
49
Location loc = readOp.getLoc();
50
if
(
auto
intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
51
return
arith::ConstantOp::create(bldr, loc, intAttr).getResult();
52
}
else
if
(
auto
feltAttr = llvm::dyn_cast<felt::FeltConstAttr>(attr)) {
53
Value constant =
felt::FeltConstantOp::create
(bldr, loc, feltAttr).
getResult
();
54
if
(constant.getType() == readOp.getType()) {
55
return
constant;
56
}
57
return
polymorphic::UnifiableCastOp::create
(bldr, loc, readOp.getType(), constant).
getResult
();
58
}
else
if
(
auto
strAttr = llvm::dyn_cast<StringAttr>(attr)) {
59
return
string::LitStringOp::create
(bldr, loc, readOp.getType(), strAttr).
getResult
();
60
}
else
{
61
llvm::outs() <<
"Encountered: "
<< attr.getAbstractAttribute().getName() <<
'\n'
;
62
llvm_unreachable(
"Unsupported constant attribute type"
);
63
}
64
}
65
66
class
PassImpl :
public
llzk::global::impl::ConstGlobalPropagationPassBase
<PassImpl> {
67
using
Base = ConstGlobalPropagationPassBase<PassImpl>;
68
69
public
:
70
using
Base::Base;
71
72
void
runOnOperation()
override
{
73
ModuleOp root = getOperation();
74
auto
constGlobals = walkCollect<GlobalDefOp>(root, [](
auto
g) {
return
g.isConstant(); });
75
if
(constGlobals.empty()) {
76
return
;
77
}
78
79
// Keep track of erased operations to skip them during the inner loop iteration and avoid
80
// use-after-free errors. These MUST NOT be dereferenced because the ops have been erased.
81
llvm::DenseSet<void *> erased;
82
SymbolUseGraph
&useGraph = getAnalysis<SymbolUseGraph>();
83
llvm::DenseMap<Operation *, SmallVector<const SymbolUseGraphNode *>> useNodesByDefinition;
84
SymbolTableCollection tables;
85
for
(
const
SymbolUseGraphNode
*candidate : useGraph.
nodesIter
()) {
86
auto
target = candidate->lookupSymbol(tables,
/*reportMissing=*/
false
);
87
if
(succeeded(target)) {
88
useNodesByDefinition[target->get()].push_back(candidate);
89
}
90
}
91
92
for
(
GlobalDefOp
globalDef : constGlobals) {
93
Attribute constValue = globalDef.getInitialValueAttr();
94
95
// Array constants cannot yet be materialized as operations. Leave both
96
// the global and all of its uses unchanged until they are supported.
97
if
(llvm::isa<ArrayAttr>(constValue)) {
98
continue
;
99
}
100
101
// A global definition and its uses can have different closest LLZK root
102
// modules after include inlining. Find every use-graph node that resolves
103
// to this definition instead of looking it up by a single symbol path.
104
for
(
const
SymbolUseGraphNode
*node : useNodesByDefinition[globalDef.getOperation()]) {
105
SymbolRefAttr symbolAttr = node->getSymbolPath();
106
for
(Operation *userOp : node->getUserOps()) {
107
// Skip erased ops to avoid use-after-free errors
108
if
(erased.contains(userOp)) {
109
continue
;
110
}
111
LLVM_DEBUG(
112
llvm::dbgs() <<
"Replacing '"
<< symbolAttr <<
"' with '"
<< constValue <<
"' in "
113
<< *userOp <<
'\n'
114
);
115
116
// Special handling to fully replace GlobalReadOp with the appropriate constant op.
117
if
(
auto
readOp = llvm::dyn_cast<GlobalReadOp>(userOp);
118
readOp && readOp.
getNameRef
() == symbolAttr) {
119
Value constantResult = convertToConstantValue(readOp, constValue);
120
readOp.getResult().replaceAllUsesWith(constantResult);
121
readOp.erase();
122
erased.insert(readOp);
123
continue
;
124
}
125
126
// Standard case that just replaces all uses of the symbol with the constant value.
127
AttrTypeReplacer replacer;
128
replacer.addReplacement([symbolAttr, constValue](SymbolRefAttr a) {
129
return
(a == symbolAttr) ? std::make_optional(constValue) : std::nullopt;
130
});
131
replacer.replaceElementsIn(
132
userOp,
133
/*replaceAttrs=*/
true
,
134
/*replaceLocs=*/
false
,
135
/*replaceTypes=*/
true
136
);
137
}
138
}
139
// Delete the const global since there are no (remaining) uses.
140
globalDef.erase();
141
erased.insert(globalDef);
142
}
143
}
144
};
145
146
}
// namespace
Debug.h
Ops.h
Ops.h
TransformationPasses.h.inc
TransformationPasses.h
Ops.h
Ops.h
SymbolTableLLZK.h
SymbolUseGraph.h
TypeHelper.h
Walk.h
llzk::SymbolUseGraphNode
Definition
SymbolUseGraph.h:27
llzk::SymbolUseGraph
Builds a graph structure representing the relationships between symbols and their uses.
Definition
SymbolUseGraph.h:124
llzk::SymbolUseGraph::nodesIter
llvm::iterator_range< iterator > nodesIter() const
Range over all nodes in the graph.
Definition
SymbolUseGraph.h:199
llzk::felt::FeltConstantOp::getResult
::mlir::TypedValue<::mlir::Type > getResult()
Definition
Ops.h.inc:1017
llzk::felt::FeltConstantOp::create
static FeltConstantOp create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Type result, ::llzk::felt::FeltConstAttr value)
Definition
Ops.cpp.inc:1274
llzk::global::GlobalDefOp
Definition
Ops.h.inc:202
llzk::global::GlobalReadOp
Definition
Ops.h.inc:491
llzk::global::GlobalReadOp::getNameRef
::mlir::SymbolRefAttr getNameRef()
Definition
Ops.cpp.inc:875
llzk::global::impl::ConstGlobalPropagationPassBase
Definition
ConstGlobalPropagationPass.cpp:25
llzk::polymorphic::UnifiableCastOp::getResult
::mlir::TypedValue<::mlir::Type > getResult()
Definition
Ops.h.inc:1557
llzk::polymorphic::UnifiableCastOp::create
static UnifiableCastOp create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Type result, ::mlir::Value input)
Definition
Ops.cpp.inc:1908
llzk::string::LitStringOp::create
static LitStringOp create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Type result, ::mlir::StringAttr value)
Definition
Ops.cpp.inc:174
llzk::string::LitStringOp::getResult
::mlir::TypedValue<::llzk::string::StringType > getResult()
Definition
Ops.h.inc:169
llzk::global
Definition
InitializerUtils.h:16
llzk
Definition
AnalysisPassEnums.cpp:19
mlir
Definition
CommonCAPIGen.h:50
lib
Dialect
Global
Transforms
ConstGlobalPropagationPass.cpp
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.