Implement initial support for function attributes, including parser, printer,
resolver support.
Still TODO are verifier support (to make sure you don't use an attribute for a
function in another module) and the TODO in ModuleParser::finalizeModule that I
will handle in the next patch.
PiperOrigin-RevId: 209361648
diff --git a/lib/Parser/Parser.cpp b/lib/Parser/Parser.cpp
index ae87ad2..5310daa 100644
--- a/lib/Parser/Parser.cpp
+++ b/lib/Parser/Parser.cpp
@@ -58,9 +58,15 @@
// A map from affine map identifier to AffineMap.
llvm::StringMap<AffineMap *> affineMapDefinitions;
+
// A map from integer set identifier to IntegerSet.
llvm::StringMap<IntegerSet *> integerSetDefinitions;
+ // This keeps track of all forward references to functions along with the
+ // temporary function used to represent them and the location of the first
+ // reference.
+ llvm::DenseMap<Identifier, std::pair<Function *, SMLoc>> functionForwardRefs;
+
private:
ParserState(const ParserState &) = delete;
void operator=(const ParserState &) = delete;
@@ -579,6 +585,7 @@
/// | string-literal
/// | type
/// | `[` (attribute-value (`,` attribute-value)*)? `]`
+/// | function-id `:` function-type
///
Attribute *Parser::parseAttribute() {
switch (getToken().getKind()) {
@@ -653,6 +660,42 @@
return builder.getAffineMapAttr(affineMap);
return (emitError("expected constant attribute value"), nullptr);
}
+
+ case Token::at_identifier: {
+ auto nameLoc = getToken().getLoc();
+ Identifier name = builder.getIdentifier(getTokenSpelling().drop_front());
+ consumeToken(Token::at_identifier);
+
+ if (parseToken(Token::colon, "expected ':' and function type"))
+ return nullptr;
+ auto typeLoc = getToken().getLoc();
+ Type *type = parseType();
+ if (!type)
+ return nullptr;
+ auto fnType = dyn_cast<FunctionType>(type);
+ if (!fnType)
+ return (emitError(typeLoc, "expected function type"), nullptr);
+
+ // See if the function has already been defined in the module.
+ Function *function = getModule()->getNamedFunction(name);
+
+ // If not, get or create a forward reference to one.
+ if (!function) {
+ auto &entry = state.functionForwardRefs[name];
+ if (!entry.first) {
+ entry.first = new ExtFunction(name, fnType);
+ entry.second = nameLoc;
+ }
+ function = entry.first;
+ }
+
+ if (function->getType() != type)
+ return (emitError(typeLoc, "reference to function with mismatched type"),
+ nullptr);
+
+ return builder.getFunctionAttr(function);
+ }
+
default: {
if (Type *type = parseType())
return builder.getTypeAttr(type);
@@ -2426,6 +2469,8 @@
ParseResult parseModule();
private:
+ ParseResult finalizeModule();
+
ParseResult parseAffineMapDef();
ParseResult parseIntegerSetDef();
@@ -2587,7 +2632,7 @@
getModule()->getFunctions().push_back(function);
// Verify no name collision / redefinition.
- if (function->getName().ref() != name)
+ if (function->getName() != name)
return emitError(loc,
"redefinition of function named '" + name.str() + "'");
@@ -2612,7 +2657,7 @@
getModule()->getFunctions().push_back(function);
// Verify no name collision / redefinition.
- if (function->getName().ref() != name)
+ if (function->getName() != name)
return emitError(loc,
"redefinition of function named '" + name.str() + "'");
@@ -2639,7 +2684,7 @@
getModule()->getFunctions().push_back(function);
// Verify no name collision / redefinition.
- if (function->getName().ref() != name)
+ if (function->getName() != name)
return emitError(loc,
"redefinition of function named '" + name.str() + "'");
@@ -2655,6 +2700,27 @@
return parser.parseFunctionBody();
}
+/// Finish the end of module parsing - when the result is valid, do final
+/// checking.
+ParseResult ModuleParser::finalizeModule() {
+
+ // Resolve all forward references.
+ for (auto forwardRef : getState().functionForwardRefs) {
+ auto name = forwardRef.first;
+
+ // Resolve the reference.
+ auto *resolvedFunction = getModule()->getNamedFunction(name);
+ if (!resolvedFunction)
+ return emitError(forwardRef.second.second,
+ "reference to undefined function '" + name.str() + "'");
+
+ // TODO(clattner): actually go through and update references in the module
+ // to the new function.
+ }
+
+ return ParseSuccess;
+}
+
/// This is the top-level module parser.
ParseResult ModuleParser::parseModule() {
while (1) {
@@ -2665,7 +2731,7 @@
// If we got to the end of the file, then we're done.
case Token::eof:
- return ParseSuccess;
+ return finalizeModule();
// If we got an error token, then the lexer already emitted an error, just
// stop. Someday we could introduce error recovery if there was demand for