blob: 828a8d5ff8df3a8915ba38bb2ca18a2f77bddca1 [file] [log] [blame]
Chris Lattnere79379a2018-06-22 10:39:19 -07001//===- Parser.cpp - MLIR Parser Implementation ----------------------------===//
2//
3// Copyright 2019 The MLIR Authors.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16// =============================================================================
17//
18// This file implements the parser for the MLIR textual form.
19//
20//===----------------------------------------------------------------------===//
21
22#include "mlir/Parser.h"
23#include "Lexer.h"
24#include "mlir/IR/Module.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070025#include "mlir/IR/CFGFunction.h"
Chris Lattnerf7e22732018-06-22 22:03:48 -070026#include "mlir/IR/Types.h"
Chris Lattnere79379a2018-06-22 10:39:19 -070027#include "llvm/Support/SourceMgr.h"
28using namespace mlir;
29using llvm::SourceMgr;
Chris Lattner4c95a502018-06-23 16:03:42 -070030using llvm::SMLoc;
Chris Lattnere79379a2018-06-22 10:39:19 -070031
32namespace {
Chris Lattner4c95a502018-06-23 16:03:42 -070033class CFGFunctionParserState;
34
Chris Lattnerf7e22732018-06-22 22:03:48 -070035/// Simple enum to make code read better in cases that would otherwise return a
36/// bool value. Failure is "true" in a boolean context.
Chris Lattnere79379a2018-06-22 10:39:19 -070037enum ParseResult {
38 ParseSuccess,
39 ParseFailure
40};
41
42/// Main parser implementation.
43class Parser {
44 public:
Chris Lattnerf7e22732018-06-22 22:03:48 -070045 Parser(llvm::SourceMgr &sourceMgr, MLIRContext *context)
46 : context(context), lex(sourceMgr), curToken(lex.lexToken()){
Chris Lattnere79379a2018-06-22 10:39:19 -070047 module.reset(new Module());
48 }
49
50 Module *parseModule();
51private:
52 // State.
Chris Lattnerf7e22732018-06-22 22:03:48 -070053 MLIRContext *const context;
54
55 // The lexer for the source file we're parsing.
Chris Lattnere79379a2018-06-22 10:39:19 -070056 Lexer lex;
57
58 // This is the next token that hasn't been consumed yet.
59 Token curToken;
60
61 // This is the result module we are parsing into.
62 std::unique_ptr<Module> module;
63
64private:
65 // Helper methods.
66
67 /// Emit an error and return failure.
Chris Lattner4c95a502018-06-23 16:03:42 -070068 ParseResult emitError(const Twine &message) {
69 return emitError(curToken.getLoc(), message);
70 }
71 ParseResult emitError(SMLoc loc, const Twine &message);
Chris Lattnere79379a2018-06-22 10:39:19 -070072
73 /// Advance the current lexer onto the next token.
74 void consumeToken() {
75 assert(curToken.isNot(Token::eof, Token::error) &&
76 "shouldn't advance past EOF or errors");
77 curToken = lex.lexToken();
78 }
79
80 /// Advance the current lexer onto the next token, asserting what the expected
81 /// current token is. This is preferred to the above method because it leads
82 /// to more self-documenting code with better checking.
83 void consumeToken(Token::TokenKind kind) {
84 assert(curToken.is(kind) && "consumed an unexpected token");
85 consumeToken();
86 }
87
Chris Lattnerbb8fafc2018-06-22 15:52:02 -070088 /// If the current token has the specified kind, consume it and return true.
89 /// If not, return false.
90 bool consumeIf(Token::TokenKind kind) {
91 if (curToken.isNot(kind))
92 return false;
93 consumeToken(kind);
94 return true;
95 }
96
97 ParseResult parseCommaSeparatedList(Token::TokenKind rightToken,
98 const std::function<ParseResult()> &parseElement,
99 bool allowEmptyList = true);
100
Chris Lattnerf7e22732018-06-22 22:03:48 -0700101 // We have two forms of parsing methods - those that return a non-null
102 // pointer on success, and those that return a ParseResult to indicate whether
103 // they returned a failure. The second class fills in by-reference arguments
104 // as the results of their action.
105
Chris Lattnere79379a2018-06-22 10:39:19 -0700106 // Type parsing.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700107 PrimitiveType *parsePrimitiveType();
108 Type *parseElementType();
109 VectorType *parseVectorType();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700110 ParseResult parseDimensionListRanked(SmallVectorImpl<int> &dimensions);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700111 Type *parseTensorType();
112 Type *parseMemRefType();
113 Type *parseFunctionType();
114 Type *parseType();
115 ParseResult parseTypeList(SmallVectorImpl<Type*> &elements);
Chris Lattnere79379a2018-06-22 10:39:19 -0700116
Chris Lattner4c95a502018-06-23 16:03:42 -0700117 // Functions.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700118 ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
Chris Lattnere79379a2018-06-22 10:39:19 -0700119 ParseResult parseExtFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700120 ParseResult parseCFGFunc();
121 ParseResult parseBasicBlock(CFGFunctionParserState &functionState);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700122 TerminatorInst *parseTerminator(BasicBlock *currentBB,
123 CFGFunctionParserState &functionState);
124
Chris Lattnere79379a2018-06-22 10:39:19 -0700125};
126} // end anonymous namespace
127
128//===----------------------------------------------------------------------===//
129// Helper methods.
130//===----------------------------------------------------------------------===//
131
Chris Lattner4c95a502018-06-23 16:03:42 -0700132ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700133 // If we hit a parse error in response to a lexer error, then the lexer
134 // already emitted an error.
135 if (curToken.is(Token::error))
136 return ParseFailure;
137
Chris Lattnere79379a2018-06-22 10:39:19 -0700138 // TODO(clattner): If/when we want to implement a -verify mode, this will need
139 // to package up errors into SMDiagnostic and report them.
Chris Lattner4c95a502018-06-23 16:03:42 -0700140 lex.getSourceMgr().PrintMessage(loc, SourceMgr::DK_Error, message);
Chris Lattnere79379a2018-06-22 10:39:19 -0700141 return ParseFailure;
142}
143
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700144/// Parse a comma-separated list of elements, terminated with an arbitrary
145/// token. This allows empty lists if allowEmptyList is true.
146///
147/// abstract-list ::= rightToken // if allowEmptyList == true
148/// abstract-list ::= element (',' element)* rightToken
149///
150ParseResult Parser::
151parseCommaSeparatedList(Token::TokenKind rightToken,
152 const std::function<ParseResult()> &parseElement,
153 bool allowEmptyList) {
154 // Handle the empty case.
155 if (curToken.is(rightToken)) {
156 if (!allowEmptyList)
157 return emitError("expected list element");
158 consumeToken(rightToken);
159 return ParseSuccess;
160 }
161
162 // Non-empty case starts with an element.
163 if (parseElement())
164 return ParseFailure;
165
166 // Otherwise we have a list of comma separated elements.
167 while (consumeIf(Token::comma)) {
168 if (parseElement())
169 return ParseFailure;
170 }
171
172 // Consume the end character.
173 if (!consumeIf(rightToken))
174 return emitError("expected ',' or ')'");
175
176 return ParseSuccess;
177}
Chris Lattnere79379a2018-06-22 10:39:19 -0700178
179//===----------------------------------------------------------------------===//
180// Type Parsing
181//===----------------------------------------------------------------------===//
182
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700183/// Parse the low-level fixed dtypes in the system.
184///
185/// primitive-type
186/// ::= `f16` | `bf16` | `f32` | `f64` // Floating point
187/// | `i1` | `i8` | `i16` | `i32` | `i64` // Sized integers
188/// | `int`
189///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700190PrimitiveType *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700191 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700192 default:
193 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700194 case Token::kw_bf16:
195 consumeToken(Token::kw_bf16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700196 return Type::getBF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700197 case Token::kw_f16:
198 consumeToken(Token::kw_f16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700199 return Type::getF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700200 case Token::kw_f32:
201 consumeToken(Token::kw_f32);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700202 return Type::getF32(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700203 case Token::kw_f64:
204 consumeToken(Token::kw_f64);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700205 return Type::getF64(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700206 case Token::kw_i1:
207 consumeToken(Token::kw_i1);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700208 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700209 case Token::kw_i8:
210 consumeToken(Token::kw_i8);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700211 return Type::getI8(context);
212 case Token::kw_i16:
213 consumeToken(Token::kw_i16);
214 return Type::getI16(context);
215 case Token::kw_i32:
216 consumeToken(Token::kw_i32);
217 return Type::getI32(context);
218 case Token::kw_i64:
219 consumeToken(Token::kw_i64);
220 return Type::getI64(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700221 case Token::kw_int:
222 consumeToken(Token::kw_int);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700223 return Type::getInt(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700224 }
225}
226
227/// Parse the element type of a tensor or memref type.
228///
229/// element-type ::= primitive-type | vector-type
230///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700231Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700232 if (curToken.is(Token::kw_vector))
233 return parseVectorType();
234
235 return parsePrimitiveType();
236}
237
238/// Parse a vector type.
239///
240/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
241/// const-dimension-list ::= (integer-literal `x`)+
242///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700243VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700244 consumeToken(Token::kw_vector);
245
246 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700247 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700248
249 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700250 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700251
252 SmallVector<unsigned, 4> dimensions;
253 while (curToken.is(Token::integer)) {
254 // Make sure this integer value is in bound and valid.
255 auto dimension = curToken.getUnsignedIntegerValue();
256 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700257 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700258 dimensions.push_back(dimension.getValue());
259
260 consumeToken(Token::integer);
261
262 // Make sure we have an 'x' or something like 'xbf32'.
263 if (curToken.isNot(Token::bare_identifier) ||
264 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700265 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700266
267 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
268 if (curToken.getSpelling().size() != 1)
269 lex.resetPointer(curToken.getSpelling().data()+1);
270
271 // Consume the 'x'.
272 consumeToken(Token::bare_identifier);
273 }
274
275 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700276 auto *elementType = parsePrimitiveType();
277 if (!elementType)
278 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700279
280 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700281 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700282
Chris Lattnerf7e22732018-06-22 22:03:48 -0700283 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700284}
285
286/// Parse a dimension list of a tensor or memref type. This populates the
287/// dimension list, returning -1 for the '?' dimensions.
288///
289/// dimension-list-ranked ::= (dimension `x`)*
290/// dimension ::= `?` | integer-literal
291///
292ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
293 while (curToken.isAny(Token::integer, Token::question)) {
294 if (consumeIf(Token::question)) {
295 dimensions.push_back(-1);
296 } else {
297 // Make sure this integer value is in bound and valid.
298 auto dimension = curToken.getUnsignedIntegerValue();
299 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
300 return emitError("invalid dimension");
301 dimensions.push_back((int)dimension.getValue());
302 consumeToken(Token::integer);
303 }
304
305 // Make sure we have an 'x' or something like 'xbf32'.
306 if (curToken.isNot(Token::bare_identifier) ||
307 curToken.getSpelling()[0] != 'x')
308 return emitError("expected 'x' in dimension list");
309
310 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
311 if (curToken.getSpelling().size() != 1)
312 lex.resetPointer(curToken.getSpelling().data()+1);
313
314 // Consume the 'x'.
315 consumeToken(Token::bare_identifier);
316 }
317
318 return ParseSuccess;
319}
320
321/// Parse a tensor type.
322///
323/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
324/// dimension-list ::= dimension-list-ranked | `??`
325///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700326Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700327 consumeToken(Token::kw_tensor);
328
329 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700330 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700331
332 bool isUnranked;
333 SmallVector<int, 4> dimensions;
334
335 if (consumeIf(Token::questionquestion)) {
336 isUnranked = true;
337 } else {
338 isUnranked = false;
339 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700340 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700341 }
342
343 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700344 auto elementType = parseElementType();
345 if (!elementType)
346 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700347
348 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700349 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700350
MLIR Team355ec862018-06-23 18:09:09 -0700351 if (isUnranked)
352 return UnrankedTensorType::get(elementType);
353 return RankedTensorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700354}
355
356/// Parse a memref type.
357///
358/// memref-type ::= `memref` `<` dimension-list-ranked element-type
359/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
360///
361/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
362/// memory-space ::= integer-literal /* | TODO: address-space-id */
363///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700364Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700365 consumeToken(Token::kw_memref);
366
367 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700368 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700369
370 SmallVector<int, 4> dimensions;
371 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700372 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700373
374 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700375 auto elementType = parseElementType();
376 if (!elementType)
377 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700378
379 // TODO: Parse semi-affine-map-composition.
380 // TODO: Parse memory-space.
381
382 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700383 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700384
Chris Lattnerf7e22732018-06-22 22:03:48 -0700385 // FIXME: Add an IR representation for memref types.
386 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700387}
388
389
390
391/// Parse a function type.
392///
393/// function-type ::= type-list-parens `->` type-list
394///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700395Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700396 assert(curToken.is(Token::l_paren));
397
Chris Lattnerf7e22732018-06-22 22:03:48 -0700398 SmallVector<Type*, 4> arguments;
399 if (parseTypeList(arguments))
400 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700401
402 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700403 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700404
Chris Lattnerf7e22732018-06-22 22:03:48 -0700405 SmallVector<Type*, 4> results;
406 if (parseTypeList(results))
407 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700408
Chris Lattnerf7e22732018-06-22 22:03:48 -0700409 return FunctionType::get(arguments, results, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700410}
411
412
413/// Parse an arbitrary type.
414///
415/// type ::= primitive-type
416/// | vector-type
417/// | tensor-type
418/// | memref-type
419/// | function-type
420/// element-type ::= primitive-type | vector-type
421///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700422Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700423 switch (curToken.getKind()) {
424 case Token::kw_memref: return parseMemRefType();
425 case Token::kw_tensor: return parseTensorType();
426 case Token::kw_vector: return parseVectorType();
427 case Token::l_paren: return parseFunctionType();
428 default:
429 return parsePrimitiveType();
430 }
431}
432
433/// Parse a "type list", which is a singular type, or a parenthesized list of
434/// types.
435///
436/// type-list ::= type-list-parens | type
437/// type-list-parens ::= `(` `)`
438/// | `(` type (`,` type)* `)`
439///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700440ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
441 auto parseElt = [&]() -> ParseResult {
442 auto elt = parseType();
443 elements.push_back(elt);
444 return elt ? ParseSuccess : ParseFailure;
445 };
446
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700447 // If there is no parens, then it must be a singular type.
448 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700449 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700450
Chris Lattnerf7e22732018-06-22 22:03:48 -0700451 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700452 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700453
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700454 return ParseSuccess;
455}
456
Chris Lattner4c95a502018-06-23 16:03:42 -0700457//===----------------------------------------------------------------------===//
458// Functions
459//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -0700460
Chris Lattnere79379a2018-06-22 10:39:19 -0700461
462/// Parse a function signature, starting with a name and including the parameter
463/// list.
464///
465/// argument-list ::= type (`,` type)* | /*empty*/
466/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
467///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700468ParseResult Parser::parseFunctionSignature(StringRef &name,
469 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700470 if (curToken.isNot(Token::at_identifier))
471 return emitError("expected a function identifier like '@foo'");
472
473 name = curToken.getSpelling().drop_front();
474 consumeToken(Token::at_identifier);
475
476 if (curToken.isNot(Token::l_paren))
477 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -0700478
Chris Lattnerf7e22732018-06-22 22:03:48 -0700479 SmallVector<Type*, 4> arguments;
480 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700481 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -0700482
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700483 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700484 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700485 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700486 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700487 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700488 }
Chris Lattnerf7e22732018-06-22 22:03:48 -0700489 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -0700490 return ParseSuccess;
491}
492
493
494/// External function declarations.
495///
496/// ext-func ::= `extfunc` function-signature
497///
498ParseResult Parser::parseExtFunc() {
499 consumeToken(Token::kw_extfunc);
500
501 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700502 FunctionType *type = nullptr;
503 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -0700504 return ParseFailure;
505
506
507 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -0700508 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -0700509 return ParseSuccess;
510}
511
512
Chris Lattner4c95a502018-06-23 16:03:42 -0700513namespace {
514/// This class represents the transient parser state for the internals of a
515/// function as we are parsing it, e.g. the names for basic blocks. It handles
516/// forward references.
517class CFGFunctionParserState {
518public:
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700519 CFGFunction *function;
520 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
521
Chris Lattner4c95a502018-06-23 16:03:42 -0700522 CFGFunctionParserState(CFGFunction *function) : function(function) {}
523
524 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700525 /// already exist. The location specified is the point of use, which allows
526 /// us to diagnose references to blocks that are not defined precisely.
527 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
528 auto &blockAndLoc = blocksByName[name];
529 if (!blockAndLoc.first) {
530 blockAndLoc.first = new BasicBlock(function);
531 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -0700532 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700533 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -0700534 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700535};
536} // end anonymous namespace
537
538
539/// CFG function declarations.
540///
541/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
542///
543ParseResult Parser::parseCFGFunc() {
544 consumeToken(Token::kw_cfgfunc);
545
546 StringRef name;
547 FunctionType *type = nullptr;
548 if (parseFunctionSignature(name, type))
549 return ParseFailure;
550
551 if (!consumeIf(Token::l_brace))
552 return emitError("expected '{' in CFG function");
553
554 // Okay, the CFG function signature was parsed correctly, create the function.
555 auto function = new CFGFunction(name, type);
556
557 // Make sure we have at least one block.
558 if (curToken.is(Token::r_brace))
559 return emitError("CFG functions must have at least one basic block");
560
561 CFGFunctionParserState functionState(function);
562
563 // Parse the list of blocks.
564 while (!consumeIf(Token::r_brace))
565 if (parseBasicBlock(functionState))
566 return ParseFailure;
567
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700568 // Verify that all referenced blocks were defined. Iteration over a
569 // StringMap isn't determinstic, but this is good enough for our purposes.
570 for (auto &elt : functionState.blocksByName) {
571 auto *bb = elt.second.first;
572 if (!bb->getTerminator())
573 return emitError(elt.second.second,
574 "reference to an undefined basic block '" +
575 elt.first() + "'");
576 }
577
Chris Lattner4c95a502018-06-23 16:03:42 -0700578 module->functionList.push_back(function);
579 return ParseSuccess;
580}
581
582/// Basic block declaration.
583///
584/// basic-block ::= bb-label instruction* terminator-stmt
585/// bb-label ::= bb-id bb-arg-list? `:`
586/// bb-id ::= bare-id
587/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
588///
589ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
590 SMLoc nameLoc = curToken.getLoc();
591 auto name = curToken.getSpelling();
592 if (!consumeIf(Token::bare_identifier))
593 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700594
595 auto block = functionState.getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -0700596
597 // If this block has already been parsed, then this is a redefinition with the
598 // same block name.
599 if (block->getTerminator())
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700600 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
601
602 // References to blocks can occur in any order, but we need to reassemble the
603 // function in the order that occurs in the source file. Do this by moving
604 // each block to the end of the list as it is defined.
605 // FIXME: This is inefficient for large functions given that blockList is a
606 // vector. blockList will eventually be an ilist, which will make this fast.
607 auto &blockList = functionState.function->blockList;
608 if (blockList.back() != block) {
609 auto it = std::find(blockList.begin(), blockList.end(), block);
610 assert(it != blockList.end() && "Block has to be in the blockList");
611 std::swap(*it, blockList.back());
612 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700613
614 // TODO: parse bb argument list.
615
616 if (!consumeIf(Token::colon))
617 return emitError("expected ':' after basic block name");
618
619
620 // TODO(clattner): Verify block hasn't already been parsed (this would be a
621 // redefinition of the same name) once we have a body implementation.
622
623 // TODO(clattner): Move block to the end of the list, once we have a proper
624 // block list representation in CFGFunction.
625
626 // TODO: parse instruction list.
627
628 // TODO: Generalize this once instruction list parsing is built out.
Chris Lattner4c95a502018-06-23 16:03:42 -0700629
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700630 auto *termInst = parseTerminator(block, functionState);
631 if (!termInst)
632 return ParseFailure;
633 block->setTerminator(termInst);
Chris Lattner4c95a502018-06-23 16:03:42 -0700634
635 return ParseSuccess;
636}
637
638
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700639/// Parse the terminator instruction for a basic block.
640///
641/// terminator-stmt ::= `br` bb-id branch-use-list?
642/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
643/// terminator-stmt ::=
644/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
645/// terminator-stmt ::= `return` ssa-use-and-type-list?
646///
647TerminatorInst *Parser::parseTerminator(BasicBlock *currentBB,
648 CFGFunctionParserState &functionState) {
649 switch (curToken.getKind()) {
650 default:
651 return (emitError("expected terminator at end of basic block"), nullptr);
652
653 case Token::kw_return:
654 consumeToken(Token::kw_return);
655 return new ReturnInst(currentBB);
656
657 case Token::kw_br: {
658 consumeToken(Token::kw_br);
659 auto destBB = functionState.getBlockNamed(curToken.getSpelling(),
660 curToken.getLoc());
661 if (!consumeIf(Token::bare_identifier))
662 return (emitError("expected basic block name"), nullptr);
663 return new BranchInst(destBB, currentBB);
664 }
665 }
666}
667
668
Chris Lattner4c95a502018-06-23 16:03:42 -0700669//===----------------------------------------------------------------------===//
670// Top-level entity parsing.
671//===----------------------------------------------------------------------===//
672
Chris Lattnere79379a2018-06-22 10:39:19 -0700673/// This is the top-level module parser.
674Module *Parser::parseModule() {
675 while (1) {
676 switch (curToken.getKind()) {
677 default:
678 emitError("expected a top level entity");
679 return nullptr;
680
681 // If we got to the end of the file, then we're done.
682 case Token::eof:
683 return module.release();
684
685 // If we got an error token, then the lexer already emitted an error, just
686 // stop. Someday we could introduce error recovery if there was demand for
687 // it.
688 case Token::error:
689 return nullptr;
690
691 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -0700692 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -0700693 break;
694
Chris Lattner4c95a502018-06-23 16:03:42 -0700695 case Token::kw_cfgfunc:
696 if (parseCFGFunc()) return nullptr;
697 break;
698
699 // TODO: mlfunc, affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -0700700 }
701 }
702}
703
704//===----------------------------------------------------------------------===//
705
706/// This parses the file specified by the indicated SourceMgr and returns an
707/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700708Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context){
709 return Parser(sourceMgr, context).parseModule();
Chris Lattnere79379a2018-06-22 10:39:19 -0700710}