blob: 5a79f1e4bff8574f30fcc25b9d253002090cff7f [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:
Jacques Pienaar9c411be2018-06-24 19:17:35 -070045 Parser(llvm::SourceMgr &sourceMgr, MLIRContext *context,
46 const SMDiagnosticHandlerTy &errorReporter)
47 : context(context),
48 lex(sourceMgr, errorReporter),
49 curToken(lex.lexToken()),
50 errorReporter(errorReporter) {
Chris Lattnere79379a2018-06-22 10:39:19 -070051 module.reset(new Module());
52 }
53
54 Module *parseModule();
55private:
56 // State.
Chris Lattnerf7e22732018-06-22 22:03:48 -070057 MLIRContext *const context;
58
59 // The lexer for the source file we're parsing.
Chris Lattnere79379a2018-06-22 10:39:19 -070060 Lexer lex;
61
62 // This is the next token that hasn't been consumed yet.
63 Token curToken;
64
Jacques Pienaar9c411be2018-06-24 19:17:35 -070065 // The diagnostic error reporter.
66 const SMDiagnosticHandlerTy &errorReporter;
67
Chris Lattnere79379a2018-06-22 10:39:19 -070068 // This is the result module we are parsing into.
69 std::unique_ptr<Module> module;
70
71private:
72 // Helper methods.
73
74 /// Emit an error and return failure.
Chris Lattner4c95a502018-06-23 16:03:42 -070075 ParseResult emitError(const Twine &message) {
76 return emitError(curToken.getLoc(), message);
77 }
78 ParseResult emitError(SMLoc loc, const Twine &message);
Chris Lattnere79379a2018-06-22 10:39:19 -070079
80 /// Advance the current lexer onto the next token.
81 void consumeToken() {
82 assert(curToken.isNot(Token::eof, Token::error) &&
83 "shouldn't advance past EOF or errors");
84 curToken = lex.lexToken();
85 }
86
87 /// Advance the current lexer onto the next token, asserting what the expected
88 /// current token is. This is preferred to the above method because it leads
89 /// to more self-documenting code with better checking.
90 void consumeToken(Token::TokenKind kind) {
91 assert(curToken.is(kind) && "consumed an unexpected token");
92 consumeToken();
93 }
94
Chris Lattnerbb8fafc2018-06-22 15:52:02 -070095 /// If the current token has the specified kind, consume it and return true.
96 /// If not, return false.
97 bool consumeIf(Token::TokenKind kind) {
98 if (curToken.isNot(kind))
99 return false;
100 consumeToken(kind);
101 return true;
102 }
103
104 ParseResult parseCommaSeparatedList(Token::TokenKind rightToken,
105 const std::function<ParseResult()> &parseElement,
106 bool allowEmptyList = true);
107
Chris Lattnerf7e22732018-06-22 22:03:48 -0700108 // We have two forms of parsing methods - those that return a non-null
109 // pointer on success, and those that return a ParseResult to indicate whether
110 // they returned a failure. The second class fills in by-reference arguments
111 // as the results of their action.
112
Chris Lattnere79379a2018-06-22 10:39:19 -0700113 // Type parsing.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700114 PrimitiveType *parsePrimitiveType();
115 Type *parseElementType();
116 VectorType *parseVectorType();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700117 ParseResult parseDimensionListRanked(SmallVectorImpl<int> &dimensions);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700118 Type *parseTensorType();
119 Type *parseMemRefType();
120 Type *parseFunctionType();
121 Type *parseType();
122 ParseResult parseTypeList(SmallVectorImpl<Type*> &elements);
Chris Lattnere79379a2018-06-22 10:39:19 -0700123
Chris Lattner4c95a502018-06-23 16:03:42 -0700124 // Functions.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700125 ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
Chris Lattnere79379a2018-06-22 10:39:19 -0700126 ParseResult parseExtFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700127 ParseResult parseCFGFunc();
128 ParseResult parseBasicBlock(CFGFunctionParserState &functionState);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700129 TerminatorInst *parseTerminator(BasicBlock *currentBB,
130 CFGFunctionParserState &functionState);
131
Chris Lattnere79379a2018-06-22 10:39:19 -0700132};
133} // end anonymous namespace
134
135//===----------------------------------------------------------------------===//
136// Helper methods.
137//===----------------------------------------------------------------------===//
138
Chris Lattner4c95a502018-06-23 16:03:42 -0700139ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700140 // If we hit a parse error in response to a lexer error, then the lexer
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700141 // already reported the error.
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700142 if (curToken.is(Token::error))
143 return ParseFailure;
144
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700145 errorReporter(
146 lex.getSourceMgr().GetMessage(loc, SourceMgr::DK_Error, message));
Chris Lattnere79379a2018-06-22 10:39:19 -0700147 return ParseFailure;
148}
149
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700150/// Parse a comma-separated list of elements, terminated with an arbitrary
151/// token. This allows empty lists if allowEmptyList is true.
152///
153/// abstract-list ::= rightToken // if allowEmptyList == true
154/// abstract-list ::= element (',' element)* rightToken
155///
156ParseResult Parser::
157parseCommaSeparatedList(Token::TokenKind rightToken,
158 const std::function<ParseResult()> &parseElement,
159 bool allowEmptyList) {
160 // Handle the empty case.
161 if (curToken.is(rightToken)) {
162 if (!allowEmptyList)
163 return emitError("expected list element");
164 consumeToken(rightToken);
165 return ParseSuccess;
166 }
167
168 // Non-empty case starts with an element.
169 if (parseElement())
170 return ParseFailure;
171
172 // Otherwise we have a list of comma separated elements.
173 while (consumeIf(Token::comma)) {
174 if (parseElement())
175 return ParseFailure;
176 }
177
178 // Consume the end character.
179 if (!consumeIf(rightToken))
180 return emitError("expected ',' or ')'");
181
182 return ParseSuccess;
183}
Chris Lattnere79379a2018-06-22 10:39:19 -0700184
185//===----------------------------------------------------------------------===//
186// Type Parsing
187//===----------------------------------------------------------------------===//
188
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700189/// Parse the low-level fixed dtypes in the system.
190///
191/// primitive-type
192/// ::= `f16` | `bf16` | `f32` | `f64` // Floating point
193/// | `i1` | `i8` | `i16` | `i32` | `i64` // Sized integers
194/// | `int`
195///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700196PrimitiveType *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700197 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700198 default:
199 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700200 case Token::kw_bf16:
201 consumeToken(Token::kw_bf16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700202 return Type::getBF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700203 case Token::kw_f16:
204 consumeToken(Token::kw_f16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700205 return Type::getF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700206 case Token::kw_f32:
207 consumeToken(Token::kw_f32);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700208 return Type::getF32(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700209 case Token::kw_f64:
210 consumeToken(Token::kw_f64);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700211 return Type::getF64(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700212 case Token::kw_i1:
213 consumeToken(Token::kw_i1);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700214 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700215 case Token::kw_i8:
216 consumeToken(Token::kw_i8);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700217 return Type::getI8(context);
218 case Token::kw_i16:
219 consumeToken(Token::kw_i16);
220 return Type::getI16(context);
221 case Token::kw_i32:
222 consumeToken(Token::kw_i32);
223 return Type::getI32(context);
224 case Token::kw_i64:
225 consumeToken(Token::kw_i64);
226 return Type::getI64(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700227 case Token::kw_int:
228 consumeToken(Token::kw_int);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700229 return Type::getInt(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700230 }
231}
232
233/// Parse the element type of a tensor or memref type.
234///
235/// element-type ::= primitive-type | vector-type
236///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700237Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700238 if (curToken.is(Token::kw_vector))
239 return parseVectorType();
240
241 return parsePrimitiveType();
242}
243
244/// Parse a vector type.
245///
246/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
247/// const-dimension-list ::= (integer-literal `x`)+
248///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700249VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700250 consumeToken(Token::kw_vector);
251
252 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700253 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700254
255 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700256 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700257
258 SmallVector<unsigned, 4> dimensions;
259 while (curToken.is(Token::integer)) {
260 // Make sure this integer value is in bound and valid.
261 auto dimension = curToken.getUnsignedIntegerValue();
262 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700263 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700264 dimensions.push_back(dimension.getValue());
265
266 consumeToken(Token::integer);
267
268 // Make sure we have an 'x' or something like 'xbf32'.
269 if (curToken.isNot(Token::bare_identifier) ||
270 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700271 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700272
273 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
274 if (curToken.getSpelling().size() != 1)
275 lex.resetPointer(curToken.getSpelling().data()+1);
276
277 // Consume the 'x'.
278 consumeToken(Token::bare_identifier);
279 }
280
281 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700282 auto *elementType = parsePrimitiveType();
283 if (!elementType)
284 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700285
286 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700287 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700288
Chris Lattnerf7e22732018-06-22 22:03:48 -0700289 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700290}
291
292/// Parse a dimension list of a tensor or memref type. This populates the
293/// dimension list, returning -1 for the '?' dimensions.
294///
295/// dimension-list-ranked ::= (dimension `x`)*
296/// dimension ::= `?` | integer-literal
297///
298ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
299 while (curToken.isAny(Token::integer, Token::question)) {
300 if (consumeIf(Token::question)) {
301 dimensions.push_back(-1);
302 } else {
303 // Make sure this integer value is in bound and valid.
304 auto dimension = curToken.getUnsignedIntegerValue();
305 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
306 return emitError("invalid dimension");
307 dimensions.push_back((int)dimension.getValue());
308 consumeToken(Token::integer);
309 }
310
311 // Make sure we have an 'x' or something like 'xbf32'.
312 if (curToken.isNot(Token::bare_identifier) ||
313 curToken.getSpelling()[0] != 'x')
314 return emitError("expected 'x' in dimension list");
315
316 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
317 if (curToken.getSpelling().size() != 1)
318 lex.resetPointer(curToken.getSpelling().data()+1);
319
320 // Consume the 'x'.
321 consumeToken(Token::bare_identifier);
322 }
323
324 return ParseSuccess;
325}
326
327/// Parse a tensor type.
328///
329/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
330/// dimension-list ::= dimension-list-ranked | `??`
331///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700332Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700333 consumeToken(Token::kw_tensor);
334
335 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700336 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700337
338 bool isUnranked;
339 SmallVector<int, 4> dimensions;
340
341 if (consumeIf(Token::questionquestion)) {
342 isUnranked = true;
343 } else {
344 isUnranked = false;
345 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700346 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700347 }
348
349 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700350 auto elementType = parseElementType();
351 if (!elementType)
352 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700353
354 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700355 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700356
MLIR Team355ec862018-06-23 18:09:09 -0700357 if (isUnranked)
358 return UnrankedTensorType::get(elementType);
359 return RankedTensorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700360}
361
362/// Parse a memref type.
363///
364/// memref-type ::= `memref` `<` dimension-list-ranked element-type
365/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
366///
367/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
368/// memory-space ::= integer-literal /* | TODO: address-space-id */
369///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700370Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700371 consumeToken(Token::kw_memref);
372
373 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700374 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700375
376 SmallVector<int, 4> dimensions;
377 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700378 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700379
380 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700381 auto elementType = parseElementType();
382 if (!elementType)
383 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700384
385 // TODO: Parse semi-affine-map-composition.
386 // TODO: Parse memory-space.
387
388 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700389 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700390
Chris Lattnerf7e22732018-06-22 22:03:48 -0700391 // FIXME: Add an IR representation for memref types.
392 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700393}
394
395
396
397/// Parse a function type.
398///
399/// function-type ::= type-list-parens `->` type-list
400///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700401Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700402 assert(curToken.is(Token::l_paren));
403
Chris Lattnerf7e22732018-06-22 22:03:48 -0700404 SmallVector<Type*, 4> arguments;
405 if (parseTypeList(arguments))
406 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700407
408 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700409 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700410
Chris Lattnerf7e22732018-06-22 22:03:48 -0700411 SmallVector<Type*, 4> results;
412 if (parseTypeList(results))
413 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700414
Chris Lattnerf7e22732018-06-22 22:03:48 -0700415 return FunctionType::get(arguments, results, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700416}
417
418
419/// Parse an arbitrary type.
420///
421/// type ::= primitive-type
422/// | vector-type
423/// | tensor-type
424/// | memref-type
425/// | function-type
426/// element-type ::= primitive-type | vector-type
427///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700428Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700429 switch (curToken.getKind()) {
430 case Token::kw_memref: return parseMemRefType();
431 case Token::kw_tensor: return parseTensorType();
432 case Token::kw_vector: return parseVectorType();
433 case Token::l_paren: return parseFunctionType();
434 default:
435 return parsePrimitiveType();
436 }
437}
438
439/// Parse a "type list", which is a singular type, or a parenthesized list of
440/// types.
441///
442/// type-list ::= type-list-parens | type
443/// type-list-parens ::= `(` `)`
444/// | `(` type (`,` type)* `)`
445///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700446ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
447 auto parseElt = [&]() -> ParseResult {
448 auto elt = parseType();
449 elements.push_back(elt);
450 return elt ? ParseSuccess : ParseFailure;
451 };
452
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700453 // If there is no parens, then it must be a singular type.
454 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700455 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700456
Chris Lattnerf7e22732018-06-22 22:03:48 -0700457 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700458 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700459
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700460 return ParseSuccess;
461}
462
Chris Lattner4c95a502018-06-23 16:03:42 -0700463//===----------------------------------------------------------------------===//
464// Functions
465//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -0700466
Chris Lattnere79379a2018-06-22 10:39:19 -0700467
468/// Parse a function signature, starting with a name and including the parameter
469/// list.
470///
471/// argument-list ::= type (`,` type)* | /*empty*/
472/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
473///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700474ParseResult Parser::parseFunctionSignature(StringRef &name,
475 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700476 if (curToken.isNot(Token::at_identifier))
477 return emitError("expected a function identifier like '@foo'");
478
479 name = curToken.getSpelling().drop_front();
480 consumeToken(Token::at_identifier);
481
482 if (curToken.isNot(Token::l_paren))
483 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -0700484
Chris Lattnerf7e22732018-06-22 22:03:48 -0700485 SmallVector<Type*, 4> arguments;
486 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700487 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -0700488
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700489 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700490 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700491 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700492 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700493 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700494 }
Chris Lattnerf7e22732018-06-22 22:03:48 -0700495 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -0700496 return ParseSuccess;
497}
498
499
500/// External function declarations.
501///
502/// ext-func ::= `extfunc` function-signature
503///
504ParseResult Parser::parseExtFunc() {
505 consumeToken(Token::kw_extfunc);
506
507 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700508 FunctionType *type = nullptr;
509 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -0700510 return ParseFailure;
511
512
513 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -0700514 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -0700515 return ParseSuccess;
516}
517
518
Chris Lattner4c95a502018-06-23 16:03:42 -0700519namespace {
520/// This class represents the transient parser state for the internals of a
521/// function as we are parsing it, e.g. the names for basic blocks. It handles
522/// forward references.
523class CFGFunctionParserState {
524public:
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700525 CFGFunction *function;
526 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
527
Chris Lattner4c95a502018-06-23 16:03:42 -0700528 CFGFunctionParserState(CFGFunction *function) : function(function) {}
529
530 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700531 /// already exist. The location specified is the point of use, which allows
532 /// us to diagnose references to blocks that are not defined precisely.
533 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
534 auto &blockAndLoc = blocksByName[name];
535 if (!blockAndLoc.first) {
536 blockAndLoc.first = new BasicBlock(function);
537 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -0700538 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700539 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -0700540 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700541};
542} // end anonymous namespace
543
544
545/// CFG function declarations.
546///
547/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
548///
549ParseResult Parser::parseCFGFunc() {
550 consumeToken(Token::kw_cfgfunc);
551
552 StringRef name;
553 FunctionType *type = nullptr;
554 if (parseFunctionSignature(name, type))
555 return ParseFailure;
556
557 if (!consumeIf(Token::l_brace))
558 return emitError("expected '{' in CFG function");
559
560 // Okay, the CFG function signature was parsed correctly, create the function.
561 auto function = new CFGFunction(name, type);
562
563 // Make sure we have at least one block.
564 if (curToken.is(Token::r_brace))
565 return emitError("CFG functions must have at least one basic block");
566
567 CFGFunctionParserState functionState(function);
568
569 // Parse the list of blocks.
570 while (!consumeIf(Token::r_brace))
571 if (parseBasicBlock(functionState))
572 return ParseFailure;
573
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700574 // Verify that all referenced blocks were defined. Iteration over a
575 // StringMap isn't determinstic, but this is good enough for our purposes.
576 for (auto &elt : functionState.blocksByName) {
577 auto *bb = elt.second.first;
578 if (!bb->getTerminator())
579 return emitError(elt.second.second,
580 "reference to an undefined basic block '" +
581 elt.first() + "'");
582 }
583
Chris Lattner4c95a502018-06-23 16:03:42 -0700584 module->functionList.push_back(function);
585 return ParseSuccess;
586}
587
588/// Basic block declaration.
589///
590/// basic-block ::= bb-label instruction* terminator-stmt
591/// bb-label ::= bb-id bb-arg-list? `:`
592/// bb-id ::= bare-id
593/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
594///
595ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
596 SMLoc nameLoc = curToken.getLoc();
597 auto name = curToken.getSpelling();
598 if (!consumeIf(Token::bare_identifier))
599 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700600
601 auto block = functionState.getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -0700602
603 // If this block has already been parsed, then this is a redefinition with the
604 // same block name.
605 if (block->getTerminator())
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700606 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
607
608 // References to blocks can occur in any order, but we need to reassemble the
609 // function in the order that occurs in the source file. Do this by moving
610 // each block to the end of the list as it is defined.
611 // FIXME: This is inefficient for large functions given that blockList is a
612 // vector. blockList will eventually be an ilist, which will make this fast.
613 auto &blockList = functionState.function->blockList;
614 if (blockList.back() != block) {
615 auto it = std::find(blockList.begin(), blockList.end(), block);
616 assert(it != blockList.end() && "Block has to be in the blockList");
617 std::swap(*it, blockList.back());
618 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700619
620 // TODO: parse bb argument list.
621
622 if (!consumeIf(Token::colon))
623 return emitError("expected ':' after basic block name");
624
625
626 // TODO(clattner): Verify block hasn't already been parsed (this would be a
627 // redefinition of the same name) once we have a body implementation.
628
629 // TODO(clattner): Move block to the end of the list, once we have a proper
630 // block list representation in CFGFunction.
631
632 // TODO: parse instruction list.
633
634 // TODO: Generalize this once instruction list parsing is built out.
Chris Lattner4c95a502018-06-23 16:03:42 -0700635
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700636 auto *termInst = parseTerminator(block, functionState);
637 if (!termInst)
638 return ParseFailure;
639 block->setTerminator(termInst);
Chris Lattner4c95a502018-06-23 16:03:42 -0700640
641 return ParseSuccess;
642}
643
644
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700645/// Parse the terminator instruction for a basic block.
646///
647/// terminator-stmt ::= `br` bb-id branch-use-list?
648/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
649/// terminator-stmt ::=
650/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
651/// terminator-stmt ::= `return` ssa-use-and-type-list?
652///
653TerminatorInst *Parser::parseTerminator(BasicBlock *currentBB,
654 CFGFunctionParserState &functionState) {
655 switch (curToken.getKind()) {
656 default:
657 return (emitError("expected terminator at end of basic block"), nullptr);
658
659 case Token::kw_return:
660 consumeToken(Token::kw_return);
661 return new ReturnInst(currentBB);
662
663 case Token::kw_br: {
664 consumeToken(Token::kw_br);
665 auto destBB = functionState.getBlockNamed(curToken.getSpelling(),
666 curToken.getLoc());
667 if (!consumeIf(Token::bare_identifier))
668 return (emitError("expected basic block name"), nullptr);
669 return new BranchInst(destBB, currentBB);
670 }
671 }
672}
673
674
Chris Lattner4c95a502018-06-23 16:03:42 -0700675//===----------------------------------------------------------------------===//
676// Top-level entity parsing.
677//===----------------------------------------------------------------------===//
678
Chris Lattnere79379a2018-06-22 10:39:19 -0700679/// This is the top-level module parser.
680Module *Parser::parseModule() {
681 while (1) {
682 switch (curToken.getKind()) {
683 default:
684 emitError("expected a top level entity");
685 return nullptr;
686
687 // If we got to the end of the file, then we're done.
688 case Token::eof:
689 return module.release();
690
691 // If we got an error token, then the lexer already emitted an error, just
692 // stop. Someday we could introduce error recovery if there was demand for
693 // it.
694 case Token::error:
695 return nullptr;
696
697 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -0700698 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -0700699 break;
700
Chris Lattner4c95a502018-06-23 16:03:42 -0700701 case Token::kw_cfgfunc:
702 if (parseCFGFunc()) return nullptr;
703 break;
704
705 // TODO: mlfunc, affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -0700706 }
707 }
708}
709
710//===----------------------------------------------------------------------===//
711
712/// This parses the file specified by the indicated SourceMgr and returns an
713/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700714Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context,
715 const SMDiagnosticHandlerTy &errorReporter) {
716 return Parser(sourceMgr, context, errorReporter).parseModule();
Chris Lattnere79379a2018-06-22 10:39:19 -0700717}