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
13
14#include <mlir/Interfaces/CallInterfaces.h>
15
16#include <cassert>
17#include <optional>
18#include <ranges>
19
20namespace llzk {
21
22namespace component {
23class StructType;
24class StructDefOp;
25class MemberDefOp;
26} // namespace component
27
28namespace function {
29class FuncDefOp;
30} // namespace function
31namespace polymorphic {
32class TemplateOp;
33} // namespace polymorphic
34
35llvm::SmallVector<mlir::StringRef> getNames(mlir::SymbolRefAttr ref);
36llvm::SmallVector<mlir::FlatSymbolRefAttr> getPieces(mlir::SymbolRefAttr ref);
37
39inline mlir::FlatSymbolRefAttr
40getFlatSymbolRefAttr(mlir::MLIRContext *context, const mlir::Twine &twine) {
41 return mlir::FlatSymbolRefAttr::get(mlir::StringAttr::get(context, twine));
42}
43
45inline mlir::SymbolRefAttr asSymbolRefAttr(mlir::StringAttr root, mlir::SymbolRefAttr tail) {
46 return mlir::SymbolRefAttr::get(root, getPieces(tail));
47}
48
50inline mlir::SymbolRefAttr asSymbolRefAttr(llvm::ArrayRef<mlir::FlatSymbolRefAttr> path) {
51 return mlir::SymbolRefAttr::get(path.front().getAttr(), path.drop_front());
52}
53
55inline mlir::SymbolRefAttr asSymbolRefAttr(const std::vector<mlir::FlatSymbolRefAttr> &path) {
56 return asSymbolRefAttr(llvm::ArrayRef<mlir::FlatSymbolRefAttr>(path));
57}
58
60inline mlir::SymbolRefAttr getTailAsSymbolRefAttr(mlir::SymbolRefAttr symbol) {
61 return asSymbolRefAttr(symbol.getNestedReferences());
62}
63
65inline mlir::SymbolRefAttr getPrefixAsSymbolRefAttr(mlir::SymbolRefAttr symbol) {
66 return mlir::SymbolRefAttr::get(
67 symbol.getRootReference(), symbol.getNestedReferences().drop_back()
68 );
69}
70
72mlir::SymbolRefAttr replaceLeaf(mlir::SymbolRefAttr orig, mlir::FlatSymbolRefAttr newLeaf);
73inline mlir::SymbolRefAttr replaceLeaf(mlir::SymbolRefAttr orig, mlir::StringAttr newLeaf) {
74 return replaceLeaf(orig, mlir::FlatSymbolRefAttr::get(newLeaf));
75}
76inline mlir::SymbolRefAttr replaceLeaf(mlir::SymbolRefAttr orig, const mlir::Twine &newLeaf) {
77 return replaceLeaf(orig, mlir::StringAttr::get(orig.getContext(), newLeaf));
78}
79
81mlir::SymbolRefAttr appendLeaf(mlir::SymbolRefAttr orig, mlir::FlatSymbolRefAttr newLeaf);
82inline mlir::SymbolRefAttr appendLeaf(mlir::SymbolRefAttr orig, mlir::StringAttr newLeaf) {
83 return appendLeaf(orig, mlir::FlatSymbolRefAttr::get(newLeaf));
84}
85inline mlir::SymbolRefAttr appendLeaf(mlir::SymbolRefAttr orig, const mlir::Twine &newLeaf) {
86 return appendLeaf(orig, mlir::StringAttr::get(orig.getContext(), newLeaf));
87}
88
91mlir::SymbolRefAttr appendLeafName(mlir::SymbolRefAttr orig, const mlir::Twine &newLeafSuffix);
92
95mlir::FailureOr<mlir::ModuleOp> getRootModule(mlir::Operation *from);
96mlir::FailureOr<mlir::SymbolRefAttr>
97getPathFromRoot(mlir::SymbolOpInterface to, mlir::ModuleOp *foundRoot = nullptr);
98mlir::FailureOr<mlir::SymbolRefAttr>
99getPathFromRoot(component::StructDefOp &to, mlir::ModuleOp *foundRoot = nullptr);
100mlir::FailureOr<mlir::SymbolRefAttr>
101getPathFromRoot(component::MemberDefOp &to, mlir::ModuleOp *foundRoot = nullptr);
102mlir::FailureOr<mlir::SymbolRefAttr>
103getPathFromRoot(function::FuncDefOp &to, mlir::ModuleOp *foundRoot = nullptr);
104
108inline mlir::SymbolRefAttr
109getFullyQualifiedName(mlir::SymbolOpInterface symbol, bool requireParent = true) {
110 if (!requireParent && symbol.getOperation()->getParentOp() == nullptr) {
111 return mlir::SymbolRefAttr::get(symbol.getOperation());
112 }
113 mlir::FailureOr<mlir::SymbolRefAttr> res = getPathFromRoot(symbol);
114 assert(mlir::succeeded(res));
115 return res.value();
116}
117
120mlir::FailureOr<mlir::ModuleOp> getTopRootModule(mlir::Operation *from);
121mlir::FailureOr<mlir::SymbolRefAttr>
122getPathFromTopRoot(mlir::SymbolOpInterface to, mlir::ModuleOp *foundRoot = nullptr);
123mlir::FailureOr<mlir::SymbolRefAttr>
124getPathFromTopRoot(component::StructDefOp &to, mlir::ModuleOp *foundRoot = nullptr);
125mlir::FailureOr<mlir::SymbolRefAttr>
126getPathFromTopRoot(component::MemberDefOp &to, mlir::ModuleOp *foundRoot = nullptr);
127mlir::FailureOr<mlir::SymbolRefAttr>
128getPathFromTopRoot(function::FuncDefOp &to, mlir::ModuleOp *foundRoot = nullptr);
129
134mlir::FailureOr<llzk::component::StructType> getMainInstanceType(mlir::Operation *lookupFrom);
135
140mlir::FailureOr<SymbolLookupResult<llzk::component::StructDefOp>>
141getMainInstanceDef(mlir::SymbolTableCollection &symbolTable, mlir::Operation *lookupFrom);
142
148template <typename T>
149inline mlir::FailureOr<SymbolLookupResult<T>>
150resolveCallable(mlir::SymbolTableCollection &symbolTable, mlir::CallOpInterface call) {
151 mlir::CallInterfaceCallable callable = call.getCallableForCallee();
152 if (auto symbolVal = llvm::dyn_cast<mlir::Value>(callable)) {
153 return SymbolLookupResult<T>(symbolVal.getDefiningOp());
154 }
155
156 // If the callable isn't a value, lookup the symbol reference.
157 // We first try to resolve in the nearest symbol table, as per the default
158 // MLIR behavior. If the resulting operation is not found, we will then
159 // use the LLZK lookup helpers.
160 auto symbolRef = llvm::cast<mlir::SymbolRefAttr>(callable);
161 mlir::Operation *op = symbolTable.lookupNearestSymbolFrom(call.getOperation(), symbolRef);
162
163 if (op) {
164 return SymbolLookupResult<T>(std::move(op));
165 }
166 // Otherwise, use the top-level lookup.
167 return lookupTopLevelSymbol<T>(symbolTable, symbolRef, call.getOperation());
168}
169
174template <typename T>
175inline mlir::FailureOr<SymbolLookupResult<T>>
176resolveCallableSilently(mlir::SymbolTableCollection &symbolTable, mlir::CallOpInterface call) {
177 mlir::CallInterfaceCallable callable = call.getCallableForCallee();
178 if (auto symbolVal = llvm::dyn_cast<mlir::Value>(callable)) {
179 SymbolLookupResult<T> result(symbolVal.getDefiningOp());
180 if (!result) {
181 return mlir::failure();
182 }
183 return result;
184 }
185
186 auto symbolRef = llvm::cast<mlir::SymbolRefAttr>(callable);
187 if (mlir::Operation *op = symbolTable.lookupNearestSymbolFrom(call.getOperation(), symbolRef)) {
188 SymbolLookupResult<T> result(op);
189 if (!result) {
190 return mlir::failure();
191 }
192 return result;
193 }
195 symbolTable, symbolRef, call.getOperation(), /*reportMissing=*/false
196 );
197}
198
199template <typename T>
200inline mlir::FailureOr<SymbolLookupResult<T>> resolveCallable(mlir::CallOpInterface call) {
201 mlir::SymbolTableCollection symbolTable;
202 return resolveCallable<T>(symbolTable, call);
203}
204
210mlir::FailureOr<polymorphic::TemplateOp>
211getConstResolutionTemplate(mlir::SymbolTableCollection &tables, mlir::Operation *origin);
212
215mlir::LogicalResult verifyParamOfType(
216 mlir::SymbolTableCollection &tables, mlir::SymbolRefAttr param, mlir::Type structOrArrayType,
217 mlir::Operation *origin, std::optional<mlir::Type> requiredParamType = std::nullopt
218);
219
223mlir::LogicalResult verifyParamsOfType(
224 mlir::SymbolTableCollection &tables, mlir::ArrayRef<mlir::Attribute> tyParams,
225 mlir::Type structOrArrayType, mlir::Operation *origin,
226 std::optional<mlir::Type> requiredParamType = std::nullopt
227);
228
230mlir::FailureOr<component::StructDefOp> verifyStructTypeResolution(
231 mlir::SymbolTableCollection &tables, component::StructType ty, mlir::Operation *origin
232);
233
235mlir::LogicalResult
236verifyTypeResolution(mlir::SymbolTableCollection &tables, mlir::Operation *origin, mlir::Type type);
237
239template <std::ranges::input_range Range>
240mlir::LogicalResult verifyTypeResolution(
241 mlir::SymbolTableCollection &tables, mlir::Operation *origin, const Range &types
242) {
243 // Check all before returning to present all applicable type errors in one compilation.
244 bool failed = false;
245 for (const auto &t : types) {
246 failed |= mlir::failed(verifyTypeResolution(tables, origin, t));
247 }
248 return mlir::LogicalResult::failure(failed);
249}
250
251} // 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)
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)
mlir::FailureOr< SymbolLookupResult< T > > resolveCallableSilently(mlir::SymbolTableCollection &symbolTable, mlir::CallOpInterface call)
Resolve a callable without emitting a diagnostic for missing top-level symbols.
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.
FailureOr< SymbolLookupResult< StructDefOp > > getMainInstanceDef(SymbolTableCollection &symbolTable, Operation *lookupFrom)
FailureOr< SymbolRefAttr > getPathFromTopRoot(SymbolOpInterface to, ModuleOp *foundRoot)
llvm::SmallVector< FlatSymbolRefAttr > getPieces(SymbolRefAttr ref)
FailureOr< SymbolRefAttr > getPathFromRoot(SymbolOpInterface to, ModuleOp *foundRoot)
LogicalResult verifyParamOfType(SymbolTableCollection &tables, SymbolRefAttr param, Type parameterizedType, Operation *origin, std::optional< Type > requiredParamType)