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