LLZK 3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
SharedImpl.h
Go to the documentation of this file.
1//===-- SharedImpl.h --------------------------------------------*- 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
15#pragma once
16
28
29#include <mlir/Dialect/Arith/IR/Arith.h>
30#include <mlir/Dialect/SCF/IR/SCF.h>
31#include <mlir/Dialect/SCF/Transforms/Patterns.h>
32#include <mlir/IR/Attributes.h>
33#include <mlir/IR/BuiltinAttributes.h>
34#include <mlir/IR/MLIRContext.h>
35#include <mlir/IR/Operation.h>
36#include <mlir/IR/PatternMatch.h>
37#include <mlir/IR/SymbolTable.h>
38#include <mlir/Transforms/DialectConversion.h>
39
40#include <llvm/ADT/DenseMap.h>
41#include <llvm/ADT/DenseSet.h>
42#include <llvm/ADT/STLExtras.h>
43#include <llvm/ADT/SmallVector.h>
44#include <llvm/Support/Debug.h>
45
46#define DEBUG_TYPE "poly-dialect-shared"
47
49
50namespace {
51
52// Default to true if the check is not for that particular operation type.
53template <typename Check> inline bool runCheck(mlir::Operation *op, Check check) {
54 if (auto specificOp =
55 llvm::dyn_cast_if_present<typename llvm::function_traits<Check>::template arg_t<0>>(op)) {
56 return check(specificOp);
57 }
58 return true;
59}
60
61} // namespace
62
64mlir::ConversionTarget newBaseTarget(mlir::MLIRContext *ctx);
65
68public:
69 mlir::SymbolTableCollection tables;
70
72 mlir::ModuleOp root, const SymbolDefTree &symDefTree, const SymbolUseGraph &symUseGraph
73 );
74
75protected:
76 mlir::ModuleOp rootMod;
79};
80
82bool isErasableDefinition(mlir::Operation *op);
83
86class FromEraseSet : public CleanupBase {
87public:
90 mlir::ModuleOp root, const SymbolDefTree &symDefTree, const SymbolUseGraph &symUseGraph,
91 llvm::DenseSet<mlir::SymbolRefAttr> &&tryToErasePaths
92 );
93
94 mlir::LogicalResult eraseUnusedDefinitions();
95
96 const llvm::DenseSet<mlir::SymbolOpInterface> &getTryToEraseSet() const { return tryToErase; }
97
98private:
100 llvm::DenseSet<mlir::SymbolOpInterface> tryToErase;
102 llvm::DenseMap<mlir::SymbolOpInterface, bool> visitedPlusSafetyResult;
104 llvm::DenseMap<const SymbolUseGraphNode *, mlir::SymbolOpInterface> lookupCache;
105
106 bool collectSafeToErase(mlir::SymbolOpInterface check);
107 bool collectSafeToErase(const SymbolDefTreeNode *check);
108 bool collectSafeToErase(const SymbolUseGraphNode *check);
109 mlir::SymbolOpInterface cachedLookup(const SymbolUseGraphNode *node);
110};
111
117array::ArrayType flattenInstantiatedArrayType(array::ArrayType inputTy, mlir::Type convertedElemTy);
118
121getStructTypeWithParams(mlir::SymbolRefAttr nameRef, mlir::ArrayAttr params) {
122 return params && !params.empty() ? component::StructType::get(nameRef, params)
124}
125
128 mlir::SymbolRefAttr nameRef, mlir::MLIRContext *ctx, mlir::ArrayRef<mlir::Attribute> params
129) {
130 return params.empty() ? component::StructType::get(nameRef)
131 : component::StructType::get(nameRef, mlir::ArrayAttr::get(ctx, params));
132}
133
137 mlir::SmallVector<mlir::Attribute> remainingNames;
139 mlir::ArrayAttr rewrittenCallParams;
140};
141
146 TemplateOp parentTemplate, mlir::ArrayAttr callParams,
147 const llvm::DenseMap<mlir::Attribute, mlir::Attribute> &paramNameToConcrete
148) {
149 mlir::SmallVector<mlir::Attribute> remainingNames;
150 mlir::SmallVector<mlir::Attribute> attrsForInstantiatedNameSuffix;
151 for (mlir::Attribute paramName : parentTemplate.getConstNames<TemplateParamOp>()) {
152 auto it = paramNameToConcrete.find(paramName);
153 if (it != paramNameToConcrete.end()) {
154 attrsForInstantiatedNameSuffix.push_back(it->second);
155 } else {
156 attrsForInstantiatedNameSuffix.push_back(nullptr);
157 remainingNames.push_back(paramName);
158 }
159 }
160
161 mlir::ArrayAttr rewrittenCallParams = nullptr;
162 if (!isNullOrEmpty(callParams) && !remainingNames.empty()) {
163 mlir::SmallVector<mlir::Attribute> remainingCallParams;
164 for (auto [paramOp, attr] :
165 llvm::zip_equal(parentTemplate.getConstOps<TemplateParamOp>(), callParams.getValue())) {
166 auto paramName = mlir::FlatSymbolRefAttr::get(paramOp.getSymNameAttr());
167 if (!paramNameToConcrete.contains(paramName)) {
168 remainingCallParams.push_back(attr);
169 }
170 }
171 rewrittenCallParams = mlir::ArrayAttr::get(parentTemplate.getContext(), remainingCallParams);
172 }
173
174 return {
175 std::move(remainingNames),
176 BuildShortTypeString::from(parentTemplate.getSymName().str(), attrsForInstantiatedNameSuffix),
177 rewrittenCallParams,
178 };
179}
180
182public:
183 virtual ~LegalityCheckCallback() = default;
184 virtual void checkStarted() = 0;
185 virtual void checkEnded(bool outcome) = 0;
186};
187
189public:
190 void checkStarted() override {}
191 void checkEnded(bool) override {}
192};
193
200template <typename... AdditionalOpClasses, typename... AdditionalChecks>
201mlir::ConversionTarget newConverterDefinedTarget(
202 mlir::TypeConverter &tyConv, mlir::MLIRContext *ctx, AdditionalChecks &&...checks
203) {
204 static EmptyLegalityCheckCallback empty;
205 return newConverterDefinedTargetWithCallback<AdditionalOpClasses...>(
206 tyConv, ctx, empty, (std::forward<AdditionalChecks>(checks))...
207 );
208}
209
216template <typename... AdditionalOpClasses, typename... AdditionalChecks>
218 mlir::TypeConverter &tyConv, mlir::MLIRContext *ctx, LegalityCheckCallback &cb,
219 AdditionalChecks &&...checks
220) {
221 mlir::ConversionTarget target = newBaseTarget(ctx);
222 auto inserter = [&](auto... opClasses) {
223 target.addDynamicallyLegalOp<decltype(opClasses)...>([&cb, &tyConv,
224 &checks...](mlir::Operation *op) {
225 LLVM_DEBUG(if (op) {
226 llvm::dbgs() << "[newConverterDefinedTarget] checking legality of ";
227 op->dump();
228 });
229 cb.checkStarted();
230 auto legality =
231 defaultLegalityCheck(tyConv, op) && (runCheck<AdditionalChecks>(op, checks) && ...);
232
233 cb.checkEnded(legality);
234 LLVM_DEBUG(if (legality) { llvm::dbgs() << "[newConverterDefinedTarget] is legal\n"; } else {
235 llvm::dbgs() << "[newConverterDefinedTarget] is not legal\n";
236 });
237 return legality;
238 });
239 };
240 std::apply(inserter, OpClassesWithStructTypes.NoGeneralBuilder);
241 std::apply(inserter, OpClassesWithStructTypes.WithGeneralBuilder);
242 applyToMoreTypes<decltype(inserter), AdditionalOpClasses...>(inserter);
243 return target;
244}
245
246} // namespace llzk::polymorphic::detail
247
248#undef DEBUG_TYPE
#define check(x)
Definition Ops.cpp:286
Reusable MLIR dialect conversion functions for LLZK StructType replacement.
static std::string from(mlir::Type type)
Return a brief string representation of the given LLZK type.
Definition TypeHelper.h:55
Builds a tree structure representing the symbol table structure.
Builds a graph structure representing the relationships between symbols and their uses.
static StructType get(::mlir::SymbolRefAttr structName)
Definition Types.cpp.inc:79
::llvm::SmallVector<::mlir::Attribute > getConstNames()
Return the names of all ops of type OpT within the body region in the order they are defined.
Definition Ops.h.inc:941
::llvm::StringRef getSymName()
Definition Ops.cpp.inc:1059
inline ::llvm::iterator_range<::mlir::Region::op_iterator< OpT > > getConstOps()
Return ops of type OpT within the body region.
Definition Ops.h.inc:921
const SymbolUseGraph & useGraph
Definition SharedImpl.h:78
mlir::SymbolTableCollection tables
Definition SharedImpl.h:69
CleanupBase(mlir::ModuleOp root, const SymbolDefTree &symDefTree, const SymbolUseGraph &symUseGraph)
mlir::LogicalResult eraseUnusedDefinitions()
const llvm::DenseSet< mlir::SymbolOpInterface > & getTryToEraseSet() const
Definition SharedImpl.h:96
FromEraseSet(mlir::ModuleOp root, const SymbolDefTree &symDefTree, const SymbolUseGraph &symUseGraph, llvm::DenseSet< mlir::SymbolRefAttr > &&tryToErasePaths)
Note: paths in tryToErase should be relative to root.
component::StructType getStructTypeWithParams(mlir::SymbolRefAttr nameRef, mlir::ArrayAttr params)
Build a struct type while representing an empty parameter list as absent.
Definition SharedImpl.h:121
mlir::ConversionTarget newConverterDefinedTargetWithCallback(mlir::TypeConverter &tyConv, mlir::MLIRContext *ctx, LegalityCheckCallback &cb, AdditionalChecks &&...checks)
Return a new ConversionTarget allowing all LLZK-required dialects and defining Op legality based on t...
Definition SharedImpl.h:217
InstantiationLayout buildInstantiationLayout(TemplateOp parentTemplate, mlir::ArrayAttr callParams, const llvm::DenseMap< mlir::Attribute, mlir::Attribute > &paramNameToConcrete)
Derive the instantiated template name and the remaining explicit parameters that should stay on the r...
Definition SharedImpl.h:145
mlir::ConversionTarget newConverterDefinedTarget(mlir::TypeConverter &tyConv, mlir::MLIRContext *ctx, AdditionalChecks &&...checks)
Return a new ConversionTarget allowing all LLZK-required dialects and defining Op legality based on t...
Definition SharedImpl.h:201
bool isErasableDefinition(mlir::Operation *op)
Return true iff op is a cleanup candidate.
mlir::ConversionTarget newBaseTarget(mlir::MLIRContext *ctx)
Return a new ConversionTarget allowing all LLZK-required dialects.
array::ArrayType flattenInstantiatedArrayType(array::ArrayType inputTy, mlir::Type convertedElemTy)
Merge nested array dimensions produced by replacing an array element type.
bool isNullOrEmpty(mlir::ArrayAttr a)
bool defaultLegalityCheck(const mlir::TypeConverter &tyConv, mlir::Operation *op)
Check whether an op is legal with respect to the given type converter, including TypeAttr attributes ...
Groups the information needed after concrete parameters have been chosen to decide how to name a new ...
Definition SharedImpl.h:136
mlir::SmallVector< mlir::Attribute > remainingNames
Definition SharedImpl.h:137