blob: d5cc707f4109e21e8620858fe65a8b48ede07b09 [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 Lattnere79379a2018-06-22 10:39:19 -0700122};
123} // end anonymous namespace
124
125//===----------------------------------------------------------------------===//
126// Helper methods.
127//===----------------------------------------------------------------------===//
128
Chris Lattner4c95a502018-06-23 16:03:42 -0700129ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700130 // If we hit a parse error in response to a lexer error, then the lexer
131 // already emitted an error.
132 if (curToken.is(Token::error))
133 return ParseFailure;
134
Chris Lattnere79379a2018-06-22 10:39:19 -0700135 // TODO(clattner): If/when we want to implement a -verify mode, this will need
136 // to package up errors into SMDiagnostic and report them.
Chris Lattner4c95a502018-06-23 16:03:42 -0700137 lex.getSourceMgr().PrintMessage(loc, SourceMgr::DK_Error, message);
Chris Lattnere79379a2018-06-22 10:39:19 -0700138 return ParseFailure;
139}
140
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700141/// Parse a comma-separated list of elements, terminated with an arbitrary
142/// token. This allows empty lists if allowEmptyList is true.
143///
144/// abstract-list ::= rightToken // if allowEmptyList == true
145/// abstract-list ::= element (',' element)* rightToken
146///
147ParseResult Parser::
148parseCommaSeparatedList(Token::TokenKind rightToken,
149 const std::function<ParseResult()> &parseElement,
150 bool allowEmptyList) {
151 // Handle the empty case.
152 if (curToken.is(rightToken)) {
153 if (!allowEmptyList)
154 return emitError("expected list element");
155 consumeToken(rightToken);
156 return ParseSuccess;
157 }
158
159 // Non-empty case starts with an element.
160 if (parseElement())
161 return ParseFailure;
162
163 // Otherwise we have a list of comma separated elements.
164 while (consumeIf(Token::comma)) {
165 if (parseElement())
166 return ParseFailure;
167 }
168
169 // Consume the end character.
170 if (!consumeIf(rightToken))
171 return emitError("expected ',' or ')'");
172
173 return ParseSuccess;
174}
Chris Lattnere79379a2018-06-22 10:39:19 -0700175
176//===----------------------------------------------------------------------===//
177// Type Parsing
178//===----------------------------------------------------------------------===//
179
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700180/// Parse the low-level fixed dtypes in the system.
181///
182/// primitive-type
183/// ::= `f16` | `bf16` | `f32` | `f64` // Floating point
184/// | `i1` | `i8` | `i16` | `i32` | `i64` // Sized integers
185/// | `int`
186///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700187PrimitiveType *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700188 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700189 default:
190 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700191 case Token::kw_bf16:
192 consumeToken(Token::kw_bf16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700193 return Type::getBF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700194 case Token::kw_f16:
195 consumeToken(Token::kw_f16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700196 return Type::getF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700197 case Token::kw_f32:
198 consumeToken(Token::kw_f32);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700199 return Type::getF32(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700200 case Token::kw_f64:
201 consumeToken(Token::kw_f64);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700202 return Type::getF64(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700203 case Token::kw_i1:
204 consumeToken(Token::kw_i1);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700205 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700206 case Token::kw_i8:
207 consumeToken(Token::kw_i8);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700208 return Type::getI8(context);
209 case Token::kw_i16:
210 consumeToken(Token::kw_i16);
211 return Type::getI16(context);
212 case Token::kw_i32:
213 consumeToken(Token::kw_i32);
214 return Type::getI32(context);
215 case Token::kw_i64:
216 consumeToken(Token::kw_i64);
217 return Type::getI64(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700218 case Token::kw_int:
219 consumeToken(Token::kw_int);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700220 return Type::getInt(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700221 }
222}
223
224/// Parse the element type of a tensor or memref type.
225///
226/// element-type ::= primitive-type | vector-type
227///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700228Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700229 if (curToken.is(Token::kw_vector))
230 return parseVectorType();
231
232 return parsePrimitiveType();
233}
234
235/// Parse a vector type.
236///
237/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
238/// const-dimension-list ::= (integer-literal `x`)+
239///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700240VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700241 consumeToken(Token::kw_vector);
242
243 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700244 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700245
246 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700247 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700248
249 SmallVector<unsigned, 4> dimensions;
250 while (curToken.is(Token::integer)) {
251 // Make sure this integer value is in bound and valid.
252 auto dimension = curToken.getUnsignedIntegerValue();
253 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700254 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700255 dimensions.push_back(dimension.getValue());
256
257 consumeToken(Token::integer);
258
259 // Make sure we have an 'x' or something like 'xbf32'.
260 if (curToken.isNot(Token::bare_identifier) ||
261 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700262 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700263
264 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
265 if (curToken.getSpelling().size() != 1)
266 lex.resetPointer(curToken.getSpelling().data()+1);
267
268 // Consume the 'x'.
269 consumeToken(Token::bare_identifier);
270 }
271
272 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700273 auto *elementType = parsePrimitiveType();
274 if (!elementType)
275 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700276
277 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700278 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700279
Chris Lattnerf7e22732018-06-22 22:03:48 -0700280 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700281}
282
283/// Parse a dimension list of a tensor or memref type. This populates the
284/// dimension list, returning -1 for the '?' dimensions.
285///
286/// dimension-list-ranked ::= (dimension `x`)*
287/// dimension ::= `?` | integer-literal
288///
289ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
290 while (curToken.isAny(Token::integer, Token::question)) {
291 if (consumeIf(Token::question)) {
292 dimensions.push_back(-1);
293 } else {
294 // Make sure this integer value is in bound and valid.
295 auto dimension = curToken.getUnsignedIntegerValue();
296 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
297 return emitError("invalid dimension");
298 dimensions.push_back((int)dimension.getValue());
299 consumeToken(Token::integer);
300 }
301
302 // Make sure we have an 'x' or something like 'xbf32'.
303 if (curToken.isNot(Token::bare_identifier) ||
304 curToken.getSpelling()[0] != 'x')
305 return emitError("expected 'x' in dimension list");
306
307 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
308 if (curToken.getSpelling().size() != 1)
309 lex.resetPointer(curToken.getSpelling().data()+1);
310
311 // Consume the 'x'.
312 consumeToken(Token::bare_identifier);
313 }
314
315 return ParseSuccess;
316}
317
318/// Parse a tensor type.
319///
320/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
321/// dimension-list ::= dimension-list-ranked | `??`
322///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700323Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700324 consumeToken(Token::kw_tensor);
325
326 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700327 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700328
329 bool isUnranked;
330 SmallVector<int, 4> dimensions;
331
332 if (consumeIf(Token::questionquestion)) {
333 isUnranked = true;
334 } else {
335 isUnranked = false;
336 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700337 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700338 }
339
340 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700341 auto elementType = parseElementType();
342 if (!elementType)
343 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700344
345 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700346 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700347
MLIR Team355ec862018-06-23 18:09:09 -0700348 if (isUnranked)
349 return UnrankedTensorType::get(elementType);
350 return RankedTensorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700351}
352
353/// Parse a memref type.
354///
355/// memref-type ::= `memref` `<` dimension-list-ranked element-type
356/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
357///
358/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
359/// memory-space ::= integer-literal /* | TODO: address-space-id */
360///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700361Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700362 consumeToken(Token::kw_memref);
363
364 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700365 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700366
367 SmallVector<int, 4> dimensions;
368 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700369 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700370
371 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700372 auto elementType = parseElementType();
373 if (!elementType)
374 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700375
376 // TODO: Parse semi-affine-map-composition.
377 // TODO: Parse memory-space.
378
379 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700380 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700381
Chris Lattnerf7e22732018-06-22 22:03:48 -0700382 // FIXME: Add an IR representation for memref types.
383 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700384}
385
386
387
388/// Parse a function type.
389///
390/// function-type ::= type-list-parens `->` type-list
391///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700392Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700393 assert(curToken.is(Token::l_paren));
394
Chris Lattnerf7e22732018-06-22 22:03:48 -0700395 SmallVector<Type*, 4> arguments;
396 if (parseTypeList(arguments))
397 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700398
399 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700400 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700401
Chris Lattnerf7e22732018-06-22 22:03:48 -0700402 SmallVector<Type*, 4> results;
403 if (parseTypeList(results))
404 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700405
Chris Lattnerf7e22732018-06-22 22:03:48 -0700406 return FunctionType::get(arguments, results, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700407}
408
409
410/// Parse an arbitrary type.
411///
412/// type ::= primitive-type
413/// | vector-type
414/// | tensor-type
415/// | memref-type
416/// | function-type
417/// element-type ::= primitive-type | vector-type
418///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700419Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700420 switch (curToken.getKind()) {
421 case Token::kw_memref: return parseMemRefType();
422 case Token::kw_tensor: return parseTensorType();
423 case Token::kw_vector: return parseVectorType();
424 case Token::l_paren: return parseFunctionType();
425 default:
426 return parsePrimitiveType();
427 }
428}
429
430/// Parse a "type list", which is a singular type, or a parenthesized list of
431/// types.
432///
433/// type-list ::= type-list-parens | type
434/// type-list-parens ::= `(` `)`
435/// | `(` type (`,` type)* `)`
436///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700437ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
438 auto parseElt = [&]() -> ParseResult {
439 auto elt = parseType();
440 elements.push_back(elt);
441 return elt ? ParseSuccess : ParseFailure;
442 };
443
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700444 // If there is no parens, then it must be a singular type.
445 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700446 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700447
Chris Lattnerf7e22732018-06-22 22:03:48 -0700448 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700449 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700450
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700451 return ParseSuccess;
452}
453
Chris Lattner4c95a502018-06-23 16:03:42 -0700454//===----------------------------------------------------------------------===//
455// Functions
456//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -0700457
Chris Lattnere79379a2018-06-22 10:39:19 -0700458
459/// Parse a function signature, starting with a name and including the parameter
460/// list.
461///
462/// argument-list ::= type (`,` type)* | /*empty*/
463/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
464///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700465ParseResult Parser::parseFunctionSignature(StringRef &name,
466 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700467 if (curToken.isNot(Token::at_identifier))
468 return emitError("expected a function identifier like '@foo'");
469
470 name = curToken.getSpelling().drop_front();
471 consumeToken(Token::at_identifier);
472
473 if (curToken.isNot(Token::l_paren))
474 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -0700475
Chris Lattnerf7e22732018-06-22 22:03:48 -0700476 SmallVector<Type*, 4> arguments;
477 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700478 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -0700479
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700480 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700481 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700482 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700483 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700484 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700485 }
Chris Lattnerf7e22732018-06-22 22:03:48 -0700486 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -0700487 return ParseSuccess;
488}
489
490
491/// External function declarations.
492///
493/// ext-func ::= `extfunc` function-signature
494///
495ParseResult Parser::parseExtFunc() {
496 consumeToken(Token::kw_extfunc);
497
498 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700499 FunctionType *type = nullptr;
500 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -0700501 return ParseFailure;
502
503
504 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -0700505 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -0700506 return ParseSuccess;
507}
508
509
Chris Lattner4c95a502018-06-23 16:03:42 -0700510namespace {
511/// This class represents the transient parser state for the internals of a
512/// function as we are parsing it, e.g. the names for basic blocks. It handles
513/// forward references.
514class CFGFunctionParserState {
515public:
516 CFGFunctionParserState(CFGFunction *function) : function(function) {}
517
518 /// Get the basic block with the specified name, creating it if it doesn't
519 /// already exist.
520 BasicBlock *getBlockNamed(StringRef name) {
521 auto *&block = blocksByName[name];
522 if (!block) {
523 block = new BasicBlock(function);
524 // TODO: Should be automatic when we have the right function
525 // representation.
526 function->blockList.push_back(block);
527 }
528 return block;
529 }
530private:
MLIR Team355ec862018-06-23 18:09:09 -0700531 CFGFunction *function;
Chris Lattner4c95a502018-06-23 16:03:42 -0700532 llvm::StringMap<BasicBlock*> blocksByName;
533};
534} // end anonymous namespace
535
536
537/// CFG function declarations.
538///
539/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
540///
541ParseResult Parser::parseCFGFunc() {
542 consumeToken(Token::kw_cfgfunc);
543
544 StringRef name;
545 FunctionType *type = nullptr;
546 if (parseFunctionSignature(name, type))
547 return ParseFailure;
548
549 if (!consumeIf(Token::l_brace))
550 return emitError("expected '{' in CFG function");
551
552 // Okay, the CFG function signature was parsed correctly, create the function.
553 auto function = new CFGFunction(name, type);
554
555 // Make sure we have at least one block.
556 if (curToken.is(Token::r_brace))
557 return emitError("CFG functions must have at least one basic block");
558
559 CFGFunctionParserState functionState(function);
560
561 // Parse the list of blocks.
562 while (!consumeIf(Token::r_brace))
563 if (parseBasicBlock(functionState))
564 return ParseFailure;
565
566 module->functionList.push_back(function);
567 return ParseSuccess;
568}
569
570/// Basic block declaration.
571///
572/// basic-block ::= bb-label instruction* terminator-stmt
573/// bb-label ::= bb-id bb-arg-list? `:`
574/// bb-id ::= bare-id
575/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
576///
577ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
578 SMLoc nameLoc = curToken.getLoc();
579 auto name = curToken.getSpelling();
580 if (!consumeIf(Token::bare_identifier))
581 return emitError("expected basic block name");
582 auto block = functionState.getBlockNamed(name);
583
584 // If this block has already been parsed, then this is a redefinition with the
585 // same block name.
586 if (block->getTerminator())
587 return emitError(nameLoc, "redefinition of block named '" +
588 name.str() + "'");
589
590 // TODO: parse bb argument list.
591
592 if (!consumeIf(Token::colon))
593 return emitError("expected ':' after basic block name");
594
595
596 // TODO(clattner): Verify block hasn't already been parsed (this would be a
597 // redefinition of the same name) once we have a body implementation.
598
599 // TODO(clattner): Move block to the end of the list, once we have a proper
600 // block list representation in CFGFunction.
601
602 // TODO: parse instruction list.
603
604 // TODO: Generalize this once instruction list parsing is built out.
605 if (!consumeIf(Token::kw_return))
606 return emitError("expected 'return' at end of basic block");
607
608 block->setTerminator(new ReturnInst(block));
609
610 return ParseSuccess;
611}
612
613
614//===----------------------------------------------------------------------===//
615// Top-level entity parsing.
616//===----------------------------------------------------------------------===//
617
Chris Lattnere79379a2018-06-22 10:39:19 -0700618/// This is the top-level module parser.
619Module *Parser::parseModule() {
620 while (1) {
621 switch (curToken.getKind()) {
622 default:
623 emitError("expected a top level entity");
624 return nullptr;
625
626 // If we got to the end of the file, then we're done.
627 case Token::eof:
628 return module.release();
629
630 // If we got an error token, then the lexer already emitted an error, just
631 // stop. Someday we could introduce error recovery if there was demand for
632 // it.
633 case Token::error:
634 return nullptr;
635
636 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -0700637 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -0700638 break;
639
Chris Lattner4c95a502018-06-23 16:03:42 -0700640 case Token::kw_cfgfunc:
641 if (parseCFGFunc()) return nullptr;
642 break;
643
644 // TODO: mlfunc, affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -0700645 }
646 }
647}
648
649//===----------------------------------------------------------------------===//
650
651/// This parses the file specified by the indicated SourceMgr and returns an
652/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700653Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context){
654 return Parser(sourceMgr, context).parseModule();
Chris Lattnere79379a2018-06-22 10:39:19 -0700655}