-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[mlir] Add concept of alias blocks #65503
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ | |
#include "mlir/IR/BuiltinTypes.h" | ||
#include "mlir/IR/Dialect.h" | ||
#include "mlir/IR/DialectImplementation.h" | ||
#include "llvm/ADT/ScopeExit.h" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: This seems to be unused |
||
#include "llvm/Support/SourceMgr.h" | ||
|
||
using namespace mlir; | ||
|
@@ -156,9 +157,11 @@ ParseResult Parser::parseDialectSymbolBody(StringRef &body, | |
} | ||
|
||
/// Parse an extended dialect symbol. | ||
template <typename Symbol, typename SymbolAliasMap, typename CreateFn> | ||
template <typename Symbol, typename SymbolAliasMap, typename ParseAliasFn, | ||
typename CreateFn> | ||
static Symbol parseExtendedSymbol(Parser &p, AsmParserState *asmState, | ||
SymbolAliasMap &aliases, | ||
ParseAliasFn &parseAliasFn, | ||
CreateFn &&createSymbol) { | ||
Token tok = p.getToken(); | ||
|
||
|
@@ -185,12 +188,32 @@ static Symbol parseExtendedSymbol(Parser &p, AsmParserState *asmState, | |
// If there is no '<' token following this, and if the typename contains no | ||
// dot, then we are parsing a symbol alias. | ||
if (!hasTrailingData && !isPrettyName) { | ||
|
||
// Don't check the validity of alias reference in syntax-only mode. | ||
if (p.syntaxOnly()) { | ||
if constexpr (std::is_same_v<Symbol, Type>) | ||
return p.getState().syntaxOnlyType; | ||
else | ||
return p.getState().syntaxOnlyAttr; | ||
} | ||
|
||
// Check for an alias for this type. | ||
auto aliasIt = aliases.find(identifier); | ||
if (aliasIt == aliases.end()) | ||
return (p.emitWrongTokenError("undefined symbol alias id '" + identifier + | ||
"'"), | ||
nullptr); | ||
if (aliasIt == aliases.end()) { | ||
FailureOr<Symbol> symbol = failure(); | ||
// Try the parse alias function if set. | ||
if (parseAliasFn) | ||
symbol = parseAliasFn(identifier); | ||
|
||
if (failed(symbol)) { | ||
p.emitWrongTokenError("undefined symbol alias id '" + identifier + "'"); | ||
return nullptr; | ||
} | ||
if (!*symbol) | ||
return nullptr; | ||
|
||
aliasIt = aliases.insert({identifier, *symbol}).first; | ||
} | ||
if (asmState) { | ||
if constexpr (std::is_same_v<Symbol, Type>) | ||
asmState->addTypeAliasUses(identifier, range); | ||
|
@@ -241,12 +264,16 @@ Attribute Parser::parseExtendedAttr(Type type) { | |
MLIRContext *ctx = getContext(); | ||
Attribute attr = parseExtendedSymbol<Attribute>( | ||
*this, state.asmState, state.symbols.attributeAliasDefinitions, | ||
state.symbols.parseUnknownAttributeAlias, | ||
[&](StringRef dialectName, StringRef symbolData, SMLoc loc) -> Attribute { | ||
// Parse an optional trailing colon type. | ||
Type attrType = type; | ||
if (consumeIf(Token::colon) && !(attrType = parseType())) | ||
return Attribute(); | ||
|
||
if (syntaxOnly()) | ||
return state.syntaxOnlyAttr; | ||
|
||
// If we found a registered dialect, then ask it to parse the attribute. | ||
if (Dialect *dialect = | ||
builder.getContext()->getOrLoadDialect(dialectName)) { | ||
|
@@ -288,7 +315,11 @@ Type Parser::parseExtendedType() { | |
MLIRContext *ctx = getContext(); | ||
return parseExtendedSymbol<Type>( | ||
*this, state.asmState, state.symbols.typeAliasDefinitions, | ||
state.symbols.parseUnknownTypeAlias, | ||
[&](StringRef dialectName, StringRef symbolData, SMLoc loc) -> Type { | ||
if (syntaxOnly()) | ||
return state.syntaxOnlyType; | ||
|
||
// If we found a registered dialect, then ask it to parse the type. | ||
if (auto *dialect = ctx->getOrLoadDialect(dialectName)) { | ||
// Temporarily reset the lexer to let the dialect parse the type. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,6 +53,9 @@ ParseResult Parser::parseCallSiteLocation(LocationAttr &loc) { | |
if (parseToken(Token::r_paren, "expected ')' in callsite location")) | ||
return failure(); | ||
|
||
if (syntaxOnly()) | ||
return success(); | ||
|
||
// Return the callsite location. | ||
loc = CallSiteLoc::get(calleeLoc, callerLoc); | ||
return success(); | ||
|
@@ -79,6 +82,9 @@ ParseResult Parser::parseFusedLocation(LocationAttr &loc) { | |
LocationAttr newLoc; | ||
if (parseLocationInstance(newLoc)) | ||
return failure(); | ||
if (syntaxOnly()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems very invasive. There is prior art to allow use-before-def, such as deferred aliases. Why won't that work for your use-case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I ruled out the deferred aliases approach as not implementable. The reason I don't think is implementable is because todays attributes and types would not be able to handle having some placeholder returned from I agree that this is invasive and I'd love to hear better options. I initially considered writing separate The silver lining is that this logic and invasiveness is private to the parser implementation and not user exposed and only part of the builtin attribute and type parsing, not any dialect parsing. |
||
return success(); | ||
|
||
locations.push_back(newLoc); | ||
return success(); | ||
}; | ||
|
@@ -135,12 +141,15 @@ ParseResult Parser::parseNameOrFileLineColLocation(LocationAttr &loc) { | |
if (parseLocationInstance(childLoc)) | ||
return failure(); | ||
|
||
loc = NameLoc::get(StringAttr::get(ctx, str), childLoc); | ||
|
||
// Parse the closing ')'. | ||
if (parseToken(Token::r_paren, | ||
"expected ')' after child location of NameLoc")) | ||
return failure(); | ||
|
||
if (syntaxOnly()) | ||
return success(); | ||
|
||
loc = NameLoc::get(StringAttr::get(ctx, str), childLoc); | ||
} else { | ||
loc = NameLoc::get(StringAttr::get(ctx, str)); | ||
} | ||
|
@@ -154,6 +163,10 @@ ParseResult Parser::parseLocationInstance(LocationAttr &loc) { | |
Attribute locAttr = parseExtendedAttr(Type()); | ||
if (!locAttr) | ||
return failure(); | ||
|
||
if (syntaxOnly()) | ||
return success(); | ||
|
||
if (!(loc = dyn_cast<LocationAttr>(locAttr))) | ||
return emitError("expected location attribute, but got") << locAttr; | ||
return success(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If understand this correctly, it's basically a forward declaration?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really. It's essentially a use-before-def. Aliases within a block are allowed to reference other aliases within the block prior to their definition.
So in this case
#integer_attr
and!integer_type
are declared afterwards, not prior.If it were a forward declaration then I'd think it'd look something like:
this would in my opinion not be very intuative and for the larger issue I am trying to solve, that is using aliases with cyclic attributes and types, less ergonomic:
instead of just
(llvm dialect only used for illustrative purposes)
This would also require an API/Interface for mutable attributes and types to return a "forward" declaration