blob: 11d289f9dbe8c1bd4026e6b9ba2bb1d777a9d3e2 [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
Chris Lattnerf7e22732018-06-22 22:03:48 -0700348 // FIXME: Add an IR representation for tensor types.
349 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700350}
351
352/// Parse a memref type.
353///
354/// memref-type ::= `memref` `<` dimension-list-ranked element-type
355/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
356///
357/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
358/// memory-space ::= integer-literal /* | TODO: address-space-id */
359///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700360Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700361 consumeToken(Token::kw_memref);
362
363 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700364 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700365
366 SmallVector<int, 4> dimensions;
367 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700368 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700369
370 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700371 auto elementType = parseElementType();
372 if (!elementType)
373 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700374
375 // TODO: Parse semi-affine-map-composition.
376 // TODO: Parse memory-space.
377
378 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700379 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700380
Chris Lattnerf7e22732018-06-22 22:03:48 -0700381 // FIXME: Add an IR representation for memref types.
382 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700383}
384
385
386
387/// Parse a function type.
388///
389/// function-type ::= type-list-parens `->` type-list
390///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700391Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700392 assert(curToken.is(Token::l_paren));
393
Chris Lattnerf7e22732018-06-22 22:03:48 -0700394 SmallVector<Type*, 4> arguments;
395 if (parseTypeList(arguments))
396 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700397
398 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700399 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700400
Chris Lattnerf7e22732018-06-22 22:03:48 -0700401 SmallVector<Type*, 4> results;
402 if (parseTypeList(results))
403 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700404
Chris Lattnerf7e22732018-06-22 22:03:48 -0700405 return FunctionType::get(arguments, results, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700406}
407
408
409/// Parse an arbitrary type.
410///
411/// type ::= primitive-type
412/// | vector-type
413/// | tensor-type
414/// | memref-type
415/// | function-type
416/// element-type ::= primitive-type | vector-type
417///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700418Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700419 switch (curToken.getKind()) {
420 case Token::kw_memref: return parseMemRefType();
421 case Token::kw_tensor: return parseTensorType();
422 case Token::kw_vector: return parseVectorType();
423 case Token::l_paren: return parseFunctionType();
424 default:
425 return parsePrimitiveType();
426 }
427}
428
429/// Parse a "type list", which is a singular type, or a parenthesized list of
430/// types.
431///
432/// type-list ::= type-list-parens | type
433/// type-list-parens ::= `(` `)`
434/// | `(` type (`,` type)* `)`
435///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700436ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
437 auto parseElt = [&]() -> ParseResult {
438 auto elt = parseType();
439 elements.push_back(elt);
440 return elt ? ParseSuccess : ParseFailure;
441 };
442
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700443 // If there is no parens, then it must be a singular type.
444 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700445 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700446
Chris Lattnerf7e22732018-06-22 22:03:48 -0700447 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700448 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700449
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700450 return ParseSuccess;
451}
452
Chris Lattner4c95a502018-06-23 16:03:42 -0700453//===----------------------------------------------------------------------===//
454// Functions
455//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -0700456
Chris Lattnere79379a2018-06-22 10:39:19 -0700457
458/// Parse a function signature, starting with a name and including the parameter
459/// list.
460///
461/// argument-list ::= type (`,` type)* | /*empty*/
462/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
463///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700464ParseResult Parser::parseFunctionSignature(StringRef &name,
465 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700466 if (curToken.isNot(Token::at_identifier))
467 return emitError("expected a function identifier like '@foo'");
468
469 name = curToken.getSpelling().drop_front();
470 consumeToken(Token::at_identifier);
471
472 if (curToken.isNot(Token::l_paren))
473 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -0700474
Chris Lattnerf7e22732018-06-22 22:03:48 -0700475 SmallVector<Type*, 4> arguments;
476 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700477 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -0700478
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700479 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700480 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700481 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700482 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700483 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700484 }
Chris Lattnerf7e22732018-06-22 22:03:48 -0700485 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -0700486 return ParseSuccess;
487}
488
489
490/// External function declarations.
491///
492/// ext-func ::= `extfunc` function-signature
493///
494ParseResult Parser::parseExtFunc() {
495 consumeToken(Token::kw_extfunc);
496
497 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700498 FunctionType *type = nullptr;
499 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -0700500 return ParseFailure;
501
502
503 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -0700504 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -0700505 return ParseSuccess;
506}
507
508
Chris Lattner4c95a502018-06-23 16:03:42 -0700509namespace {
510/// This class represents the transient parser state for the internals of a
511/// function as we are parsing it, e.g. the names for basic blocks. It handles
512/// forward references.
513class CFGFunctionParserState {
514public:
515 CFGFunctionParserState(CFGFunction *function) : function(function) {}
516
517 /// Get the basic block with the specified name, creating it if it doesn't
518 /// already exist.
519 BasicBlock *getBlockNamed(StringRef name) {
520 auto *&block = blocksByName[name];
521 if (!block) {
522 block = new BasicBlock(function);
523 // TODO: Should be automatic when we have the right function
524 // representation.
525 function->blockList.push_back(block);
526 }
527 return block;
528 }
529private:
530 CFGFunction *function;
531 llvm::StringMap<BasicBlock*> blocksByName;
532};
533} // end anonymous namespace
534
535
536/// CFG function declarations.
537///
538/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
539///
540ParseResult Parser::parseCFGFunc() {
541 consumeToken(Token::kw_cfgfunc);
542
543 StringRef name;
544 FunctionType *type = nullptr;
545 if (parseFunctionSignature(name, type))
546 return ParseFailure;
547
548 if (!consumeIf(Token::l_brace))
549 return emitError("expected '{' in CFG function");
550
551 // Okay, the CFG function signature was parsed correctly, create the function.
552 auto function = new CFGFunction(name, type);
553
554 // Make sure we have at least one block.
555 if (curToken.is(Token::r_brace))
556 return emitError("CFG functions must have at least one basic block");
557
558 CFGFunctionParserState functionState(function);
559
560 // Parse the list of blocks.
561 while (!consumeIf(Token::r_brace))
562 if (parseBasicBlock(functionState))
563 return ParseFailure;
564
565 module->functionList.push_back(function);
566 return ParseSuccess;
567}
568
569/// Basic block declaration.
570///
571/// basic-block ::= bb-label instruction* terminator-stmt
572/// bb-label ::= bb-id bb-arg-list? `:`
573/// bb-id ::= bare-id
574/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
575///
576ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
577 SMLoc nameLoc = curToken.getLoc();
578 auto name = curToken.getSpelling();
579 if (!consumeIf(Token::bare_identifier))
580 return emitError("expected basic block name");
581 auto block = functionState.getBlockNamed(name);
582
583 // If this block has already been parsed, then this is a redefinition with the
584 // same block name.
585 if (block->getTerminator())
586 return emitError(nameLoc, "redefinition of block named '" +
587 name.str() + "'");
588
589 // TODO: parse bb argument list.
590
591 if (!consumeIf(Token::colon))
592 return emitError("expected ':' after basic block name");
593
594
595 // TODO(clattner): Verify block hasn't already been parsed (this would be a
596 // redefinition of the same name) once we have a body implementation.
597
598 // TODO(clattner): Move block to the end of the list, once we have a proper
599 // block list representation in CFGFunction.
600
601 // TODO: parse instruction list.
602
603 // TODO: Generalize this once instruction list parsing is built out.
604 if (!consumeIf(Token::kw_return))
605 return emitError("expected 'return' at end of basic block");
606
607 block->setTerminator(new ReturnInst(block));
608
609 return ParseSuccess;
610}
611
612
613//===----------------------------------------------------------------------===//
614// Top-level entity parsing.
615//===----------------------------------------------------------------------===//
616
Chris Lattnere79379a2018-06-22 10:39:19 -0700617/// This is the top-level module parser.
618Module *Parser::parseModule() {
619 while (1) {
620 switch (curToken.getKind()) {
621 default:
622 emitError("expected a top level entity");
623 return nullptr;
624
625 // If we got to the end of the file, then we're done.
626 case Token::eof:
627 return module.release();
628
629 // If we got an error token, then the lexer already emitted an error, just
630 // stop. Someday we could introduce error recovery if there was demand for
631 // it.
632 case Token::error:
633 return nullptr;
634
635 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -0700636 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -0700637 break;
638
Chris Lattner4c95a502018-06-23 16:03:42 -0700639 case Token::kw_cfgfunc:
640 if (parseCFGFunc()) return nullptr;
641 break;
642
643 // TODO: mlfunc, affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -0700644 }
645 }
646}
647
648//===----------------------------------------------------------------------===//
649
650/// This parses the file specified by the indicated SourceMgr and returns an
651/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700652Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context){
653 return Parser(sourceMgr, context).parseModule();
Chris Lattnere79379a2018-06-22 10:39:19 -0700654}