LLZK 3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
SymbolHelper.h
Go to the documentation of this file.
1//===-- SymbolHelper.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//===----------------------------------------------------------------------===//
9
10#pragma once
11
14
15#include <mlir/IR/Diagnostics.h>
16#include <mlir/Interfaces/CallInterfaces.h>
17
18#include <llvm/ADT/STLFunctionalExtras.h>
19
20#include <cassert>
21#include <optional>
22#include <ranges>
23
24namespace llzk {
25
26namespace component {
27class StructType;
28class StructDefOp;
29class MemberDefOp;
30} // namespace component
31
32namespace function {
33class FuncDefOp;
34} // namespace function
35namespace polymorphic {
36class TemplateOp;
37class TemplateParamOp;
38} // namespace polymorphic
39
41void eraseEmptyNestedModules(mlir::ModuleOp rootModule);
42
43llvm::SmallVector<mlir::StringRef> getNames(mlir::SymbolRefAttr ref);
44llvm::SmallVector<mlir::FlatSymbolRefAttr> getPieces(mlir::SymbolRefAttr ref);
45
47inline mlir::FlatSymbolRefAttr
48getFlatSymbolRefAttr(mlir::MLIRContext *context, const mlir::Twine &twine) {
49 return mlir::FlatSymbolRefAttr::get(mlir::StringAttr::get(context, twine));
50}
51
53inline mlir::SymbolRefAttr asSymbolRefAttr(mlir::StringAttr root, mlir::SymbolRefAttr tail) {
54 return mlir::SymbolRefAttr::get(root, getPieces(tail));
55}
56
58inline mlir::SymbolRefAttr asSymbolRefAttr(llvm::ArrayRef<mlir::FlatSymbolRefAttr> path) {
59 return mlir::SymbolRefAttr::get(path.front().getAttr(), path.drop_front());
60}
61
63inline mlir::SymbolRefAttr asSymbolRefAttr(const std::vector<mlir::FlatSymbolRefAttr> &path) {
64 return asSymbolRefAttr(llvm::ArrayRef<mlir::FlatSymbolRefAttr>(path));
65}
66
68inline mlir::SymbolRefAttr getTailAsSymbolRefAttr(mlir::SymbolRefAttr symbol) {
69 return asSymbolRefAttr(symbol.getNestedReferences());
70}
71
73inline mlir::SymbolRefAttr getPrefixAsSymbolRefAttr(mlir::SymbolRefAttr symbol) {
74 return mlir::SymbolRefAttr::get(
75 symbol.getRootReference(), symbol.getNestedReferences().drop_back()
76 );
77}
78
80mlir::SymbolRefAttr replaceLeaf(mlir::SymbolRefAttr orig, mlir::FlatSymbolRefAttr newLeaf);
81inline mlir::SymbolRefAttr replaceLeaf(mlir::SymbolRefAttr orig, mlir::StringAttr newLeaf) {
82 return replaceLeaf(orig, mlir::FlatSymbolRefAttr::get(newLeaf));
83}
84inline mlir::SymbolRefAttr replaceLeaf(mlir::SymbolRefAttr orig, const mlir::Twine &newLeaf) {
85 return replaceLeaf(orig, mlir::StringAttr::get(orig.getContext(), newLeaf));
86}
87
89mlir::SymbolRefAttr appendLeaf(mlir::SymbolRefAttr orig, mlir::FlatSymbolRefAttr newLeaf);
90inline mlir::SymbolRefAttr appendLeaf(mlir::SymbolRefAttr orig, mlir::StringAttr newLeaf) {
91 return appendLeaf(orig, mlir::FlatSymbolRefAttr::get(newLeaf));
92}
93inline mlir::SymbolRefAttr appendLeaf(mlir::SymbolRefAttr orig, const mlir::Twine &newLeaf) {
94 return appendLeaf(orig, mlir::StringAttr::get(orig.getContext(), newLeaf));
95}
96
99mlir::SymbolRefAttr appendLeafName(mlir::SymbolRefAttr orig, const mlir::Twine &newLeafSuffix);
100
103mlir::FailureOr<mlir::ModuleOp> getRootModule(mlir::Operation *from);
104mlir::FailureOr<mlir::SymbolRefAttr>
105getPathFromRoot(mlir::SymbolOpInterface to, mlir::ModuleOp *foundRoot = nullptr);
106mlir::FailureOr<mlir::SymbolRefAttr>
107getPathFromRoot(component::StructDefOp &to, mlir::ModuleOp *foundRoot = nullptr);
108mlir::FailureOr<mlir::SymbolRefAttr>
109getPathFromRoot(component::MemberDefOp &to, mlir::ModuleOp *foundRoot = nullptr);
110mlir::FailureOr<mlir::SymbolRefAttr>
111getPathFromRoot(function::FuncDefOp &to, mlir::ModuleOp *foundRoot = nullptr);
112
122mlir::FailureOr<mlir::SymbolRefAttr> getPathRelativeToAncestor(
123 mlir::SymbolOpInterface symbol, mlir::ModuleOp ancestor,
124 llvm::function_ref<mlir::InFlightDiagnostic()> emitError = nullptr
125);
126
130inline mlir::SymbolRefAttr
131getFullyQualifiedName(mlir::SymbolOpInterface symbol, bool requireParent = true) {
132 if (!requireParent && symbol.getOperation()->getParentOp() == nullptr) {
133 return mlir::SymbolRefAttr::get(symbol.getOperation());
134 }
135 mlir::FailureOr<mlir::SymbolRefAttr> res = getPathFromRoot(symbol);
136 assert(mlir::succeeded(res));
137 return res.value();
138}
139
142mlir::FailureOr<mlir::ModuleOp> getTopRootModule(mlir::Operation *from);
143mlir::FailureOr<mlir::SymbolRefAttr>
144getPathFromTopRoot(mlir::SymbolOpInterface to, mlir::ModuleOp *foundRoot = nullptr);
145mlir::FailureOr<mlir::SymbolRefAttr>
146getPathFromTopRoot(component::StructDefOp &to, mlir::ModuleOp *foundRoot = nullptr);
147mlir::FailureOr<mlir::SymbolRefAttr>
148getPathFromTopRoot(component::MemberDefOp &to, mlir::ModuleOp *foundRoot = nullptr);
149mlir::FailureOr<mlir::SymbolRefAttr>
150getPathFromTopRoot(function::FuncDefOp &to, mlir::ModuleOp *foundRoot = nullptr);
151
156mlir::FailureOr<llzk::component::StructType> getMainInstanceType(mlir::Operation *lookupFrom);
157
162mlir::FailureOr<SymbolLookupResult<llzk::component::StructDefOp>>
163getMainInstanceDef(mlir::SymbolTableCollection &symbolTable, mlir::Operation *lookupFrom);
164
168mlir::FailureOr<SymbolLookupResult<component::StructDefOp>> getRootStructDef(
169 mlir::SymbolTableCollection &tables, mlir::Operation *lookupFrom,
170 mlir::StringRef symbolPath = {}
171);
172
178template <typename T>
179inline mlir::FailureOr<SymbolLookupResult<T>>
180resolveCallable(mlir::SymbolTableCollection &symbolTable, mlir::CallOpInterface call) {
181 mlir::CallInterfaceCallable callable = call.getCallableForCallee();
182 if (auto symbolVal = llvm::dyn_cast<mlir::Value>(callable)) {
183 return SymbolLookupResult<T>(symbolVal.getDefiningOp());
184 }
185
186 // If the callable isn't a value, lookup the symbol reference.
187 // We first try to resolve in the nearest symbol table, as per the default
188 // MLIR behavior. If the resulting operation is not found, we will then
189 // use the LLZK lookup helpers.
190 auto symbolRef = llvm::cast<mlir::SymbolRefAttr>(callable);
191 mlir::Operation *op = symbolTable.lookupNearestSymbolFrom(call.getOperation(), symbolRef);
192
193 if (op) {
194 return SymbolLookupResult<T>(std::move(op));
195 }
196 // Otherwise, use the top-level lookup.
197 return lookupTopLevelSymbol<T>(symbolTable, symbolRef, call.getOperation());
198}
199
204template <typename T>
205inline mlir::FailureOr<SymbolLookupResult<T>>
206resolveCallableSilently(mlir::SymbolTableCollection &symbolTable, mlir::CallOpInterface call) {
207 mlir::CallInterfaceCallable callable = call.getCallableForCallee();
208 if (auto symbolVal = llvm::dyn_cast<mlir::Value>(callable)) {
209 SymbolLookupResult<T> result(symbolVal.getDefiningOp());
210 if (!result) {
211 return mlir::failure();
212 }
213 return result;
214 }
215
216 auto symbolRef = llvm::cast<mlir::SymbolRefAttr>(callable);
217 if (mlir::Operation *op = symbolTable.lookupNearestSymbolFrom(call.getOperation(), symbolRef)) {
218 SymbolLookupResult<T> result(op);
219 if (!result) {
220 return mlir::failure();
221 }
222 return result;
223 }
225 symbolTable, symbolRef, call.getOperation(), /*reportMissing=*/false
226 );
227}
228
229template <typename T>
230inline mlir::FailureOr<SymbolLookupResult<T>> resolveCallable(mlir::CallOpInterface call) {
231 mlir::SymbolTableCollection symbolTable;
232 return resolveCallable<T>(symbolTable, call);
233}
234
240mlir::FailureOr<polymorphic::TemplateOp>
241getConstResolutionTemplate(mlir::SymbolTableCollection &tables, mlir::Operation *origin);
242
245mlir::LogicalResult verifyTemplateParamSymbol(
246 mlir::SymbolTableCollection &tables, mlir::SymbolRefAttr symbol, mlir::Operation *origin
247);
248
252 mlir::Operation *origin, mlir::Attribute value, polymorphic::TemplateParamOp targetParam
253);
254
258 mlir::Operation *origin, mlir::ArrayAttr explicitParams,
259 llvm::iterator_range<mlir::Region::op_iterator<polymorphic::TemplateParamOp>> targetParamDefs
260);
261
271 mlir::Operation *origin, mlir::ArrayAttr explicitParams,
272 llvm::iterator_range<mlir::Region::op_iterator<polymorphic::TemplateParamOp>> targetParamDefs,
273 const UnificationMap &unifications
274);
275
278mlir::LogicalResult verifyParamOfType(
279 mlir::SymbolTableCollection &tables, mlir::SymbolRefAttr param, mlir::Type structOrArrayType,
280 mlir::Operation *origin, std::optional<mlir::Type> requiredParamType = std::nullopt
281);
282
286mlir::LogicalResult verifyParamsOfType(
287 mlir::SymbolTableCollection &tables, mlir::ArrayRef<mlir::Attribute> tyParams,
288 mlir::Type structOrArrayType, mlir::Operation *origin,
289 std::optional<mlir::Type> requiredParamType = std::nullopt
290);
291
293mlir::FailureOr<component::StructDefOp> verifyStructTypeResolution(
294 mlir::SymbolTableCollection &tables, component::StructType ty, mlir::Operation *origin
295);
296
298mlir::LogicalResult
299verifyTypeResolution(mlir::SymbolTableCollection &tables, mlir::Operation *origin, mlir::Type type);
300
302template <std::ranges::input_range Range>
303mlir::LogicalResult verifyTypeResolution(
304 mlir::SymbolTableCollection &tables, mlir::Operation *origin, const Range &types
305) {
306 // Check all before returning to present all applicable type errors in one compilation.
307 bool failed = false;
308 for (const auto &t : types) {
309 failed |= mlir::failed(verifyTypeResolution(tables, origin, t));
310 }
311 return mlir::LogicalResult::failure(failed);
312}
313
314} // namespace llzk
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation and configuration files Object form shall mean any form resulting from mechanical transformation or translation of a Source including but not limited to compiled object generated and conversions to other media types Work shall mean the work of whether in Source or Object made available under the as indicated by a copyright notice that is included in or attached to the whether in Source or Object that is based or other modifications as a an original work of authorship For the purposes of this Derivative Works shall not include works that remain separable from
Definition LICENSE.txt:45
This file defines methods symbol lookup across LLZK operations and included files.
mlir::SymbolRefAttr getPrefixAsSymbolRefAttr(mlir::SymbolRefAttr symbol)
Return SymbolRefAttr like the one given but with the leaf/final element removed.
SymbolRefAttr appendLeafName(SymbolRefAttr orig, const Twine &newLeafSuffix)
mlir::FlatSymbolRefAttr getFlatSymbolRefAttr(mlir::MLIRContext *context, const mlir::Twine &twine)
Construct a FlatSymbolRefAttr with the given content.
mlir::FailureOr< SymbolLookupResultUntyped > lookupTopLevelSymbol(mlir::SymbolTableCollection &tables, mlir::SymbolRefAttr symbol, mlir::Operation *origin, bool reportMissing=true)
FailureOr< StructType > getMainInstanceType(Operation *lookupFrom)
llvm::SmallVector< StringRef > getNames(SymbolRefAttr ref)
FailureOr< ModuleOp > getRootModule(Operation *from)
FailureOr< TemplateOp > getConstResolutionTemplate(SymbolTableCollection &tables, Operation *origin)
LogicalResult verifyTemplateParamsMatchInferred(Operation *origin, ArrayAttr explicitParams, llvm::iterator_range< Region::op_iterator< TemplateParamOp > > targetParamDefs, const UnificationMap &unifications)
mlir::DenseMap< std::pair< mlir::SymbolRefAttr, Side >, mlir::Attribute > UnificationMap
Optional result from type unifications.
Definition TypeHelper.h:208
SymbolRefAttr appendLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf)
SymbolRefAttr replaceLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf)
FailureOr< StructDefOp > verifyStructTypeResolution(SymbolTableCollection &tables, StructType ty, Operation *origin)
mlir::FailureOr< SymbolLookupResult< T > > resolveCallable(mlir::SymbolTableCollection &symbolTable, mlir::CallOpInterface call)
Based on mlir::CallOpInterface::resolveCallable, but using LLZK lookup helpers.
FailureOr< ModuleOp > getTopRootModule(Operation *from)
LogicalResult verifyParamsOfType(SymbolTableCollection &tables, ArrayRef< Attribute > tyParams, Type parameterizedType, Operation *origin, std::optional< Type > requiredParamType)
LogicalResult verifyTypeResolution(SymbolTableCollection &tables, Operation *origin, Type ty)
LogicalResult verifyTemplateParamValueCompatibility(Operation *origin, Attribute value, TemplateParamOp targetParam)
mlir::FailureOr< SymbolLookupResult< T > > resolveCallableSilently(mlir::SymbolTableCollection &symbolTable, mlir::CallOpInterface call)
Resolve a callable without emitting a diagnostic for missing top-level symbols.
LogicalResult verifyTemplateParamValuesCompatibility(Operation *origin, ArrayAttr explicitParams, llvm::iterator_range< Region::op_iterator< TemplateParamOp > > targetParamDefs)
mlir::SymbolRefAttr asSymbolRefAttr(mlir::StringAttr root, mlir::SymbolRefAttr tail)
Build a SymbolRefAttr that prepends tail with root, i.e., root::tail.
mlir::SymbolRefAttr getFullyQualifiedName(mlir::SymbolOpInterface symbol, bool requireParent=true)
Return the full name for this symbol from the root module, including any surrounding symbol table nam...
mlir::SymbolRefAttr getTailAsSymbolRefAttr(mlir::SymbolRefAttr symbol)
Return SymbolRefAttr like the one given but with the root/head element removed.
void eraseEmptyNestedModules(ModuleOp rootModule)
FailureOr< SymbolLookupResult< StructDefOp > > getMainInstanceDef(SymbolTableCollection &symbolTable, Operation *lookupFrom)
FailureOr< SymbolRefAttr > getPathFromTopRoot(SymbolOpInterface to, ModuleOp *foundRoot)
FailureOr< SymbolRefAttr > getPathRelativeToAncestor(SymbolOpInterface symbol, ModuleOp ancestor, llvm::function_ref< InFlightDiagnostic()> emitError)
LogicalResult verifyTemplateParamSymbol(SymbolTableCollection &tables, SymbolRefAttr symbol, Operation *origin)
llvm::SmallVector< FlatSymbolRefAttr > getPieces(SymbolRefAttr ref)
FailureOr< SymbolLookupResult< StructDefOp > > getRootStructDef(SymbolTableCollection &tables, Operation *lookupFrom, StringRef symbolPath)
FailureOr< SymbolRefAttr > getPathFromRoot(SymbolOpInterface to, ModuleOp *foundRoot)
LogicalResult verifyParamOfType(SymbolTableCollection &tables, SymbolRefAttr param, Type parameterizedType, Operation *origin, std::optional< Type > requiredParamType)