25#include <mlir/IR/BuiltinOps.h>
26#include <mlir/IR/Operation.h>
28#include <llvm/ADT/TypeSwitch.h>
29#include <llvm/Support/Debug.h>
31#define DEBUG_TYPE "llzk-symbol-helpers"
38using namespace component;
39using namespace function;
40using namespace global;
41using namespace polymorphic;
49constexpr char POSITION_IS_ROOT_INDICATOR[] =
"<<symbol lookup root>>";
50constexpr char UNNAMED_SYMBOL_INDICATOR[] =
"<<unnamed symbol>>";
52enum RootSelector : std::uint8_t { CLOSEST, FURTHEST };
54class RootPathBuilder {
55 RootSelector _whichRoot;
60 RootPathBuilder(RootSelector whichRoot, Operation *origin, ModuleOp *foundRoot)
61 : _whichRoot(whichRoot), _origin(origin), _foundRoot(foundRoot) {}
70 FailureOr<ModuleOp> collectPathToRoot(Operation *
from, std::vector<FlatSymbolRefAttr> &path) {
72 ModuleOp currRoot =
nullptr;
74 if (ModuleOp m = llvm::dyn_cast_if_present<ModuleOp>(
check)) {
79 if (_whichRoot == RootSelector::CLOSEST) {
84 if (StringAttr modName = m.getSymNameAttr()) {
85 path.push_back(FlatSymbolRefAttr::get(modName));
86 }
else if (!currRoot) {
87 return _origin->emitOpError()
89 "has ancestor '", ModuleOp::getOperationName(),
"' without \"",
LANG_ATTR_NAME,
90 "\" attribute or a name"
92 .attachNote(m.getLoc())
93 .append(
"unnamed '", ModuleOp::getOperationName(),
"' here");
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));
102 if (_whichRoot == RootSelector::FURTHEST && currRoot) {
106 return _origin->emitOpError().append(
107 "has no ancestor '", ModuleOp::getOperationName(),
"' with \"",
LANG_ATTR_NAME,
114 FailureOr<SymbolRefAttr>
115 buildPathFromRootToAnyOp(Operation *position, std::vector<FlatSymbolRefAttr> &&path) {
117 FailureOr<ModuleOp> rootMod = collectPathToRoot(position, path);
118 if (failed(rootMod)) {
122 *_foundRoot = rootMod.value();
128 assert(position == rootMod.value().getOperation() &&
"empty path only at root itself");
132 std::vector<FlatSymbolRefAttr> reversedVec(path.rbegin(), path.rend());
137 FailureOr<SymbolRefAttr> getPathFromRootToAnyOp(Operation *op) {
138 std::vector<FlatSymbolRefAttr> path;
139 return buildPathFromRootToAnyOp(op, std::move(path));
144 FailureOr<SymbolRefAttr>
145 buildPathFromRootToStruct(StructDefOp to, std::vector<FlatSymbolRefAttr> &&path) {
147 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
148 return buildPathFromRootToAnyOp(to, std::move(path));
151 FailureOr<SymbolRefAttr> getPathFromRootToStruct(StructDefOp to) {
152 std::vector<FlatSymbolRefAttr> path;
153 return buildPathFromRootToStruct(to, std::move(path));
156 FailureOr<SymbolRefAttr> getPathFromRootToMember(MemberDefOp to) {
157 std::vector<FlatSymbolRefAttr> path;
159 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
161 return buildPathFromRootToStruct(to.getParentOp<StructDefOp>(), std::move(path));
164 FailureOr<SymbolRefAttr> getPathFromRootToFunc(FuncDefOp to) {
165 std::vector<FlatSymbolRefAttr> path;
167 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
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));
185 FailureOr<SymbolRefAttr> getPathFromRootToAnySymbol(SymbolOpInterface to) {
187 return TypeSwitch<Operation *, FailureOr<SymbolRefAttr>>(to.getOperation())
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); })
197 .Default([
this, &to](
auto) {
198 std::vector<FlatSymbolRefAttr> path;
200 path.push_back(FlatSymbolRefAttr::get(name));
203 assert(to.isOptionalSymbol());
204 path.push_back(FlatSymbolRefAttr::get(to.getContext(), UNNAMED_SYMBOL_INDICATOR));
206 return buildPathFromRootToAnyOp(to, std::move(path));
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());
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()) {
234SymbolRefAttr changeLeafImpl(
235 StringAttr origRoot, ArrayRef<FlatSymbolRefAttr> origTail, FlatSymbolRefAttr newLeaf,
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);
246SymbolRefAttr
replaceLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf) {
247 ArrayRef<FlatSymbolRefAttr> origTail = orig.getNestedReferences();
248 if (origTail.empty()) {
252 return changeLeafImpl(orig.getRootReference(), origTail, newLeaf);
256SymbolRefAttr
appendLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf) {
257 return changeLeafImpl(orig.getRootReference(), orig.getNestedReferences(), newLeaf, 0);
261 ArrayRef<FlatSymbolRefAttr> origTail = orig.getNestedReferences();
262 if (origTail.empty()) {
265 orig.getContext(), orig.getRootReference().getValue() + newLeafSuffix
268 return changeLeafImpl(
269 orig.getRootReference(), origTail,
276 std::vector<FlatSymbolRefAttr> path;
277 return RootPathBuilder(RootSelector::CLOSEST,
from,
nullptr).collectPathToRoot(
from, path);
281 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToAnySymbol(to);
285 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToAnyOp(to);
289 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToStruct(to);
293 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToMember(to);
297 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToFunc(to);
301 std::vector<FlatSymbolRefAttr> path;
302 return RootPathBuilder(RootSelector::FURTHEST,
from,
nullptr).collectPathToRoot(
from, path);
306 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToAnySymbol(to);
310 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToAnyOp(to);
314 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToStruct(to);
318 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToMember(to);
322 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToFunc(to);
327 if (failed(rootOpt)) {
330 ModuleOp root = rootOpt.value();
335 return success(
nullptr);
338FailureOr<SymbolLookupResult<StructDefOp>>
341 if (failed(mainStructTypeOpt)) {
344 if (
StructType st = mainStructTypeOpt.value()) {
345 return st.getDefinition(symbolTable, lookupFrom);
347 return success(
nullptr);
353 FailureOr<SymbolLookupResultUntyped> targetRes =
355 if (failed(targetRes)) {
360 return targetTemplate;
368 SymbolTableCollection &tables, SymbolRefAttr param, Type parameterizedType, Operation *origin
373 if (param.getNestedReferences().empty()) {
375 if (failed(parent)) {
386 if (failed(lookupRes)) {
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";
399 SymbolTableCollection &tables, ArrayRef<Attribute> tyParams, Type parameterizedType,
404 LogicalResult paramCheckResult = success();
406 llvm::dbgs() <<
"[verifyParamOfType] parameterizedType = " << parameterizedType <<
'\n';
408 for (Attribute attr : tyParams) {
409 LLVM_DEBUG({ llvm::dbgs() <<
"[verifyParamOfType] checking attribute " << attr <<
'\n'; });
411 if (SymbolRefAttr symRefParam = llvm::dyn_cast<SymbolRefAttr>(attr)) {
414 llvm::dbgs() <<
"[verifyParamOfType] failed to verify symbol attribute\n";
416 paramCheckResult = failure();
418 }
else if (TypeAttr typeParam = llvm::dyn_cast<TypeAttr>(attr)) {
421 llvm::dbgs() <<
"[verifyParamOfType] failed to verify type attribute\n";
423 paramCheckResult = failure();
426 LLVM_DEBUG({ llvm::dbgs() <<
"[verifyParamOfType] verified attribute\n"; });
429 return paramCheckResult;
432FailureOr<StructDefOp>
440 return origin->emitError()
442 "Cannot unify parameters of type ", ty,
" with parameters of '",
445 .attachNote(defForType.getLoc())
446 .append(
"type parameters must unify with parameters defined here");
449 if (ArrayAttr tyParams = ty.
getParams()) {
458 if (
StructType sTy = llvm::dyn_cast<StructType>(ty)) {
460 }
else if (
ArrayType aTy = llvm::dyn_cast<ArrayType>(ty)) {
465 }
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 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...
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'.
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)
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.