Implement parser/IR support for CFG functions, basic blocks and return instruction.
This is pretty much minimal scaffolding for this step. Basic block arguments,
instructions, other terminators, a proper IR representation for
blocks/instructions, etc are all coming.
PiperOrigin-RevId: 201826439
diff --git a/lib/Parser/Parser.cpp b/lib/Parser/Parser.cpp
index 7e3076f..11d289f 100644
--- a/lib/Parser/Parser.cpp
+++ b/lib/Parser/Parser.cpp
@@ -22,12 +22,16 @@
#include "mlir/Parser.h"
#include "Lexer.h"
#include "mlir/IR/Module.h"
+#include "mlir/IR/CFGFunction.h"
#include "mlir/IR/Types.h"
#include "llvm/Support/SourceMgr.h"
using namespace mlir;
using llvm::SourceMgr;
+using llvm::SMLoc;
namespace {
+class CFGFunctionParserState;
+
/// Simple enum to make code read better in cases that would otherwise return a
/// bool value. Failure is "true" in a boolean context.
enum ParseResult {
@@ -61,7 +65,10 @@
// Helper methods.
/// Emit an error and return failure.
- ParseResult emitError(const Twine &message);
+ ParseResult emitError(const Twine &message) {
+ return emitError(curToken.getLoc(), message);
+ }
+ ParseResult emitError(SMLoc loc, const Twine &message);
/// Advance the current lexer onto the next token.
void consumeToken() {
@@ -107,9 +114,11 @@
Type *parseType();
ParseResult parseTypeList(SmallVectorImpl<Type*> &elements);
- // Top level entity parsing.
+ // Functions.
ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
ParseResult parseExtFunc();
+ ParseResult parseCFGFunc();
+ ParseResult parseBasicBlock(CFGFunctionParserState &functionState);
};
} // end anonymous namespace
@@ -117,7 +126,7 @@
// Helper methods.
//===----------------------------------------------------------------------===//
-ParseResult Parser::emitError(const Twine &message) {
+ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
// If we hit a parse error in response to a lexer error, then the lexer
// already emitted an error.
if (curToken.is(Token::error))
@@ -125,8 +134,7 @@
// TODO(clattner): If/when we want to implement a -verify mode, this will need
// to package up errors into SMDiagnostic and report them.
- lex.getSourceMgr().PrintMessage(curToken.getLoc(), SourceMgr::DK_Error,
- message);
+ lex.getSourceMgr().PrintMessage(loc, SourceMgr::DK_Error, message);
return ParseFailure;
}
@@ -442,10 +450,10 @@
return ParseSuccess;
}
+//===----------------------------------------------------------------------===//
+// Functions
+//===----------------------------------------------------------------------===//
-//===----------------------------------------------------------------------===//
-// Top-level entity parsing.
-//===----------------------------------------------------------------------===//
/// Parse a function signature, starting with a name and including the parameter
/// list.
@@ -493,11 +501,119 @@
// Okay, the external function definition was parsed correctly.
- module->functionList.push_back(new Function(name, type));
+ module->functionList.push_back(new ExtFunction(name, type));
return ParseSuccess;
}
+namespace {
+/// This class represents the transient parser state for the internals of a
+/// function as we are parsing it, e.g. the names for basic blocks. It handles
+/// forward references.
+class CFGFunctionParserState {
+public:
+ CFGFunctionParserState(CFGFunction *function) : function(function) {}
+
+ /// Get the basic block with the specified name, creating it if it doesn't
+ /// already exist.
+ BasicBlock *getBlockNamed(StringRef name) {
+ auto *&block = blocksByName[name];
+ if (!block) {
+ block = new BasicBlock(function);
+ // TODO: Should be automatic when we have the right function
+ // representation.
+ function->blockList.push_back(block);
+ }
+ return block;
+ }
+private:
+ CFGFunction *function;
+ llvm::StringMap<BasicBlock*> blocksByName;
+};
+} // end anonymous namespace
+
+
+/// CFG function declarations.
+///
+/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
+///
+ParseResult Parser::parseCFGFunc() {
+ consumeToken(Token::kw_cfgfunc);
+
+ StringRef name;
+ FunctionType *type = nullptr;
+ if (parseFunctionSignature(name, type))
+ return ParseFailure;
+
+ if (!consumeIf(Token::l_brace))
+ return emitError("expected '{' in CFG function");
+
+ // Okay, the CFG function signature was parsed correctly, create the function.
+ auto function = new CFGFunction(name, type);
+
+ // Make sure we have at least one block.
+ if (curToken.is(Token::r_brace))
+ return emitError("CFG functions must have at least one basic block");
+
+ CFGFunctionParserState functionState(function);
+
+ // Parse the list of blocks.
+ while (!consumeIf(Token::r_brace))
+ if (parseBasicBlock(functionState))
+ return ParseFailure;
+
+ module->functionList.push_back(function);
+ return ParseSuccess;
+}
+
+/// Basic block declaration.
+///
+/// basic-block ::= bb-label instruction* terminator-stmt
+/// bb-label ::= bb-id bb-arg-list? `:`
+/// bb-id ::= bare-id
+/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
+///
+ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
+ SMLoc nameLoc = curToken.getLoc();
+ auto name = curToken.getSpelling();
+ if (!consumeIf(Token::bare_identifier))
+ return emitError("expected basic block name");
+ auto block = functionState.getBlockNamed(name);
+
+ // If this block has already been parsed, then this is a redefinition with the
+ // same block name.
+ if (block->getTerminator())
+ return emitError(nameLoc, "redefinition of block named '" +
+ name.str() + "'");
+
+ // TODO: parse bb argument list.
+
+ if (!consumeIf(Token::colon))
+ return emitError("expected ':' after basic block name");
+
+
+ // TODO(clattner): Verify block hasn't already been parsed (this would be a
+ // redefinition of the same name) once we have a body implementation.
+
+ // TODO(clattner): Move block to the end of the list, once we have a proper
+ // block list representation in CFGFunction.
+
+ // TODO: parse instruction list.
+
+ // TODO: Generalize this once instruction list parsing is built out.
+ if (!consumeIf(Token::kw_return))
+ return emitError("expected 'return' at end of basic block");
+
+ block->setTerminator(new ReturnInst(block));
+
+ return ParseSuccess;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Top-level entity parsing.
+//===----------------------------------------------------------------------===//
+
/// This is the top-level module parser.
Module *Parser::parseModule() {
while (1) {
@@ -517,11 +633,14 @@
return nullptr;
case Token::kw_extfunc:
- if (parseExtFunc())
- return nullptr;
+ if (parseExtFunc()) return nullptr;
break;
- // TODO: cfgfunc, mlfunc, affine entity declarations, etc.
+ case Token::kw_cfgfunc:
+ if (parseCFGFunc()) return nullptr;
+ break;
+
+ // TODO: mlfunc, affine entity declarations, etc.
}
}
}