blob: 692705018aa896deba0b325f579a986948c14aad [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//===----------------------------------------------------------------------===//
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070021#include <stack>
Chris Lattnere79379a2018-06-22 10:39:19 -070022
23#include "mlir/Parser.h"
24#include "Lexer.h"
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070025#include "mlir/IR/AffineExpr.h"
MLIR Teamf85a6262018-06-27 11:03:08 -070026#include "mlir/IR/AffineMap.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070027#include "mlir/IR/CFGFunction.h"
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070028#include "mlir/IR/Module.h"
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -070029#include "mlir/IR/MLFunction.h"
Chris Lattnerf7e22732018-06-22 22:03:48 -070030#include "mlir/IR/Types.h"
Chris Lattnere79379a2018-06-22 10:39:19 -070031#include "llvm/Support/SourceMgr.h"
32using namespace mlir;
33using llvm::SourceMgr;
Chris Lattner4c95a502018-06-23 16:03:42 -070034using llvm::SMLoc;
Chris Lattnere79379a2018-06-22 10:39:19 -070035
36namespace {
Chris Lattner4c95a502018-06-23 16:03:42 -070037class CFGFunctionParserState;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070038class AffineMapParserState;
Chris Lattner4c95a502018-06-23 16:03:42 -070039
Chris Lattnerf7e22732018-06-22 22:03:48 -070040/// Simple enum to make code read better in cases that would otherwise return a
41/// bool value. Failure is "true" in a boolean context.
Chris Lattnere79379a2018-06-22 10:39:19 -070042enum ParseResult {
43 ParseSuccess,
44 ParseFailure
45};
46
47/// Main parser implementation.
48class Parser {
Chris Lattnered65a732018-06-28 20:45:33 -070049public:
Jacques Pienaar9c411be2018-06-24 19:17:35 -070050 Parser(llvm::SourceMgr &sourceMgr, MLIRContext *context,
51 const SMDiagnosticHandlerTy &errorReporter)
52 : context(context),
53 lex(sourceMgr, errorReporter),
54 curToken(lex.lexToken()),
55 errorReporter(errorReporter) {
Chris Lattnere79379a2018-06-22 10:39:19 -070056 module.reset(new Module());
57 }
58
59 Module *parseModule();
60private:
61 // State.
Chris Lattnerf7e22732018-06-22 22:03:48 -070062 MLIRContext *const context;
63
64 // The lexer for the source file we're parsing.
Chris Lattnere79379a2018-06-22 10:39:19 -070065 Lexer lex;
66
67 // This is the next token that hasn't been consumed yet.
68 Token curToken;
69
Jacques Pienaar9c411be2018-06-24 19:17:35 -070070 // The diagnostic error reporter.
71 const SMDiagnosticHandlerTy &errorReporter;
72
Chris Lattnere79379a2018-06-22 10:39:19 -070073 // This is the result module we are parsing into.
74 std::unique_ptr<Module> module;
75
MLIR Teamf85a6262018-06-27 11:03:08 -070076 // A map from affine map identifier to AffineMap.
77 // TODO(andydavis) Remove use of unique_ptr when AffineMaps are bump pointer
78 // allocated.
79 llvm::StringMap<std::unique_ptr<AffineMap>> affineMaps;
80
Chris Lattnere79379a2018-06-22 10:39:19 -070081private:
82 // Helper methods.
83
84 /// Emit an error and return failure.
Chris Lattner4c95a502018-06-23 16:03:42 -070085 ParseResult emitError(const Twine &message) {
86 return emitError(curToken.getLoc(), message);
87 }
88 ParseResult emitError(SMLoc loc, const Twine &message);
Chris Lattnere79379a2018-06-22 10:39:19 -070089
90 /// Advance the current lexer onto the next token.
91 void consumeToken() {
92 assert(curToken.isNot(Token::eof, Token::error) &&
93 "shouldn't advance past EOF or errors");
94 curToken = lex.lexToken();
95 }
96
97 /// Advance the current lexer onto the next token, asserting what the expected
98 /// current token is. This is preferred to the above method because it leads
99 /// to more self-documenting code with better checking.
Chris Lattner8da0c282018-06-29 11:15:56 -0700100 void consumeToken(Token::Kind kind) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700101 assert(curToken.is(kind) && "consumed an unexpected token");
102 consumeToken();
103 }
104
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700105 /// If the current token has the specified kind, consume it and return true.
106 /// If not, return false.
Chris Lattner8da0c282018-06-29 11:15:56 -0700107 bool consumeIf(Token::Kind kind) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700108 if (curToken.isNot(kind))
109 return false;
110 consumeToken(kind);
111 return true;
112 }
113
Chris Lattner8da0c282018-06-29 11:15:56 -0700114 ParseResult parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700115 const std::function<ParseResult()> &parseElement,
116 bool allowEmptyList = true);
117
Chris Lattnerf7e22732018-06-22 22:03:48 -0700118 // We have two forms of parsing methods - those that return a non-null
119 // pointer on success, and those that return a ParseResult to indicate whether
120 // they returned a failure. The second class fills in by-reference arguments
121 // as the results of their action.
122
Chris Lattnere79379a2018-06-22 10:39:19 -0700123 // Type parsing.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700124 PrimitiveType *parsePrimitiveType();
125 Type *parseElementType();
126 VectorType *parseVectorType();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700127 ParseResult parseDimensionListRanked(SmallVectorImpl<int> &dimensions);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700128 Type *parseTensorType();
129 Type *parseMemRefType();
130 Type *parseFunctionType();
131 Type *parseType();
132 ParseResult parseTypeList(SmallVectorImpl<Type*> &elements);
Chris Lattnere79379a2018-06-22 10:39:19 -0700133
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700134 // Identifiers
135 ParseResult parseDimIdList(SmallVectorImpl<StringRef> &dims,
136 SmallVectorImpl<StringRef> &symbols);
137 ParseResult parseSymbolIdList(SmallVectorImpl<StringRef> &dims,
138 SmallVectorImpl<StringRef> &symbols);
139 StringRef parseDimOrSymbolId(SmallVectorImpl<StringRef> &dims,
140 SmallVectorImpl<StringRef> &symbols,
141 bool symbol);
142
MLIR Teamf85a6262018-06-27 11:03:08 -0700143 // Polyhedral structures
144 ParseResult parseAffineMapDef();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700145 AffineMap *parseAffineMapInline(StringRef mapId);
146 AffineExpr *parseAffineExpr(AffineMapParserState &state);
MLIR Teamf85a6262018-06-27 11:03:08 -0700147
Chris Lattner4c95a502018-06-23 16:03:42 -0700148 // Functions.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700149 ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
Chris Lattnere79379a2018-06-22 10:39:19 -0700150 ParseResult parseExtFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700151 ParseResult parseCFGFunc();
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700152 ParseResult parseMLFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700153 ParseResult parseBasicBlock(CFGFunctionParserState &functionState);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700154 MLStatement *parseMLStatement(MLFunction *currentFunction);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700155
Chris Lattnered65a732018-06-28 20:45:33 -0700156 ParseResult parseCFGOperation(BasicBlock *currentBB,
157 CFGFunctionParserState &functionState);
158 ParseResult parseTerminator(BasicBlock *currentBB,
159 CFGFunctionParserState &functionState);
160
Chris Lattnere79379a2018-06-22 10:39:19 -0700161};
162} // end anonymous namespace
163
164//===----------------------------------------------------------------------===//
165// Helper methods.
166//===----------------------------------------------------------------------===//
167
Chris Lattner4c95a502018-06-23 16:03:42 -0700168ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700169 // If we hit a parse error in response to a lexer error, then the lexer
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700170 // already reported the error.
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700171 if (curToken.is(Token::error))
172 return ParseFailure;
173
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700174 errorReporter(
175 lex.getSourceMgr().GetMessage(loc, SourceMgr::DK_Error, message));
Chris Lattnere79379a2018-06-22 10:39:19 -0700176 return ParseFailure;
177}
178
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700179/// Parse a comma-separated list of elements, terminated with an arbitrary
180/// token. This allows empty lists if allowEmptyList is true.
181///
182/// abstract-list ::= rightToken // if allowEmptyList == true
183/// abstract-list ::= element (',' element)* rightToken
184///
185ParseResult Parser::
Chris Lattner8da0c282018-06-29 11:15:56 -0700186parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700187 const std::function<ParseResult()> &parseElement,
188 bool allowEmptyList) {
189 // Handle the empty case.
190 if (curToken.is(rightToken)) {
191 if (!allowEmptyList)
192 return emitError("expected list element");
193 consumeToken(rightToken);
194 return ParseSuccess;
195 }
196
197 // Non-empty case starts with an element.
198 if (parseElement())
199 return ParseFailure;
200
201 // Otherwise we have a list of comma separated elements.
202 while (consumeIf(Token::comma)) {
203 if (parseElement())
204 return ParseFailure;
205 }
206
207 // Consume the end character.
208 if (!consumeIf(rightToken))
Chris Lattner8da0c282018-06-29 11:15:56 -0700209 return emitError("expected ',' or '" + Token::getTokenSpelling(rightToken) +
210 "'");
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700211
212 return ParseSuccess;
213}
Chris Lattnere79379a2018-06-22 10:39:19 -0700214
215//===----------------------------------------------------------------------===//
216// Type Parsing
217//===----------------------------------------------------------------------===//
218
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700219/// Parse the low-level fixed dtypes in the system.
220///
221/// primitive-type
222/// ::= `f16` | `bf16` | `f32` | `f64` // Floating point
223/// | `i1` | `i8` | `i16` | `i32` | `i64` // Sized integers
224/// | `int`
225///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700226PrimitiveType *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700227 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700228 default:
229 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700230 case Token::kw_bf16:
231 consumeToken(Token::kw_bf16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700232 return Type::getBF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700233 case Token::kw_f16:
234 consumeToken(Token::kw_f16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700235 return Type::getF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700236 case Token::kw_f32:
237 consumeToken(Token::kw_f32);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700238 return Type::getF32(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700239 case Token::kw_f64:
240 consumeToken(Token::kw_f64);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700241 return Type::getF64(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700242 case Token::kw_i1:
243 consumeToken(Token::kw_i1);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700244 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700245 case Token::kw_i8:
246 consumeToken(Token::kw_i8);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700247 return Type::getI8(context);
248 case Token::kw_i16:
249 consumeToken(Token::kw_i16);
250 return Type::getI16(context);
251 case Token::kw_i32:
252 consumeToken(Token::kw_i32);
253 return Type::getI32(context);
254 case Token::kw_i64:
255 consumeToken(Token::kw_i64);
256 return Type::getI64(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700257 case Token::kw_int:
258 consumeToken(Token::kw_int);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700259 return Type::getInt(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700260 }
261}
262
263/// Parse the element type of a tensor or memref type.
264///
265/// element-type ::= primitive-type | vector-type
266///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700267Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700268 if (curToken.is(Token::kw_vector))
269 return parseVectorType();
270
271 return parsePrimitiveType();
272}
273
274/// Parse a vector type.
275///
276/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
277/// const-dimension-list ::= (integer-literal `x`)+
278///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700279VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700280 consumeToken(Token::kw_vector);
281
282 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700283 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700284
285 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700286 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700287
288 SmallVector<unsigned, 4> dimensions;
289 while (curToken.is(Token::integer)) {
290 // Make sure this integer value is in bound and valid.
291 auto dimension = curToken.getUnsignedIntegerValue();
292 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700293 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700294 dimensions.push_back(dimension.getValue());
295
296 consumeToken(Token::integer);
297
298 // Make sure we have an 'x' or something like 'xbf32'.
299 if (curToken.isNot(Token::bare_identifier) ||
300 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700301 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700302
303 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
304 if (curToken.getSpelling().size() != 1)
305 lex.resetPointer(curToken.getSpelling().data()+1);
306
307 // Consume the 'x'.
308 consumeToken(Token::bare_identifier);
309 }
310
311 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700312 auto *elementType = parsePrimitiveType();
313 if (!elementType)
314 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700315
316 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700317 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700318
Chris Lattnerf7e22732018-06-22 22:03:48 -0700319 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700320}
321
322/// Parse a dimension list of a tensor or memref type. This populates the
323/// dimension list, returning -1 for the '?' dimensions.
324///
325/// dimension-list-ranked ::= (dimension `x`)*
326/// dimension ::= `?` | integer-literal
327///
328ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
329 while (curToken.isAny(Token::integer, Token::question)) {
330 if (consumeIf(Token::question)) {
331 dimensions.push_back(-1);
332 } else {
333 // Make sure this integer value is in bound and valid.
334 auto dimension = curToken.getUnsignedIntegerValue();
335 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
336 return emitError("invalid dimension");
337 dimensions.push_back((int)dimension.getValue());
338 consumeToken(Token::integer);
339 }
340
341 // Make sure we have an 'x' or something like 'xbf32'.
342 if (curToken.isNot(Token::bare_identifier) ||
343 curToken.getSpelling()[0] != 'x')
344 return emitError("expected 'x' in dimension list");
345
346 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
347 if (curToken.getSpelling().size() != 1)
348 lex.resetPointer(curToken.getSpelling().data()+1);
349
350 // Consume the 'x'.
351 consumeToken(Token::bare_identifier);
352 }
353
354 return ParseSuccess;
355}
356
357/// Parse a tensor type.
358///
359/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
360/// dimension-list ::= dimension-list-ranked | `??`
361///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700362Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700363 consumeToken(Token::kw_tensor);
364
365 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700366 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700367
368 bool isUnranked;
369 SmallVector<int, 4> dimensions;
370
371 if (consumeIf(Token::questionquestion)) {
372 isUnranked = true;
373 } else {
374 isUnranked = false;
375 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700376 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700377 }
378
379 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700380 auto elementType = parseElementType();
381 if (!elementType)
382 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700383
384 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700385 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700386
MLIR Team355ec862018-06-23 18:09:09 -0700387 if (isUnranked)
388 return UnrankedTensorType::get(elementType);
389 return RankedTensorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700390}
391
392/// Parse a memref type.
393///
394/// memref-type ::= `memref` `<` dimension-list-ranked element-type
395/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
396///
397/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
398/// memory-space ::= integer-literal /* | TODO: address-space-id */
399///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700400Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700401 consumeToken(Token::kw_memref);
402
403 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700404 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700405
406 SmallVector<int, 4> dimensions;
407 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700408 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700409
410 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700411 auto elementType = parseElementType();
412 if (!elementType)
413 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700414
415 // TODO: Parse semi-affine-map-composition.
416 // TODO: Parse memory-space.
417
418 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700419 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700420
Chris Lattnerf7e22732018-06-22 22:03:48 -0700421 // FIXME: Add an IR representation for memref types.
422 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700423}
424
425
426
427/// Parse a function type.
428///
429/// function-type ::= type-list-parens `->` type-list
430///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700431Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700432 assert(curToken.is(Token::l_paren));
433
Chris Lattnerf7e22732018-06-22 22:03:48 -0700434 SmallVector<Type*, 4> arguments;
435 if (parseTypeList(arguments))
436 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700437
438 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700439 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700440
Chris Lattnerf7e22732018-06-22 22:03:48 -0700441 SmallVector<Type*, 4> results;
442 if (parseTypeList(results))
443 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700444
Chris Lattnerf7e22732018-06-22 22:03:48 -0700445 return FunctionType::get(arguments, results, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700446}
447
448
449/// Parse an arbitrary type.
450///
451/// type ::= primitive-type
452/// | vector-type
453/// | tensor-type
454/// | memref-type
455/// | function-type
456/// element-type ::= primitive-type | vector-type
457///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700458Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700459 switch (curToken.getKind()) {
460 case Token::kw_memref: return parseMemRefType();
461 case Token::kw_tensor: return parseTensorType();
462 case Token::kw_vector: return parseVectorType();
463 case Token::l_paren: return parseFunctionType();
464 default:
465 return parsePrimitiveType();
466 }
467}
468
469/// Parse a "type list", which is a singular type, or a parenthesized list of
470/// types.
471///
472/// type-list ::= type-list-parens | type
473/// type-list-parens ::= `(` `)`
474/// | `(` type (`,` type)* `)`
475///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700476ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
477 auto parseElt = [&]() -> ParseResult {
478 auto elt = parseType();
479 elements.push_back(elt);
480 return elt ? ParseSuccess : ParseFailure;
481 };
482
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700483 // If there is no parens, then it must be a singular type.
484 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700485 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700486
Chris Lattnerf7e22732018-06-22 22:03:48 -0700487 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700488 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700489
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700490 return ParseSuccess;
491}
492
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700493namespace {
494/// This class represents the transient parser state while parsing an affine
495/// expression.
496class AffineMapParserState {
497 public:
498 explicit AffineMapParserState(ArrayRef<StringRef> dims,
499 ArrayRef<StringRef> symbols) :
500 dims_(dims), symbols_(symbols) {}
501
502 unsigned dimCount() const { return dims_.size(); }
503 unsigned symbolCount() const { return symbols_.size(); }
504
505 // Stack operations for affine expression parsing
506 // TODO(bondhugula): all of this will be improved/made more principled
507 void pushAffineExpr(AffineExpr *expr) { exprStack.push(expr); }
508 AffineExpr *popAffineExpr() {
509 auto *t = exprStack.top();
510 exprStack.pop();
511 return t;
512 }
513 AffineExpr *topAffineExpr() { return exprStack.top(); }
514
515 ArrayRef<StringRef> getDims() const { return dims_; }
516 ArrayRef<StringRef> getSymbols() const { return symbols_; }
517
518 private:
519 const ArrayRef<StringRef> dims_;
520 const ArrayRef<StringRef> symbols_;
521
522 // TEMP: stack to hold affine expressions
523 std::stack<AffineExpr *> exprStack;
524};
525} // end anonymous namespace
526
Chris Lattner4c95a502018-06-23 16:03:42 -0700527//===----------------------------------------------------------------------===//
MLIR Teamf85a6262018-06-27 11:03:08 -0700528// Polyhedral structures.
529//===----------------------------------------------------------------------===//
530
531/// Affine map declaration.
532///
533/// affine-map-def ::= affine-map-id `=` affine-map-inline
MLIR Teamf85a6262018-06-27 11:03:08 -0700534///
535ParseResult Parser::parseAffineMapDef() {
Chris Lattner8da0c282018-06-29 11:15:56 -0700536 assert(curToken.is(Token::affine_map_identifier));
MLIR Teamf85a6262018-06-27 11:03:08 -0700537
538 StringRef affineMapId = curToken.getSpelling().drop_front();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700539 consumeToken(Token::affine_map_identifier);
540
MLIR Teamf85a6262018-06-27 11:03:08 -0700541 // Check that 'affineMapId' is unique.
542 // TODO(andydavis) Add a unit test for this case.
543 if (affineMaps.count(affineMapId) > 0)
Chris Lattnered65a732018-06-28 20:45:33 -0700544 return emitError("redefinition of affine map id '" + affineMapId + "'");
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700545 // Parse the '='
546 if (!consumeIf(Token::equal))
547 return emitError("expected '=' in affine map outlined definition");
MLIR Teamf85a6262018-06-27 11:03:08 -0700548
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700549 auto *affineMap = parseAffineMapInline(affineMapId);
550 affineMaps[affineMapId].reset(affineMap);
551 if (!affineMap) return ParseFailure;
MLIR Teamf85a6262018-06-27 11:03:08 -0700552
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700553 module->affineMapList.push_back(affineMap);
554 return affineMap ? ParseSuccess : ParseFailure;
555}
556
557///
558/// Parse a multi-dimensional affine expression
559/// affine-expr ::= `(` affine-expr `)`
560/// | affine-expr `+` affine-expr
561/// | affine-expr `-` affine-expr
562/// | `-`? integer-literal `*` affine-expr
563/// | `ceildiv` `(` affine-expr `,` integer-literal `)`
564/// | `floordiv` `(` affine-expr `,` integer-literal `)`
565/// | affine-expr `mod` integer-literal
566/// | bare-id
567/// | `-`? integer-literal
568/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
569///
570/// Use 'state' to check if valid identifiers appear.
571///
572AffineExpr *Parser::parseAffineExpr(AffineMapParserState &state) {
573 // TODO(bondhugula): complete support for this
574 // The code below is all placeholder / it is wrong / not complete
575 // Operator precedence not considered; pure left to right associativity
576 if (curToken.is(Token::comma)) {
577 emitError("expecting affine expression");
578 return nullptr;
579 }
580
581 while (curToken.isNot(Token::comma, Token::r_paren,
582 Token::eof, Token::error)) {
583 switch (curToken.getKind()) {
584 case Token::bare_identifier: {
585 // TODO(bondhugula): look up state to see if it's a symbol or dim_id and
586 // get its position
587 AffineExpr *expr = AffineDimExpr::get(0, context);
588 state.pushAffineExpr(expr);
589 consumeToken(Token::bare_identifier);
590 break;
591 }
592 case Token::plus: {
593 consumeToken(Token::plus);
594 if (state.topAffineExpr()) {
595 auto lChild = state.popAffineExpr();
596 auto rChild = parseAffineExpr(state);
597 if (rChild) {
598 auto binaryOpExpr = AffineAddExpr::get(lChild, rChild, context);
599 state.popAffineExpr();
600 state.pushAffineExpr(binaryOpExpr);
601 } else {
602 emitError("right operand of + missing");
603 }
604 } else {
605 emitError("left operand of + missing");
606 }
607 break;
608 }
609 case Token::integer: {
610 AffineExpr *expr = AffineConstantExpr::get(
611 curToken.getUnsignedIntegerValue().getValue(), context);
612 state.pushAffineExpr(expr);
613 consumeToken(Token::integer);
614 break;
615 }
616 case Token::l_paren: {
617 consumeToken(Token::l_paren);
618 break;
619 }
620 case Token::r_paren: {
621 consumeToken(Token::r_paren);
622 break;
623 }
624 default: {
625 emitError("affine map expr parse impl incomplete/unexpected token");
626 return nullptr;
627 }
628 }
629 }
630 if (!state.topAffineExpr()) {
631 // An error will be emitted by parse comma separated list on an empty list
632 return nullptr;
633 }
634 return state.topAffineExpr();
635}
636
637// Return empty string if no bare id was found
638StringRef Parser::parseDimOrSymbolId(SmallVectorImpl<StringRef> &dims,
639 SmallVectorImpl<StringRef> &symbols,
640 bool symbol = false) {
641 if (curToken.isNot(Token::bare_identifier)) {
642 emitError("expected bare identifier");
643 return StringRef();
644 }
645 // TODO(bondhugula): check whether the id already exists in either
646 // state.symbols or state.dims; report error if it does; otherwise create a
647 // new one.
648 StringRef ref = curToken.getSpelling();
649 consumeToken(Token::bare_identifier);
650 return ref;
651}
652
653ParseResult Parser::parseSymbolIdList(SmallVectorImpl<StringRef> &dims,
654 SmallVectorImpl<StringRef> &symbols) {
655 if (!consumeIf(Token::l_bracket)) return emitError("expected '['");
656
657 auto parseElt = [&]() -> ParseResult {
658 auto elt = parseDimOrSymbolId(dims, symbols, true);
659 // FIXME(bondhugula): assuming dim arg for now
660 if (!elt.empty()) {
661 symbols.push_back(elt);
662 return ParseSuccess;
663 }
664 return ParseFailure;
665 };
666 return parseCommaSeparatedList(Token::r_bracket, parseElt);
667}
668
669// TODO(andy,bondhugula)
670ParseResult Parser::parseDimIdList(SmallVectorImpl<StringRef> &dims,
671 SmallVectorImpl<StringRef> &symbols) {
672 if (!consumeIf(Token::l_paren))
673 return emitError("expected '(' at start of dimensional identifiers list");
674
675 auto parseElt = [&]() -> ParseResult {
676 auto elt = parseDimOrSymbolId(dims, symbols, false);
677 if (!elt.empty()) {
678 dims.push_back(elt);
679 return ParseSuccess;
680 }
681 return ParseFailure;
682 };
683
684 return parseCommaSeparatedList(Token::r_paren, parseElt);
685}
686
687/// Affine map definition.
688///
689/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
690/// ( `size` `(` dim-size (`,` dim-size)* `)` )?
691/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
692///
693AffineMap *Parser::parseAffineMapInline(StringRef mapId) {
694 SmallVector<StringRef, 4> dims;
695 SmallVector<StringRef, 4> symbols;
696
697 // List of dimensional identifiers.
698 if (parseDimIdList(dims, symbols)) return nullptr;
699
700 // Symbols are optional.
701 if (curToken.is(Token::l_bracket)) {
702 if (parseSymbolIdList(dims, symbols)) return nullptr;
703 }
704 if (!consumeIf(Token::arrow)) {
705 emitError("expected '->' or '['");
706 return nullptr;
707 }
708 if (!consumeIf(Token::l_paren)) {
709 emitError("expected '(' at start of affine map range");
710 return nullptr;
711 }
712
713 AffineMapParserState affState(dims, symbols);
714
715 SmallVector<AffineExpr *, 4> exprs;
716 auto parseElt = [&]() -> ParseResult {
717 auto elt = parseAffineExpr(affState);
718 ParseResult res = elt ? ParseSuccess : ParseFailure;
719 exprs.push_back(elt);
720 return res;
721 };
722
723 // Parse a multi-dimensional affine expression (a comma-separated list of 1-d
724 // affine expressions)
725 if (parseCommaSeparatedList(Token::r_paren, parseElt, false)) return nullptr;
726
727 // Parsed a valid affine map
728 auto *affineMap =
729 AffineMap::get(affState.dimCount(), affState.symbolCount(), exprs,
730 context);
731
732 return affineMap;
MLIR Teamf85a6262018-06-27 11:03:08 -0700733}
734
735//===----------------------------------------------------------------------===//
Chris Lattner4c95a502018-06-23 16:03:42 -0700736// Functions
737//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -0700738
Chris Lattnere79379a2018-06-22 10:39:19 -0700739
740/// Parse a function signature, starting with a name and including the parameter
741/// list.
742///
743/// argument-list ::= type (`,` type)* | /*empty*/
744/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
745///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700746ParseResult Parser::parseFunctionSignature(StringRef &name,
747 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700748 if (curToken.isNot(Token::at_identifier))
749 return emitError("expected a function identifier like '@foo'");
750
751 name = curToken.getSpelling().drop_front();
752 consumeToken(Token::at_identifier);
753
754 if (curToken.isNot(Token::l_paren))
755 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -0700756
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700757 SmallVector<Type*, 4> arguments;
758 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700759 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -0700760
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700761 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700762 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700763 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700764 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700765 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700766 }
Chris Lattnerf7e22732018-06-22 22:03:48 -0700767 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -0700768 return ParseSuccess;
769}
770
Chris Lattnere79379a2018-06-22 10:39:19 -0700771/// External function declarations.
772///
773/// ext-func ::= `extfunc` function-signature
774///
775ParseResult Parser::parseExtFunc() {
776 consumeToken(Token::kw_extfunc);
777
778 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700779 FunctionType *type = nullptr;
780 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -0700781 return ParseFailure;
782
783
784 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -0700785 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -0700786 return ParseSuccess;
787}
788
789
Chris Lattner4c95a502018-06-23 16:03:42 -0700790namespace {
791/// This class represents the transient parser state for the internals of a
792/// function as we are parsing it, e.g. the names for basic blocks. It handles
793/// forward references.
794class CFGFunctionParserState {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700795 public:
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700796 CFGFunction *function;
797 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
798
Chris Lattner4c95a502018-06-23 16:03:42 -0700799 CFGFunctionParserState(CFGFunction *function) : function(function) {}
800
801 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700802 /// already exist. The location specified is the point of use, which allows
803 /// us to diagnose references to blocks that are not defined precisely.
804 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
805 auto &blockAndLoc = blocksByName[name];
806 if (!blockAndLoc.first) {
807 blockAndLoc.first = new BasicBlock(function);
808 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -0700809 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700810 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -0700811 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700812};
813} // end anonymous namespace
814
815
816/// CFG function declarations.
817///
818/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
819///
820ParseResult Parser::parseCFGFunc() {
821 consumeToken(Token::kw_cfgfunc);
822
823 StringRef name;
824 FunctionType *type = nullptr;
825 if (parseFunctionSignature(name, type))
826 return ParseFailure;
827
828 if (!consumeIf(Token::l_brace))
829 return emitError("expected '{' in CFG function");
830
831 // Okay, the CFG function signature was parsed correctly, create the function.
832 auto function = new CFGFunction(name, type);
833
834 // Make sure we have at least one block.
835 if (curToken.is(Token::r_brace))
836 return emitError("CFG functions must have at least one basic block");
837
838 CFGFunctionParserState functionState(function);
839
840 // Parse the list of blocks.
841 while (!consumeIf(Token::r_brace))
842 if (parseBasicBlock(functionState))
843 return ParseFailure;
844
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700845 // Verify that all referenced blocks were defined. Iteration over a
846 // StringMap isn't determinstic, but this is good enough for our purposes.
847 for (auto &elt : functionState.blocksByName) {
848 auto *bb = elt.second.first;
849 if (!bb->getTerminator())
850 return emitError(elt.second.second,
851 "reference to an undefined basic block '" +
852 elt.first() + "'");
853 }
854
Chris Lattner4c95a502018-06-23 16:03:42 -0700855 module->functionList.push_back(function);
856 return ParseSuccess;
857}
858
859/// Basic block declaration.
860///
861/// basic-block ::= bb-label instruction* terminator-stmt
862/// bb-label ::= bb-id bb-arg-list? `:`
863/// bb-id ::= bare-id
864/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
865///
866ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
867 SMLoc nameLoc = curToken.getLoc();
868 auto name = curToken.getSpelling();
869 if (!consumeIf(Token::bare_identifier))
870 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700871
872 auto block = functionState.getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -0700873
874 // If this block has already been parsed, then this is a redefinition with the
875 // same block name.
876 if (block->getTerminator())
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700877 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
878
879 // References to blocks can occur in any order, but we need to reassemble the
880 // function in the order that occurs in the source file. Do this by moving
881 // each block to the end of the list as it is defined.
882 // FIXME: This is inefficient for large functions given that blockList is a
883 // vector. blockList will eventually be an ilist, which will make this fast.
884 auto &blockList = functionState.function->blockList;
885 if (blockList.back() != block) {
886 auto it = std::find(blockList.begin(), blockList.end(), block);
887 assert(it != blockList.end() && "Block has to be in the blockList");
888 std::swap(*it, blockList.back());
889 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700890
891 // TODO: parse bb argument list.
892
893 if (!consumeIf(Token::colon))
894 return emitError("expected ':' after basic block name");
895
Chris Lattnered65a732018-06-28 20:45:33 -0700896 // Parse the list of operations that make up the body of the block.
897 while (curToken.isNot(Token::kw_return, Token::kw_br)) {
898 if (parseCFGOperation(block, functionState))
899 return ParseFailure;
900 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700901
Chris Lattnered65a732018-06-28 20:45:33 -0700902 if (parseTerminator(block, functionState))
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700903 return ParseFailure;
Chris Lattner4c95a502018-06-23 16:03:42 -0700904
905 return ParseSuccess;
906}
907
908
Chris Lattnered65a732018-06-28 20:45:33 -0700909/// Parse the CFG operation.
910///
911/// TODO(clattner): This is a change from the MLIR spec as written, it is an
912/// experiment that will eliminate "builtin" instructions as a thing.
913///
914/// cfg-operation ::=
915/// (ssa-id `=`)? string '(' ssa-use-list? ')' attribute-dict?
916/// `:` function-type
917///
918ParseResult Parser::
919parseCFGOperation(BasicBlock *currentBB,
920 CFGFunctionParserState &functionState) {
921
922 // TODO: parse ssa-id.
923
924 if (curToken.isNot(Token::string))
925 return emitError("expected operation name in quotes");
926
927 auto name = curToken.getStringValue();
928 if (name.empty())
929 return emitError("empty operation name is invalid");
930
931 consumeToken(Token::string);
932
933 if (!consumeIf(Token::l_paren))
934 return emitError("expected '(' in operation");
935
936 // TODO: Parse operands.
937 if (!consumeIf(Token::r_paren))
938 return emitError("expected '(' in operation");
939
940 auto nameId = Identifier::get(name, context);
941 new OperationInst(nameId, currentBB);
942
943 // TODO: add instruction the per-function symbol table.
944 return ParseSuccess;
945}
946
947
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700948/// Parse the terminator instruction for a basic block.
949///
950/// terminator-stmt ::= `br` bb-id branch-use-list?
951/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
952/// terminator-stmt ::=
953/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
954/// terminator-stmt ::= `return` ssa-use-and-type-list?
955///
Chris Lattnered65a732018-06-28 20:45:33 -0700956ParseResult Parser::parseTerminator(BasicBlock *currentBB,
957 CFGFunctionParserState &functionState) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700958 switch (curToken.getKind()) {
959 default:
Chris Lattnered65a732018-06-28 20:45:33 -0700960 return emitError("expected terminator at end of basic block");
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700961
962 case Token::kw_return:
963 consumeToken(Token::kw_return);
Chris Lattnered65a732018-06-28 20:45:33 -0700964 new ReturnInst(currentBB);
965 return ParseSuccess;
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700966
967 case Token::kw_br: {
968 consumeToken(Token::kw_br);
969 auto destBB = functionState.getBlockNamed(curToken.getSpelling(),
970 curToken.getLoc());
971 if (!consumeIf(Token::bare_identifier))
Chris Lattnered65a732018-06-28 20:45:33 -0700972 return emitError("expected basic block name");
973 new BranchInst(destBB, currentBB);
974 return ParseSuccess;
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700975 }
976 }
977}
978
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700979/// ML function declarations.
980///
981/// ml-func ::= `mlfunc` ml-func-signature `{` ml-stmt* ml-return-stmt `}`
982///
983ParseResult Parser::parseMLFunc() {
984 consumeToken(Token::kw_mlfunc);
985
986 StringRef name;
987 FunctionType *type = nullptr;
988
989 // FIXME: Parse ML function signature (args + types)
990 // by passing pointer to SmallVector<identifier> into parseFunctionSignature
991 if (parseFunctionSignature(name, type))
992 return ParseFailure;
993
994 if (!consumeIf(Token::l_brace))
995 return emitError("expected '{' in ML function");
996
997 // Okay, the ML function signature was parsed correctly, create the function.
998 auto function = new MLFunction(name, type);
999
1000 // Make sure we have at least one statement.
1001 if (curToken.is(Token::r_brace))
1002 return emitError("ML function must end with return statement");
1003
1004 // Parse the list of instructions.
1005 while (!consumeIf(Token::kw_return)) {
1006 auto *stmt = parseMLStatement(function);
1007 if (!stmt)
1008 return ParseFailure;
1009 function->stmtList.push_back(stmt);
1010 }
1011
1012 // TODO: parse return statement operands
1013 if (!consumeIf(Token::r_brace))
1014 emitError("expected '}' in ML function");
1015
1016 module->functionList.push_back(function);
1017
1018 return ParseSuccess;
1019}
1020
1021/// Parse an MLStatement
1022/// TODO
1023///
1024MLStatement *Parser::parseMLStatement(MLFunction *currentFunction) {
1025 switch (curToken.getKind()) {
1026 default:
1027 return (emitError("expected ML statement"), nullptr);
1028
1029 // TODO: add parsing of ML statements
1030 }
1031}
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001032
Chris Lattner4c95a502018-06-23 16:03:42 -07001033//===----------------------------------------------------------------------===//
1034// Top-level entity parsing.
1035//===----------------------------------------------------------------------===//
1036
Chris Lattnere79379a2018-06-22 10:39:19 -07001037/// This is the top-level module parser.
1038Module *Parser::parseModule() {
1039 while (1) {
1040 switch (curToken.getKind()) {
1041 default:
1042 emitError("expected a top level entity");
1043 return nullptr;
1044
1045 // If we got to the end of the file, then we're done.
1046 case Token::eof:
1047 return module.release();
1048
1049 // If we got an error token, then the lexer already emitted an error, just
1050 // stop. Someday we could introduce error recovery if there was demand for
1051 // it.
1052 case Token::error:
1053 return nullptr;
1054
1055 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -07001056 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -07001057 break;
1058
Chris Lattner4c95a502018-06-23 16:03:42 -07001059 case Token::kw_cfgfunc:
1060 if (parseCFGFunc()) return nullptr;
1061 break;
Chris Lattner8da0c282018-06-29 11:15:56 -07001062 case Token::affine_map_identifier:
MLIR Teamf85a6262018-06-27 11:03:08 -07001063 if (parseAffineMapDef()) return nullptr;
1064 break;
Chris Lattner4c95a502018-06-23 16:03:42 -07001065
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001066 case Token::kw_mlfunc:
1067 if (parseMLFunc()) return nullptr;
1068 break;
1069
1070 // TODO: affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -07001071 }
1072 }
1073}
1074
1075//===----------------------------------------------------------------------===//
1076
1077/// This parses the file specified by the indicated SourceMgr and returns an
1078/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Jacques Pienaar9c411be2018-06-24 19:17:35 -07001079Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context,
1080 const SMDiagnosticHandlerTy &errorReporter) {
1081 return Parser(sourceMgr, context, errorReporter).parseModule();
Chris Lattnere79379a2018-06-22 10:39:19 -07001082}
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001083