24#include <mlir/IR/BuiltinOps.h>
25#include <mlir/IR/Operation.h>
27#include <llvm/ADT/TypeSwitch.h>
28#include <llvm/Support/Debug.h>
30#define DEBUG_TYPE "llzk-symbol-helpers"
37using namespace component;
38using namespace function;
39using namespace global;
40using namespace polymorphic;
48constexpr char POSITION_IS_ROOT_INDICATOR[] =
"<<symbol lookup root>>";
49constexpr char UNNAMED_SYMBOL_INDICATOR[] =
"<<unnamed symbol>>";
51enum RootSelector : std::uint8_t { CLOSEST, FURTHEST };
53class RootPathBuilder {
54 RootSelector _whichRoot;
59 RootPathBuilder(RootSelector whichRoot, Operation *origin, ModuleOp *foundRoot)
60 : _whichRoot(whichRoot), _origin(origin), _foundRoot(foundRoot) {}
69 FailureOr<ModuleOp> collectPathToRoot(Operation *
from, std::vector<FlatSymbolRefAttr> &path) {
71 ModuleOp currRoot =
nullptr;
73 if (ModuleOp m = llvm::dyn_cast_if_present<ModuleOp>(
check)) {
78 if (_whichRoot == RootSelector::CLOSEST) {
83 if (StringAttr modName = m.getSymNameAttr()) {
84 path.push_back(FlatSymbolRefAttr::get(modName));
85 }
else if (!currRoot) {
86 return _origin->emitOpError()
88 "has ancestor '", ModuleOp::getOperationName(),
"' without \"",
LANG_ATTR_NAME,
89 "\" attribute or a name"
91 .attachNote(m.getLoc())
92 .append(
"unnamed '", ModuleOp::getOperationName(),
"' here");
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));
101 if (_whichRoot == RootSelector::FURTHEST && currRoot) {
105 return _origin->emitOpError().append(
106 "has no ancestor '", ModuleOp::getOperationName(),
"' with \"",
LANG_ATTR_NAME,
113 FailureOr<SymbolRefAttr>
114 buildPathFromRootToAnyOp(Operation *position, std::vector<FlatSymbolRefAttr> &&path) {
116 FailureOr<ModuleOp> rootMod = collectPathToRoot(position, path);
117 if (failed(rootMod)) {
121 *_foundRoot = rootMod.value();
127 assert(position == rootMod.value().getOperation() &&
"empty path only at root itself");
131 std::vector<FlatSymbolRefAttr> reversedVec(path.rbegin(), path.rend());
136 FailureOr<SymbolRefAttr> getPathFromRootToAnyOp(Operation *op) {
137 std::vector<FlatSymbolRefAttr> path;
138 return buildPathFromRootToAnyOp(op, std::move(path));
143 FailureOr<SymbolRefAttr>
144 buildPathFromRootToStruct(StructDefOp to, std::vector<FlatSymbolRefAttr> &&path) {
146 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
147 return buildPathFromRootToAnyOp(to, std::move(path));
150 FailureOr<SymbolRefAttr> getPathFromRootToStruct(StructDefOp to) {
151 std::vector<FlatSymbolRefAttr> path;
152 return buildPathFromRootToStruct(to, std::move(path));
155 FailureOr<SymbolRefAttr> getPathFromRootToMember(MemberDefOp to) {
156 std::vector<FlatSymbolRefAttr> path;
158 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
160 return buildPathFromRootToStruct(to.getParentOp<StructDefOp>(), std::move(path));
163 FailureOr<SymbolRefAttr> getPathFromRootToFunc(FuncDefOp to) {
164 std::vector<FlatSymbolRefAttr> path;
166 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
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));
184 FailureOr<SymbolRefAttr> getPathFromRootToAnySymbol(SymbolOpInterface to) {
186 return TypeSwitch<Operation *, FailureOr<SymbolRefAttr>>(to.getOperation())
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); })
196 .Default([
this, &to](
auto) {
197 std::vector<FlatSymbolRefAttr> path;
199 path.push_back(FlatSymbolRefAttr::get(name));
202 assert(to.isOptionalSymbol());
203 path.push_back(FlatSymbolRefAttr::get(to.getContext(), UNNAMED_SYMBOL_INDICATOR));
205 return buildPathFromRootToAnyOp(to, std::move(path));
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());
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()) {
233SymbolRefAttr changeLeafImpl(
234 StringAttr origRoot, ArrayRef<FlatSymbolRefAttr> origTail, FlatSymbolRefAttr newLeaf,
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);
245SymbolRefAttr
replaceLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf) {
246 ArrayRef<FlatSymbolRefAttr> origTail = orig.getNestedReferences();
247 if (origTail.empty()) {
251 return changeLeafImpl(orig.getRootReference(), origTail, newLeaf);
255SymbolRefAttr
appendLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf) {
256 return changeLeafImpl(orig.getRootReference(), orig.getNestedReferences(), newLeaf, 0);
260 ArrayRef<FlatSymbolRefAttr> origTail = orig.getNestedReferences();
261 if (origTail.empty()) {
264 orig.getContext(), orig.getRootReference().getValue() + newLeafSuffix
267 return changeLeafImpl(
268 orig.getRootReference(), origTail,
275 std::vector<FlatSymbolRefAttr> path;
276 return RootPathBuilder(RootSelector::CLOSEST,
from,
nullptr).collectPathToRoot(
from, path);
280 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToAnySymbol(to);
284 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToAnyOp(to);
288 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToStruct(to);
292 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToMember(to);
296 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToFunc(to);
300 std::vector<FlatSymbolRefAttr> path;
301 return RootPathBuilder(RootSelector::FURTHEST,
from,
nullptr).collectPathToRoot(
from, path);
305 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToAnySymbol(to);
309 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToAnyOp(to);
313 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToStruct(to);
317 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToMember(to);
321 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToFunc(to);
326 if (failed(rootOpt)) {
329 ModuleOp root = rootOpt.value();
332 if (TypeAttr ta = llvm::dyn_cast<TypeAttr>(a)) {
333 if (
StructType st = llvm::dyn_cast<StructType>(ta.getValue())) {
339 return rootOpt->emitError().append(
341 "' attribute. Found: ", a
345 return success(
nullptr);
348FailureOr<SymbolLookupResult<StructDefOp>>
351 if (failed(mainStructTypeOpt)) {
354 if (
StructType st = mainStructTypeOpt.value()) {
355 return st.getDefinition(symbolTable, lookupFrom);
357 return success(
nullptr);
362 SymbolTableCollection &tables, SymbolRefAttr param, Type parameterizedType, Operation *origin
367 if (param.getNestedReferences().empty()) {
376 if (failed(lookupRes)) {
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";
389 SymbolTableCollection &tables, ArrayRef<Attribute> tyParams, Type parameterizedType,
394 LogicalResult paramCheckResult = success();
396 llvm::dbgs() <<
"[verifyParamOfType] parameterizedType = " << parameterizedType <<
'\n';
398 for (Attribute attr : tyParams) {
399 LLVM_DEBUG({ llvm::dbgs() <<
"[verifyParamOfType] checking attribute " << attr <<
'\n'; });
401 if (SymbolRefAttr symRefParam = llvm::dyn_cast<SymbolRefAttr>(attr)) {
404 llvm::dbgs() <<
"[verifyParamOfType] failed to verify symbol attribute\n";
406 paramCheckResult = failure();
408 }
else if (TypeAttr typeParam = llvm::dyn_cast<TypeAttr>(attr)) {
411 llvm::dbgs() <<
"[verifyParamOfType] failed to verify type attribute\n";
413 paramCheckResult = failure();
416 LLVM_DEBUG({ llvm::dbgs() <<
"[verifyParamOfType] verified attribute\n"; });
419 return paramCheckResult;
422FailureOr<StructDefOp>
430 return origin->emitError()
432 "Cannot unify parameters of type ", ty,
" with parameters of '",
435 .attachNote(defForType.getLoc())
436 .append(
"type parameters must unify with parameters defined here");
439 if (ArrayAttr tyParams = ty.
getParams()) {
448 if (
StructType sTy = llvm::dyn_cast<StructType>(ty)) {
450 }
else if (
ArrayType aTy = llvm::dyn_cast<ArrayType>(ty)) {
455 }
else if (
TypeVarType vTy = llvm::dyn_cast<TypeVarType>(ty)) {
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
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
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()
::std::string getHeaderString()
Generate header string, in the same format as the assemblyFormat.
::mlir::FailureOr< SymbolLookupResult< StructDefOp > > getDefinition(::mlir::SymbolTableCollection &symbolTable, ::mlir::Operation *op, bool reportMissing=true) const
Gets the struct op that defines this struct.
::mlir::ArrayAttr getParams() const
static constexpr ::llvm::StringLiteral name
static constexpr ::llvm::StringLiteral getOperationName()
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...
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'.
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.