23#include <mlir/IR/BuiltinOps.h>
24#include <mlir/IR/Operation.h>
26#include <llvm/ADT/TypeSwitch.h>
27#include <llvm/Support/Debug.h>
29#define DEBUG_TYPE "llzk-symbol-helpers"
36using namespace component;
37using namespace function;
38using namespace global;
39using namespace polymorphic;
47constexpr char POSITION_IS_ROOT_INDICATOR[] =
"<<symbol lookup root>>";
48constexpr char UNNAMED_SYMBOL_INDICATOR[] =
"<<unnamed symbol>>";
50enum RootSelector { CLOSEST, FURTHEST };
52class RootPathBuilder {
53 RootSelector _whichRoot;
58 RootPathBuilder(RootSelector whichRoot, Operation *origin, ModuleOp *foundRoot)
59 : _whichRoot(whichRoot), _origin(origin), _foundRoot(foundRoot) {}
68 FailureOr<ModuleOp> collectPathToRoot(Operation *
from, std::vector<FlatSymbolRefAttr> &path) {
69 Operation *check =
from;
70 ModuleOp currRoot =
nullptr;
72 if (ModuleOp m = llvm::dyn_cast_if_present<ModuleOp>(check)) {
77 if (_whichRoot == RootSelector::CLOSEST) {
82 if (StringAttr modName = m.getSymNameAttr()) {
83 path.push_back(FlatSymbolRefAttr::get(modName));
84 }
else if (!currRoot) {
85 return _origin->emitOpError()
87 "has ancestor '", ModuleOp::getOperationName(),
"' without \"",
LANG_ATTR_NAME,
88 "\" attribute or a name"
90 .attachNote(m.getLoc())
91 .append(
"unnamed '", ModuleOp::getOperationName(),
"' here");
94 }
while ((check = check->getParentOp()));
96 if (_whichRoot == RootSelector::FURTHEST && currRoot) {
100 return _origin->emitOpError().append(
101 "has no ancestor '", ModuleOp::getOperationName(),
"' with \"",
LANG_ATTR_NAME,
108 FailureOr<SymbolRefAttr> buildPathFromRootToAnyOp(
109 Operation *position, std::vector<FlatSymbolRefAttr> &&path
113 FailureOr<ModuleOp> rootMod = collectPathToRoot(position, path);
114 if (failed(rootMod)) {
118 *_foundRoot = rootMod.value();
124 assert(position == rootMod.value().getOperation() &&
"empty path only at root itself");
128 std::vector<FlatSymbolRefAttr> reversedVec(path.rbegin(), path.rend());
134 FailureOr<SymbolRefAttr>
135 buildPathFromRootToStruct(StructDefOp to, std::vector<FlatSymbolRefAttr> &&path) {
137 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
138 return buildPathFromRootToAnyOp(to, std::move(path));
141 FailureOr<SymbolRefAttr> getPathFromRootToStruct(StructDefOp to) {
142 std::vector<FlatSymbolRefAttr> path;
143 return buildPathFromRootToStruct(to, std::move(path));
146 FailureOr<SymbolRefAttr> getPathFromRootToField(FieldDefOp to) {
147 std::vector<FlatSymbolRefAttr> path;
149 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
151 return buildPathFromRootToStruct(to.getParentOp<StructDefOp>(), std::move(path));
154 FailureOr<SymbolRefAttr> getPathFromRootToFunc(FuncDefOp to) {
155 std::vector<FlatSymbolRefAttr> path;
157 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
160 Operation *current = to.getOperation();
161 Operation *parent = current->getParentOp();
162 if (StructDefOp parentStruct = llvm::dyn_cast_if_present<StructDefOp>(parent)) {
163 return buildPathFromRootToStruct(parentStruct, std::move(path));
164 }
else if (ModuleOp parentMod = llvm::dyn_cast_if_present<ModuleOp>(parent)) {
165 return buildPathFromRootToAnyOp(parentMod, std::move(path));
173 FailureOr<SymbolRefAttr> getPathFromRootToAnySymbol(SymbolOpInterface to) {
174 return TypeSwitch<Operation *, FailureOr<SymbolRefAttr>>(to.getOperation())
176 .Case<FuncDefOp>([
this](FuncDefOp toOp) {
return getPathFromRootToFunc(toOp); })
177 .Case<FieldDefOp>([
this](FieldDefOp toOp) {
return getPathFromRootToField(toOp); })
178 .Case<StructDefOp>([
this](StructDefOp toOp) {
return getPathFromRootToStruct(toOp); })
182 .Case<ModuleOp>([
this](ModuleOp toOp) {
183 std::vector<FlatSymbolRefAttr> path;
184 return buildPathFromRootToAnyOp(toOp, std::move(path));
189 .Default([
this, &to](Operation *_) {
190 std::vector<FlatSymbolRefAttr> path;
192 path.push_back(FlatSymbolRefAttr::get(
name));
195 assert(to.isOptionalSymbol());
196 path.push_back(FlatSymbolRefAttr::get(to.getContext(), UNNAMED_SYMBOL_INDICATOR));
198 return buildPathFromRootToAnyOp(to, std::move(path));
205llvm::SmallVector<StringRef>
getNames(SymbolRefAttr ref) {
206 llvm::SmallVector<StringRef>
names;
207 names.push_back(ref.getRootReference().getValue());
208 for (
const FlatSymbolRefAttr &r : ref.getNestedReferences()) {
209 names.push_back(r.getValue());
214llvm::SmallVector<FlatSymbolRefAttr>
getPieces(SymbolRefAttr ref) {
215 llvm::SmallVector<FlatSymbolRefAttr> pieces;
216 pieces.push_back(FlatSymbolRefAttr::get(ref.getRootReference()));
217 for (
const FlatSymbolRefAttr &r : ref.getNestedReferences()) {
225SymbolRefAttr changeLeafImpl(
226 StringAttr origRoot, ArrayRef<FlatSymbolRefAttr> origTail, FlatSymbolRefAttr newLeaf,
229 llvm::SmallVector<FlatSymbolRefAttr> newTail;
230 newTail.append(origTail.begin(), origTail.drop_back(drop).end());
231 newTail.push_back(newLeaf);
232 return SymbolRefAttr::get(origRoot, newTail);
237SymbolRefAttr
replaceLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf) {
238 ArrayRef<FlatSymbolRefAttr> origTail = orig.getNestedReferences();
239 if (origTail.empty()) {
243 return changeLeafImpl(orig.getRootReference(), origTail, newLeaf);
247SymbolRefAttr
appendLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf) {
248 return changeLeafImpl(orig.getRootReference(), orig.getNestedReferences(), newLeaf, 0);
252 ArrayRef<FlatSymbolRefAttr> origTail = orig.getNestedReferences();
253 if (origTail.empty()) {
256 orig.getContext(), orig.getRootReference().getValue() + newLeafSuffix
259 return changeLeafImpl(
260 orig.getRootReference(), origTail,
267 std::vector<FlatSymbolRefAttr> path;
268 return RootPathBuilder(RootSelector::CLOSEST,
from,
nullptr).collectPathToRoot(
from, path);
272 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToAnySymbol(to);
276 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToStruct(to);
280 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToField(to);
284 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToFunc(to);
288 std::vector<FlatSymbolRefAttr> path;
289 return RootPathBuilder(RootSelector::FURTHEST,
from,
nullptr).collectPathToRoot(
from, path);
293 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToAnySymbol(to);
297 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToStruct(to);
301 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToField(to);
305 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToFunc(to);
309 SymbolTableCollection &tables, SymbolRefAttr param, Type parameterizedType, Operation *origin
314 if (param.getNestedReferences().empty()) {
316 if (succeeded(getParentRes)) {
317 if (getParentRes->hasParamNamed(param.getRootReference())) {
324 if (failed(lookupRes)) {
327 Operation *foundOp = lookupRes->get();
328 if (!llvm::isa<GlobalDefOp>(foundOp)) {
329 return origin->emitError() <<
"ref \"" << param <<
"\" in type " << parameterizedType
330 <<
" refers to a '" << foundOp->getName()
331 <<
"' which is not allowed";
337 SymbolTableCollection &tables, ArrayRef<Attribute> tyParams, Type parameterizedType,
342 LogicalResult paramCheckResult = success();
343 for (Attribute attr : tyParams) {
345 if (SymbolRefAttr symRefParam = llvm::dyn_cast<SymbolRefAttr>(attr)) {
347 paramCheckResult = failure();
349 }
else if (TypeAttr typeParam = llvm::dyn_cast<TypeAttr>(attr)) {
351 paramCheckResult = failure();
356 return paramCheckResult;
359FailureOr<StructDefOp>
367 return origin->emitError()
369 "Cannot unify parameters of type ", ty,
" with parameters of '",
372 .attachNote(defForType.getLoc())
373 .append(
"type parameters must unify with parameters defined here");
376 if (ArrayAttr tyParams = ty.
getParams()) {
385 if (
StructType sTy = llvm::dyn_cast<StructType>(ty)) {
387 }
else if (
ArrayType aTy = llvm::dyn_cast<ArrayType>(ty)) {
392 }
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::ArrayAttr getParams() const
::mlir::FailureOr< SymbolLookupResult< StructDefOp > > getDefinition(::mlir::SymbolTableCollection &symbolTable, ::mlir::Operation *op) const
Gets the struct op that defines this struct.
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 specifies the IR language name.
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)
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)
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.
mlir::FailureOr< OpClass > getParentOfType(mlir::Operation *op)
Return the closest surrounding parent operation that is of type 'OpClass'.
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)