25#include <mlir/IR/BuiltinOps.h>
26#include <mlir/IR/BuiltinTypes.h>
27#include <mlir/IR/Operation.h>
29#include <llvm/ADT/TypeSwitch.h>
30#include <llvm/Support/Debug.h>
32#define DEBUG_TYPE "llzk-symbol-helpers"
39using namespace component;
40using namespace function;
41using namespace global;
42using namespace polymorphic;
50constexpr char POSITION_IS_ROOT_INDICATOR[] =
"<<symbol lookup root>>";
51constexpr char UNNAMED_SYMBOL_INDICATOR[] =
"<<unnamed symbol>>";
53enum RootSelector : std::uint8_t { CLOSEST, FURTHEST };
55class RootPathBuilder {
56 RootSelector _whichRoot;
61 RootPathBuilder(RootSelector whichRoot, Operation *origin, ModuleOp *foundRoot)
62 : _whichRoot(whichRoot), _origin(origin), _foundRoot(foundRoot) {}
71 FailureOr<ModuleOp> collectPathToRoot(Operation *
from, std::vector<FlatSymbolRefAttr> &path) {
73 ModuleOp currRoot =
nullptr;
75 if (ModuleOp m = llvm::dyn_cast_if_present<ModuleOp>(
check)) {
80 if (_whichRoot == RootSelector::CLOSEST) {
85 if (StringAttr modName = m.getSymNameAttr()) {
86 path.push_back(FlatSymbolRefAttr::get(modName));
87 }
else if (!currRoot) {
88 return _origin->emitOpError()
90 "has ancestor '", ModuleOp::getOperationName(),
"' without \"",
LANG_ATTR_NAME,
91 "\" attribute or a name"
93 .attachNote(m.getLoc())
94 .append(
"unnamed '", ModuleOp::getOperationName(),
"' here");
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));
103 if (_whichRoot == RootSelector::FURTHEST && currRoot) {
107 return _origin->emitOpError().append(
108 "has no ancestor '", ModuleOp::getOperationName(),
"' with \"",
LANG_ATTR_NAME,
115 FailureOr<SymbolRefAttr>
116 buildPathFromRootToAnyOp(Operation *position, std::vector<FlatSymbolRefAttr> &&path) {
118 FailureOr<ModuleOp> rootMod = collectPathToRoot(position, path);
119 if (failed(rootMod)) {
123 *_foundRoot = rootMod.value();
129 assert(position == rootMod.value().getOperation() &&
"empty path only at root itself");
133 std::vector<FlatSymbolRefAttr> reversedVec(path.rbegin(), path.rend());
138 FailureOr<SymbolRefAttr> getPathFromRootToAnyOp(Operation *op) {
139 std::vector<FlatSymbolRefAttr> path;
140 return buildPathFromRootToAnyOp(op, std::move(path));
145 FailureOr<SymbolRefAttr>
146 buildPathFromRootToStruct(StructDefOp to, std::vector<FlatSymbolRefAttr> &&path) {
148 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
149 return buildPathFromRootToAnyOp(to, std::move(path));
152 FailureOr<SymbolRefAttr> getPathFromRootToStruct(StructDefOp to) {
153 std::vector<FlatSymbolRefAttr> path;
154 return buildPathFromRootToStruct(to, std::move(path));
157 FailureOr<SymbolRefAttr> getPathFromRootToMember(MemberDefOp to) {
158 std::vector<FlatSymbolRefAttr> path;
160 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
162 return buildPathFromRootToStruct(to.getParentOp<StructDefOp>(), std::move(path));
165 FailureOr<SymbolRefAttr> getPathFromRootToFunc(FuncDefOp to) {
166 std::vector<FlatSymbolRefAttr> path;
168 path.push_back(FlatSymbolRefAttr::get(to.getSymNameAttr()));
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));
186 FailureOr<SymbolRefAttr> getPathFromRootToAnySymbol(SymbolOpInterface to) {
188 return TypeSwitch<Operation *, FailureOr<SymbolRefAttr>>(to.getOperation())
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); })
198 .Default([
this, &to](
auto) {
199 std::vector<FlatSymbolRefAttr> path;
201 path.push_back(FlatSymbolRefAttr::get(name));
204 assert(to.isOptionalSymbol());
205 path.push_back(FlatSymbolRefAttr::get(to.getContext(), UNNAMED_SYMBOL_INDICATOR));
207 return buildPathFromRootToAnyOp(to, std::move(path));
213LogicalResult verifyTemplateSymbolType(
214 TemplateSymbolBindingOpInterface binding, SymbolRefAttr param, Type parameterizedType,
215 Operation *origin, std::optional<Type> requiredParamType
217 if (requiredParamType) {
218 std::optional<Type> actualType = binding.getTypeOpt();
220 return origin->emitError().append(
221 "ref \"", param,
"\" in type ", parameterizedType,
" refers to a '", binding->getName(),
222 "' that must have type ", *requiredParamType
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
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());
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()) {
257SymbolRefAttr changeLeafImpl(
258 StringAttr origRoot, ArrayRef<FlatSymbolRefAttr> origTail, FlatSymbolRefAttr newLeaf,
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);
269SymbolRefAttr
replaceLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf) {
270 ArrayRef<FlatSymbolRefAttr> origTail = orig.getNestedReferences();
271 if (origTail.empty()) {
275 return changeLeafImpl(orig.getRootReference(), origTail, newLeaf);
279SymbolRefAttr
appendLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf) {
280 return changeLeafImpl(orig.getRootReference(), orig.getNestedReferences(), newLeaf, 0);
284 ArrayRef<FlatSymbolRefAttr> origTail = orig.getNestedReferences();
285 if (origTail.empty()) {
288 orig.getContext(), orig.getRootReference().getValue() + newLeafSuffix
291 return changeLeafImpl(
292 orig.getRootReference(), origTail,
299 std::vector<FlatSymbolRefAttr> path;
300 return RootPathBuilder(RootSelector::CLOSEST,
from,
nullptr).collectPathToRoot(
from, path);
304 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToAnySymbol(to);
308 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToAnyOp(to);
312 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToStruct(to);
316 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToMember(to);
320 return RootPathBuilder(RootSelector::CLOSEST, to, foundRoot).getPathFromRootToFunc(to);
324 std::vector<FlatSymbolRefAttr> path;
325 return RootPathBuilder(RootSelector::FURTHEST,
from,
nullptr).collectPathToRoot(
from, path);
329 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToAnySymbol(to);
333 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToAnyOp(to);
337 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToStruct(to);
341 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToMember(to);
345 return RootPathBuilder(RootSelector::FURTHEST, to, foundRoot).getPathFromRootToFunc(to);
350 if (failed(rootOpt)) {
353 ModuleOp root = rootOpt.value();
358 return success(
nullptr);
361FailureOr<SymbolLookupResult<StructDefOp>>
364 if (failed(mainStructTypeOpt)) {
367 if (
StructType st = mainStructTypeOpt.value()) {
368 return st.getDefinition(symbolTable, lookupFrom);
370 return success(
nullptr);
376 FailureOr<SymbolLookupResultUntyped> targetRes =
378 if (failed(targetRes)) {
383 return targetTemplate;
391 SymbolTableCollection &tables, SymbolRefAttr param, Type parameterizedType, Operation *origin,
392 std::optional<Type> requiredParamType
397 if (param.getNestedReferences().empty()) {
399 if (failed(parent)) {
406 return verifyTemplateSymbolType(b, param, parameterizedType, origin, requiredParamType);
412 if (failed(lookupRes)) {
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";
425 SymbolTableCollection &tables, ArrayRef<Attribute> tyParams, Type parameterizedType,
426 Operation *origin, std::optional<Type> requiredParamType
430 LogicalResult paramCheckResult = success();
432 llvm::dbgs() <<
"[verifyParamOfType] parameterizedType = " << parameterizedType <<
'\n';
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);
441 llvm::dbgs() <<
"[verifyParamOfType] failed to verify symbol attribute\n";
443 paramCheckResult = failure();
445 }
else if (TypeAttr typeParam = llvm::dyn_cast<TypeAttr>(attr)) {
448 llvm::dbgs() <<
"[verifyParamOfType] failed to verify type attribute\n";
450 paramCheckResult = failure();
453 LLVM_DEBUG({ llvm::dbgs() <<
"[verifyParamOfType] verified attribute\n"; });
456 return paramCheckResult;
459FailureOr<StructDefOp>
467 return origin->emitError()
469 "Cannot unify parameters of type ", ty,
" with parameters of '",
472 .attachNote(defForType.getLoc())
473 .append(
"type parameters must unify with parameters defined here");
476 if (ArrayAttr tyParams = ty.
getParams()) {
485 if (
StructType sTy = llvm::dyn_cast<StructType>(ty)) {
487 }
else if (
ArrayType aTy = llvm::dyn_cast<ArrayType>(ty)) {
489 tables, aTy.getDimensionSizes(), aTy, origin, IndexType::get(aTy.getContext())
495 }
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 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)
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.
LogicalResult verifyParamOfType(SymbolTableCollection &tables, SymbolRefAttr param, Type parameterizedType, Operation *origin, std::optional< Type > requiredParamType)