LLZK 2.1.1
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
SymbolHelper.cpp
Go to the documentation of this file.
1//===-- SymbolHelper.cpp - LLZK Symbol Helpers ------------------*- 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
16
24
25#include <mlir/IR/BuiltinOps.h>
26#include <mlir/IR/Operation.h>
27
28#include <llvm/ADT/TypeSwitch.h>
29#include <llvm/Support/Debug.h>
30
31#define DEBUG_TYPE "llzk-symbol-helpers"
32
33using namespace mlir;
34
35namespace llzk {
36
37using namespace array;
38using namespace component;
39using namespace function;
40using namespace global;
41using namespace polymorphic;
42
43namespace {
44
45// NOTE: These may be used in SymbolRefAttr instances returned from these functions but there is no
46// restriction that the same value cannot be used as a symbol name in user code so these should not
47// be used in such a way that relies on that assumption. That's why they are (currently) defined in
48// this anonymous namespace rather than within the header file.
49constexpr char POSITION_IS_ROOT_INDICATOR[] = "<<symbol lookup root>>";
50constexpr char UNNAMED_SYMBOL_INDICATOR[] = "<<unnamed symbol>>";
51
52enum RootSelector : std::uint8_t { CLOSEST, FURTHEST };
53
54class RootPathBuilder {
55 RootSelector _whichRoot;
56 Operation *_origin;
57 ModuleOp *_foundRoot;
58
59public:
60 RootPathBuilder(RootSelector whichRoot, Operation *origin, ModuleOp *foundRoot)
61 : _whichRoot(whichRoot), _origin(origin), _foundRoot(foundRoot) {}
62
70 FailureOr<ModuleOp> collectPathToRoot(Operation *from, std::vector<FlatSymbolRefAttr> &path) {
71 Operation *check = from;
72 ModuleOp currRoot = nullptr;
73 do {
74 if (ModuleOp m = llvm::dyn_cast_if_present<ModuleOp>(check)) {
75 // We need this attribute restriction because some stages of parsing have
76 // an extra module wrapping the top-level module from the input file.
77 // This module, even if it has a name, does not contribute to path names.
78 if (m->hasAttr(LANG_ATTR_NAME)) {
79 if (_whichRoot == RootSelector::CLOSEST) {
80 return m;
81 }
82 currRoot = m;
83 }
84 if (StringAttr modName = m.getSymNameAttr()) {
85 path.push_back(FlatSymbolRefAttr::get(modName));
86 } else if (!currRoot) {
87 return _origin->emitOpError()
88 .append(
89 "has ancestor '", ModuleOp::getOperationName(), "' without \"", LANG_ATTR_NAME,
90 "\" attribute or a name"
91 )
92 .attachNote(m.getLoc())
93 .append("unnamed '", ModuleOp::getOperationName(), "' here");
94 }
95 } else if (TemplateOp t = llvm::dyn_cast_if_present<TemplateOp>(check)) {
96 StringAttr name = t.getSymNameAttr();
97 assert(name && "per ODS");
98 path.push_back(FlatSymbolRefAttr::get(name));
99 }
100 } while ((check = check->getParentOp()));
101
102 if (_whichRoot == RootSelector::FURTHEST && currRoot) {
103 return currRoot;
104 }
105
106 return _origin->emitOpError().append(
107 "has no ancestor '", ModuleOp::getOperationName(), "' with \"", LANG_ATTR_NAME,
108 "\" attribute"
109 );
110 }
111
114 FailureOr<SymbolRefAttr>
115 buildPathFromRootToAnyOp(Operation *position, std::vector<FlatSymbolRefAttr> &&path) {
116 // Collect the rest of the path to the root module
117 FailureOr<ModuleOp> rootMod = collectPathToRoot(position, path);
118 if (failed(rootMod)) {
119 return failure();
120 }
121 if (_foundRoot) {
122 *_foundRoot = rootMod.value();
123 }
124 // Special case for empty path (because asSymbolRefAttr() cannot handle it).
125 if (path.empty()) {
126 // ASSERT: This can only occur when the given `position` is the discovered root ModuleOp
127 // itself.
128 assert(position == rootMod.value().getOperation() && "empty path only at root itself");
129 return getFlatSymbolRefAttr(_origin->getContext(), POSITION_IS_ROOT_INDICATOR);
130 }
131 // Reverse the vector and convert it to a SymbolRefAttr
132 std::vector<FlatSymbolRefAttr> reversedVec(path.rbegin(), path.rend());
133 return asSymbolRefAttr(reversedVec);
134 }
135
137 FailureOr<SymbolRefAttr> getPathFromRootToAnyOp(Operation *op) {
138 std::vector<FlatSymbolRefAttr> path;
139 return buildPathFromRootToAnyOp(op, std::move(path));
140 }
141
144 FailureOr<SymbolRefAttr>
145 buildPathFromRootToStruct(StructDefOp to, std::vector<FlatSymbolRefAttr> &&path) {
146 // Add the name of the struct (its name is not optional) and then delegate to helper
147 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
148 return buildPathFromRootToAnyOp(to, std::move(path));
149 }
150
151 FailureOr<SymbolRefAttr> getPathFromRootToStruct(StructDefOp to) {
152 std::vector<FlatSymbolRefAttr> path;
153 return buildPathFromRootToStruct(to, std::move(path));
154 }
155
156 FailureOr<SymbolRefAttr> getPathFromRootToMember(MemberDefOp to) {
157 std::vector<FlatSymbolRefAttr> path;
158 // Add the name of the member (its name is not optional)
159 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
160 // Delegate to the parent handler (must be StructDefOp per ODS)
161 return buildPathFromRootToStruct(to.getParentOp<StructDefOp>(), std::move(path));
162 }
163
164 FailureOr<SymbolRefAttr> getPathFromRootToFunc(FuncDefOp to) {
165 std::vector<FlatSymbolRefAttr> path;
166 // Add the name of the function (its name is not optional)
167 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
168
169 // Delegate based on the type of the parent op
170 Operation *current = to.getOperation();
171 Operation *parent = current->getParentOp();
172 if (StructDefOp parentStruct = llvm::dyn_cast_if_present<StructDefOp>(parent)) {
173 return buildPathFromRootToStruct(parentStruct, std::move(path));
174 } else if (ModuleOp parentMod = llvm::dyn_cast_if_present<ModuleOp>(parent)) {
175 return buildPathFromRootToAnyOp(parentMod, std::move(path));
176 } else if (TemplateOp parentTemplate = llvm::dyn_cast_if_present<TemplateOp>(parent)) {
177 return buildPathFromRootToAnyOp(parentTemplate, std::move(path));
178 } else {
179 // This is an error in the compiler itself. In current implementation,
180 // FuncDefOp must have module, struct, or template as its parent.
181 return current->emitError().append("orphaned '", FuncDefOp::getOperationName(), '\'');
182 }
183 }
184
185 FailureOr<SymbolRefAttr> getPathFromRootToAnySymbol(SymbolOpInterface to) {
186 // clang-format off
187 return TypeSwitch<Operation *, FailureOr<SymbolRefAttr>>(to.getOperation())
188 // This more general function must check for the specific cases first.
189 .Case<FuncDefOp>([this](auto toOp) { return getPathFromRootToFunc(toOp); })
190 .Case<MemberDefOp>([this](auto toOp) { return getPathFromRootToMember(toOp); })
191 .Case<StructDefOp>([this](auto toOp) { return getPathFromRootToStruct(toOp); })
192 .Case<TemplateOp>([this](auto toOp) { return getPathFromRootToAnyOp(toOp); })
193 .Case<ModuleOp>([this](auto toOp) { return getPathFromRootToAnyOp(toOp); })
194
195 // For any other symbol, append the name of the symbol and then delegate to
196 // `buildPathFromRootToAnyOp()`.
197 .Default([this, &to](auto) {
198 std::vector<FlatSymbolRefAttr> path;
199 if (StringAttr name = llzk::getSymbolName(to)) {
200 path.push_back(FlatSymbolRefAttr::get(name));
201 } else {
202 // This can only happen if the symbol is optional. Add a placeholder name.
203 assert(to.isOptionalSymbol());
204 path.push_back(FlatSymbolRefAttr::get(to.getContext(), UNNAMED_SYMBOL_INDICATOR));
205 }
206 return buildPathFromRootToAnyOp(to, std::move(path));
207 });
208 // clang-format on
209 }
210};
211
212} // namespace
213
214llvm::SmallVector<StringRef> getNames(SymbolRefAttr ref) {
215 llvm::SmallVector<StringRef> names;
216 names.push_back(ref.getRootReference().getValue());
217 for (const FlatSymbolRefAttr &r : ref.getNestedReferences()) {
218 names.push_back(r.getValue());
219 }
220 return names;
221}
222
223llvm::SmallVector<FlatSymbolRefAttr> getPieces(SymbolRefAttr ref) {
224 llvm::SmallVector<FlatSymbolRefAttr> pieces;
225 pieces.push_back(FlatSymbolRefAttr::get(ref.getRootReference()));
226 for (const FlatSymbolRefAttr &r : ref.getNestedReferences()) {
227 pieces.push_back(r);
228 }
229 return pieces;
230}
231
232namespace {
233
234SymbolRefAttr changeLeafImpl(
235 StringAttr origRoot, ArrayRef<FlatSymbolRefAttr> origTail, FlatSymbolRefAttr newLeaf,
236 size_t drop = 1
237) {
238 llvm::SmallVector<FlatSymbolRefAttr> newTail;
239 newTail.append(origTail.begin(), origTail.drop_back(drop).end());
240 newTail.push_back(newLeaf);
241 return SymbolRefAttr::get(origRoot, newTail);
242}
243
244} // namespace
245
246SymbolRefAttr replaceLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf) {
247 ArrayRef<FlatSymbolRefAttr> origTail = orig.getNestedReferences();
248 if (origTail.empty()) {
249 // If there is no tail, the root is the leaf so replace the whole thing
250 return newLeaf;
251 } else {
252 return changeLeafImpl(orig.getRootReference(), origTail, newLeaf);
253 }
254}
255
256SymbolRefAttr appendLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf) {
257 return changeLeafImpl(orig.getRootReference(), orig.getNestedReferences(), newLeaf, 0);
258}
259
260SymbolRefAttr appendLeafName(SymbolRefAttr orig, const Twine &newLeafSuffix) {
261 ArrayRef<FlatSymbolRefAttr> origTail = orig.getNestedReferences();
262 if (origTail.empty()) {
263 // If there is no tail, the root is the leaf so append on the root instead
265 orig.getContext(), orig.getRootReference().getValue() + newLeafSuffix
266 );
267 } else {
268 return changeLeafImpl(
269 orig.getRootReference(), origTail,
270 getFlatSymbolRefAttr(orig.getContext(), origTail.back().getValue() + newLeafSuffix)
271 );
272 }
273}
274
275FailureOr<ModuleOp> getRootModule(Operation *from) {
276 std::vector<FlatSymbolRefAttr> path;
277 return RootPathBuilder(RootSelector::CLOSEST, from, nullptr).collectPathToRoot(from, path);
278}
279
280FailureOr<SymbolRefAttr> getPathFromRoot(SymbolOpInterface to, ModuleOp *foundRoot) {
281 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToAnySymbol(to);
282}
283
284FailureOr<SymbolRefAttr> getPathFromRoot(TemplateOp &to, ModuleOp *foundRoot) {
285 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToAnyOp(to);
286}
287
288FailureOr<SymbolRefAttr> getPathFromRoot(StructDefOp &to, ModuleOp *foundRoot) {
289 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToStruct(to);
290}
291
292FailureOr<SymbolRefAttr> getPathFromRoot(MemberDefOp &to, ModuleOp *foundRoot) {
293 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToMember(to);
294}
295
296FailureOr<SymbolRefAttr> getPathFromRoot(FuncDefOp &to, ModuleOp *foundRoot) {
297 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToFunc(to);
298}
299
300FailureOr<ModuleOp> getTopRootModule(Operation *from) {
301 std::vector<FlatSymbolRefAttr> path;
302 return RootPathBuilder(RootSelector::FURTHEST, from, nullptr).collectPathToRoot(from, path);
303}
304
305FailureOr<SymbolRefAttr> getPathFromTopRoot(SymbolOpInterface to, ModuleOp *foundRoot) {
306 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToAnySymbol(to);
307}
308
309FailureOr<SymbolRefAttr> getPathFromTopRoot(TemplateOp &to, ModuleOp *foundRoot) {
310 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToAnyOp(to);
311}
312
313FailureOr<SymbolRefAttr> getPathFromTopRoot(StructDefOp &to, ModuleOp *foundRoot) {
314 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToStruct(to);
315}
316
317FailureOr<SymbolRefAttr> getPathFromTopRoot(MemberDefOp &to, ModuleOp *foundRoot) {
318 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToMember(to);
319}
320
321FailureOr<SymbolRefAttr> getPathFromTopRoot(FuncDefOp &to, ModuleOp *foundRoot) {
322 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToFunc(to);
323}
324
325FailureOr<StructType> getMainInstanceType(Operation *lookupFrom) {
326 FailureOr<ModuleOp> rootOpt = getRootModule(lookupFrom);
327 if (failed(rootOpt)) {
328 return failure();
329 }
330 ModuleOp root = rootOpt.value();
331 if (Attribute a = root->getAttr(MAIN_ATTR_NAME)) {
332 return getTypeFromLlzkMainAttr(root, a);
333 }
334 // The attribute is optional so it's okay if not present.
335 return success(nullptr);
336}
337
338FailureOr<SymbolLookupResult<StructDefOp>>
339getMainInstanceDef(SymbolTableCollection &symbolTable, Operation *lookupFrom) {
340 FailureOr<StructType> mainStructTypeOpt = getMainInstanceType(lookupFrom);
341 if (failed(mainStructTypeOpt)) {
342 return failure();
343 }
344 if (StructType st = mainStructTypeOpt.value()) {
345 return st.getDefinition(symbolTable, lookupFrom);
346 } else {
347 return success(nullptr);
348 }
349}
350
351FailureOr<TemplateOp> getConstResolutionTemplate(SymbolTableCollection &tables, Operation *origin) {
352 if (auto contract = origin->getParentOfType<verif::ContractOp>()) {
353 FailureOr<SymbolLookupResultUntyped> targetRes =
354 lookupTopLevelSymbol(tables, contract.getTargetAttr(), origin);
355 if (failed(targetRes)) {
356 return failure(); // lookupTopLevelSymbol() already emits a sufficient error message
357 }
358
359 if (TemplateOp targetTemplate = targetRes->get()->getParentOfType<TemplateOp>()) {
360 return targetTemplate;
361 }
362 }
363
364 return getParentOfType<TemplateOp>(origin);
365}
366
367LogicalResult verifyParamOfType(
368 SymbolTableCollection &tables, SymbolRefAttr param, Type parameterizedType, Operation *origin
369) {
370 // Most often, StructType and ArrayType SymbolRefAttr parameters will be defined as parameters of
371 // the template that the current Operation is nested within. These are always flat references
372 // (i.e., contain no nested references).
373 if (param.getNestedReferences().empty()) {
374 FailureOr<TemplateOp> parent = getConstResolutionTemplate(tables, origin);
375 if (failed(parent)) {
376 return failure(); // getConstResolutionTemplate() failure cases emit a sufficient error
377 // message
378 }
379 if (*parent &&
380 parent->hasConstNamed<TemplateSymbolBindingOpInterface>(param.getRootReference())) {
381 return success();
382 }
383 }
384 // Otherwise, see if the symbol can be found via lookup from the `origin` Operation.
385 auto lookupRes = lookupTopLevelSymbol(tables, param, origin);
386 if (failed(lookupRes)) {
387 return failure(); // lookupTopLevelSymbol() already emits a sufficient error message
388 }
389 Operation *foundOp = lookupRes->get();
390 if (!llvm::isa<GlobalDefOp>(foundOp)) {
391 return origin->emitError() << "ref \"" << param << "\" in type " << parameterizedType
392 << " refers to a '" << foundOp->getName()
393 << "' which is not allowed";
394 }
395 return success();
396}
397
398LogicalResult verifyParamsOfType(
399 SymbolTableCollection &tables, ArrayRef<Attribute> tyParams, Type parameterizedType,
400 Operation *origin
401) {
402 // Rather than immediately returning on failure, we check all params and aggregate to provide as
403 // many errors are possible in a single verifier run.
404 LogicalResult paramCheckResult = success();
405 LLVM_DEBUG({
406 llvm::dbgs() << "[verifyParamOfType] parameterizedType = " << parameterizedType << '\n';
407 });
408 for (Attribute attr : tyParams) {
409 LLVM_DEBUG({ llvm::dbgs() << "[verifyParamOfType] checking attribute " << attr << '\n'; });
411 if (SymbolRefAttr symRefParam = llvm::dyn_cast<SymbolRefAttr>(attr)) {
412 if (failed(verifyParamOfType(tables, symRefParam, parameterizedType, origin))) {
413 LLVM_DEBUG({
414 llvm::dbgs() << "[verifyParamOfType] failed to verify symbol attribute\n";
415 });
416 paramCheckResult = failure();
417 }
418 } else if (TypeAttr typeParam = llvm::dyn_cast<TypeAttr>(attr)) {
419 if (failed(verifyTypeResolution(tables, origin, typeParam.getValue()))) {
420 LLVM_DEBUG({
421 llvm::dbgs() << "[verifyParamOfType] failed to verify type attribute\n";
422 });
423 paramCheckResult = failure();
424 }
425 }
426 LLVM_DEBUG({ llvm::dbgs() << "[verifyParamOfType] verified attribute\n"; });
427 // IntegerAttr and AffineMapAttr cannot contain symbol references
428 }
429 return paramCheckResult;
430}
431
432FailureOr<StructDefOp>
433verifyStructTypeResolution(SymbolTableCollection &tables, StructType ty, Operation *origin) {
434 auto res = ty.getDefinition(tables, origin);
435 if (failed(res)) {
436 return failure();
437 }
438 StructDefOp defForType = res.value().get();
439 if (!structTypesUnify(ty, defForType.getType({}), res->getNamespace())) {
440 return origin->emitError()
441 .append(
442 "Cannot unify parameters of type ", ty, " with parameters of '",
443 StructDefOp::getOperationName(), "' \"", defForType.getHeaderString(), '"'
444 )
445 .attachNote(defForType.getLoc())
446 .append("type parameters must unify with parameters defined here");
447 }
448 // If there are any SymbolRefAttr parameters on the StructType, ensure those refs are valid.
449 if (ArrayAttr tyParams = ty.getParams()) {
450 if (failed(verifyParamsOfType(tables, tyParams.getValue(), ty, origin))) {
451 return failure(); // verifyParamsOfType() already emits a sufficient error message
452 }
453 }
454 return defForType;
455}
456
457LogicalResult verifyTypeResolution(SymbolTableCollection &tables, Operation *origin, Type ty) {
458 if (StructType sTy = llvm::dyn_cast<StructType>(ty)) {
459 return verifyStructTypeResolution(tables, sTy, origin);
460 } else if (ArrayType aTy = llvm::dyn_cast<ArrayType>(ty)) {
461 if (failed(verifyParamsOfType(tables, aTy.getDimensionSizes(), aTy, origin))) {
462 return failure();
463 }
464 return verifyTypeResolution(tables, origin, aTy.getElementType());
465 } else if (TypeVarType vTy = llvm::dyn_cast<TypeVarType>(ty)) {
466 return verifyParamOfType(tables, vTy.getNameRef(), vTy, origin);
467 } else {
468 return success();
469 }
470}
471
472} // namespace llzk
within a display generated by the Derivative if and wherever such third party notices normally appear The contents of the NOTICE file are for informational purposes only and do not modify the License You may add Your own attribution notices within Derivative Works that You alongside or as an addendum to the NOTICE text from the provided that such additional attribution notices cannot be construed as modifying the License You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for or distribution of Your or for any such Derivative Works as a provided Your and distribution of the Work otherwise complies with the conditions stated in this License Submission of Contributions Unless You explicitly state any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this without any additional terms or conditions Notwithstanding the nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions Trademarks This License does not grant permission to use the trade names
Definition LICENSE.txt:139
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
#define check(x)
Definition Ops.cpp:285
This file defines methods symbol lookup across LLZK operations and included files.
StructType getType(::std::optional<::mlir::ArrayAttr > constParams={})
Gets the StructType representing this struct.
static constexpr ::llvm::StringLiteral getOperationName()
Definition Ops.h.inc:1165
::std::string getHeaderString()
Generate header string, in the same format as the assemblyFormat.
Definition Ops.cpp:181
::mlir::FailureOr< SymbolLookupResult< StructDefOp > > getDefinition(::mlir::SymbolTableCollection &symbolTable, ::mlir::Operation *op, bool reportMissing=true) const
Gets the struct op that defines this struct.
Definition Types.cpp:26
::mlir::ArrayAttr getParams() const
static constexpr ::llvm::StringLiteral getOperationName()
Definition Ops.h.inc:666
void assertValidAttrForParamOfType(Attribute attr)
SymbolRefAttr appendLeafName(SymbolRefAttr orig, const Twine &newLeafSuffix)
constexpr char LANG_ATTR_NAME[]
Name of the attribute on the top-level ModuleOp that identifies the ModuleOp as the root module and s...
Definition Constants.h:23
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)
mlir::StringAttr getSymbolName(mlir::Operation *symbol)
Returns the name of the given symbol operation, or nullptr if no symbol is present.
bool structTypesUnify(StructType lhs, StructType rhs, ArrayRef< StringRef > rhsReversePrefix, UnificationMap *unifications)
FailureOr< ModuleOp > getRootModule(Operation *from)
FailureOr< TemplateOp > getConstResolutionTemplate(SymbolTableCollection &tables, Operation *origin)
SymbolRefAttr appendLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf)
OpClass getParentOfType(mlir::Operation *op)
Return the closest surrounding parent/ancestor operation that is of type 'OpClass'.
Definition OpHelpers.h:51
SymbolRefAttr replaceLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf)
FailureOr< StructDefOp > verifyStructTypeResolution(SymbolTableCollection &tables, StructType ty, Operation *origin)
FailureOr< ModuleOp > getTopRootModule(Operation *from)
LogicalResult verifyTypeResolution(SymbolTableCollection &tables, Operation *origin, Type ty)
LogicalResult verifyParamsOfType(SymbolTableCollection &tables, ArrayRef< Attribute > tyParams, Type parameterizedType, Operation *origin)
FailureOr< StructType > getTypeFromLlzkMainAttr(ModuleOp op, Attribute attr)
Definition Attrs.cpp:24
mlir::SymbolRefAttr asSymbolRefAttr(mlir::StringAttr root, mlir::SymbolRefAttr tail)
Build a SymbolRefAttr that prepends tail with root, i.e., root::tail.
FailureOr< SymbolLookupResult< StructDefOp > > getMainInstanceDef(SymbolTableCollection &symbolTable, Operation *lookupFrom)
FailureOr< SymbolRefAttr > getPathFromTopRoot(SymbolOpInterface to, ModuleOp *foundRoot)
LogicalResult verifyParamOfType(SymbolTableCollection &tables, SymbolRefAttr param, Type parameterizedType, Operation *origin)
llvm::SmallVector< FlatSymbolRefAttr > getPieces(SymbolRefAttr ref)
FailureOr< SymbolRefAttr > getPathFromRoot(SymbolOpInterface to, ModuleOp *foundRoot)
constexpr char MAIN_ATTR_NAME[]
Name of the attribute on the top-level ModuleOp that specifies the type of the main struct.
Definition Constants.h:37