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