blob: 1bfa331256dc69f46d8f370aec7e770199fa9433 [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 Lattnerf958bbe2018-06-29 22:08:05 -0700124 Type *parsePrimitiveType();
Chris Lattnerf7e22732018-06-22 22:03:48 -0700125 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///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700221/// primitive-type ::= `f16` | `bf16` | `f32` | `f64`
222/// primitive-type ::= integer-type
223/// primitive-type ::= `affineint`
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700224///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700225Type *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700226 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700227 default:
228 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700229 case Token::kw_bf16:
230 consumeToken(Token::kw_bf16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700231 return Type::getBF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700232 case Token::kw_f16:
233 consumeToken(Token::kw_f16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700234 return Type::getF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700235 case Token::kw_f32:
236 consumeToken(Token::kw_f32);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700237 return Type::getF32(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700238 case Token::kw_f64:
239 consumeToken(Token::kw_f64);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700240 return Type::getF64(context);
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700241 case Token::kw_affineint:
242 consumeToken(Token::kw_affineint);
243 return Type::getAffineInt(context);
244 case Token::inttype: {
245 auto width = curToken.getIntTypeBitwidth();
246 if (!width.hasValue())
247 return (emitError("invalid integer width"), nullptr);
248 consumeToken(Token::inttype);
249 return Type::getInt(width.getValue(), context);
250 }
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700251 }
252}
253
254/// Parse the element type of a tensor or memref type.
255///
256/// element-type ::= primitive-type | vector-type
257///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700258Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700259 if (curToken.is(Token::kw_vector))
260 return parseVectorType();
261
262 return parsePrimitiveType();
263}
264
265/// Parse a vector type.
266///
267/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
268/// const-dimension-list ::= (integer-literal `x`)+
269///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700270VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700271 consumeToken(Token::kw_vector);
272
273 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700274 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700275
276 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700277 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700278
279 SmallVector<unsigned, 4> dimensions;
280 while (curToken.is(Token::integer)) {
281 // Make sure this integer value is in bound and valid.
282 auto dimension = curToken.getUnsignedIntegerValue();
283 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700284 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700285 dimensions.push_back(dimension.getValue());
286
287 consumeToken(Token::integer);
288
289 // Make sure we have an 'x' or something like 'xbf32'.
290 if (curToken.isNot(Token::bare_identifier) ||
291 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700292 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700293
294 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
295 if (curToken.getSpelling().size() != 1)
296 lex.resetPointer(curToken.getSpelling().data()+1);
297
298 // Consume the 'x'.
299 consumeToken(Token::bare_identifier);
300 }
301
302 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700303 auto *elementType = parsePrimitiveType();
304 if (!elementType)
305 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700306
307 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700308 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700309
Chris Lattnerf7e22732018-06-22 22:03:48 -0700310 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700311}
312
313/// Parse a dimension list of a tensor or memref type. This populates the
314/// dimension list, returning -1 for the '?' dimensions.
315///
316/// dimension-list-ranked ::= (dimension `x`)*
317/// dimension ::= `?` | integer-literal
318///
319ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
320 while (curToken.isAny(Token::integer, Token::question)) {
321 if (consumeIf(Token::question)) {
322 dimensions.push_back(-1);
323 } else {
324 // Make sure this integer value is in bound and valid.
325 auto dimension = curToken.getUnsignedIntegerValue();
326 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
327 return emitError("invalid dimension");
328 dimensions.push_back((int)dimension.getValue());
329 consumeToken(Token::integer);
330 }
331
332 // Make sure we have an 'x' or something like 'xbf32'.
333 if (curToken.isNot(Token::bare_identifier) ||
334 curToken.getSpelling()[0] != 'x')
335 return emitError("expected 'x' in dimension list");
336
337 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
338 if (curToken.getSpelling().size() != 1)
339 lex.resetPointer(curToken.getSpelling().data()+1);
340
341 // Consume the 'x'.
342 consumeToken(Token::bare_identifier);
343 }
344
345 return ParseSuccess;
346}
347
348/// Parse a tensor type.
349///
350/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
351/// dimension-list ::= dimension-list-ranked | `??`
352///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700353Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700354 consumeToken(Token::kw_tensor);
355
356 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700357 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700358
359 bool isUnranked;
360 SmallVector<int, 4> dimensions;
361
362 if (consumeIf(Token::questionquestion)) {
363 isUnranked = true;
364 } else {
365 isUnranked = false;
366 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700367 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700368 }
369
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 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700376 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700377
MLIR Team355ec862018-06-23 18:09:09 -0700378 if (isUnranked)
379 return UnrankedTensorType::get(elementType);
380 return RankedTensorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700381}
382
383/// Parse a memref type.
384///
385/// memref-type ::= `memref` `<` dimension-list-ranked element-type
386/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
387///
388/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
389/// memory-space ::= integer-literal /* | TODO: address-space-id */
390///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700391Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700392 consumeToken(Token::kw_memref);
393
394 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700395 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700396
397 SmallVector<int, 4> dimensions;
398 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700399 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700400
401 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700402 auto elementType = parseElementType();
403 if (!elementType)
404 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700405
406 // TODO: Parse semi-affine-map-composition.
407 // TODO: Parse memory-space.
408
409 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700410 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700411
Chris Lattnerf7e22732018-06-22 22:03:48 -0700412 // FIXME: Add an IR representation for memref types.
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700413 return Type::getInt(1, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700414}
415
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700416/// Parse a function type.
417///
418/// function-type ::= type-list-parens `->` type-list
419///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700420Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700421 assert(curToken.is(Token::l_paren));
422
Chris Lattnerf7e22732018-06-22 22:03:48 -0700423 SmallVector<Type*, 4> arguments;
424 if (parseTypeList(arguments))
425 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700426
427 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700428 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700429
Chris Lattnerf7e22732018-06-22 22:03:48 -0700430 SmallVector<Type*, 4> results;
431 if (parseTypeList(results))
432 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700433
Chris Lattnerf7e22732018-06-22 22:03:48 -0700434 return FunctionType::get(arguments, results, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700435}
436
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700437/// Parse an arbitrary type.
438///
439/// type ::= primitive-type
440/// | vector-type
441/// | tensor-type
442/// | memref-type
443/// | function-type
444/// element-type ::= primitive-type | vector-type
445///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700446Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700447 switch (curToken.getKind()) {
448 case Token::kw_memref: return parseMemRefType();
449 case Token::kw_tensor: return parseTensorType();
450 case Token::kw_vector: return parseVectorType();
451 case Token::l_paren: return parseFunctionType();
452 default:
453 return parsePrimitiveType();
454 }
455}
456
457/// Parse a "type list", which is a singular type, or a parenthesized list of
458/// types.
459///
460/// type-list ::= type-list-parens | type
461/// type-list-parens ::= `(` `)`
462/// | `(` type (`,` type)* `)`
463///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700464ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
465 auto parseElt = [&]() -> ParseResult {
466 auto elt = parseType();
467 elements.push_back(elt);
468 return elt ? ParseSuccess : ParseFailure;
469 };
470
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700471 // If there is no parens, then it must be a singular type.
472 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700473 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700474
Chris Lattnerf7e22732018-06-22 22:03:48 -0700475 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700476 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700477
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700478 return ParseSuccess;
479}
480
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700481namespace {
482/// This class represents the transient parser state while parsing an affine
483/// expression.
484class AffineMapParserState {
485 public:
486 explicit AffineMapParserState(ArrayRef<StringRef> dims,
487 ArrayRef<StringRef> symbols) :
488 dims_(dims), symbols_(symbols) {}
489
490 unsigned dimCount() const { return dims_.size(); }
491 unsigned symbolCount() const { return symbols_.size(); }
492
493 // Stack operations for affine expression parsing
494 // TODO(bondhugula): all of this will be improved/made more principled
495 void pushAffineExpr(AffineExpr *expr) { exprStack.push(expr); }
496 AffineExpr *popAffineExpr() {
497 auto *t = exprStack.top();
498 exprStack.pop();
499 return t;
500 }
501 AffineExpr *topAffineExpr() { return exprStack.top(); }
502
503 ArrayRef<StringRef> getDims() const { return dims_; }
504 ArrayRef<StringRef> getSymbols() const { return symbols_; }
505
506 private:
507 const ArrayRef<StringRef> dims_;
508 const ArrayRef<StringRef> symbols_;
509
510 // TEMP: stack to hold affine expressions
511 std::stack<AffineExpr *> exprStack;
512};
513} // end anonymous namespace
514
Chris Lattner4c95a502018-06-23 16:03:42 -0700515//===----------------------------------------------------------------------===//
MLIR Teamf85a6262018-06-27 11:03:08 -0700516// Polyhedral structures.
517//===----------------------------------------------------------------------===//
518
519/// Affine map declaration.
520///
521/// affine-map-def ::= affine-map-id `=` affine-map-inline
MLIR Teamf85a6262018-06-27 11:03:08 -0700522///
523ParseResult Parser::parseAffineMapDef() {
Chris Lattner8da0c282018-06-29 11:15:56 -0700524 assert(curToken.is(Token::affine_map_identifier));
MLIR Teamf85a6262018-06-27 11:03:08 -0700525
526 StringRef affineMapId = curToken.getSpelling().drop_front();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700527 consumeToken(Token::affine_map_identifier);
528
MLIR Teamf85a6262018-06-27 11:03:08 -0700529 // Check that 'affineMapId' is unique.
530 // TODO(andydavis) Add a unit test for this case.
531 if (affineMaps.count(affineMapId) > 0)
Chris Lattnered65a732018-06-28 20:45:33 -0700532 return emitError("redefinition of affine map id '" + affineMapId + "'");
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700533 // Parse the '='
534 if (!consumeIf(Token::equal))
535 return emitError("expected '=' in affine map outlined definition");
MLIR Teamf85a6262018-06-27 11:03:08 -0700536
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700537 auto *affineMap = parseAffineMapInline(affineMapId);
538 affineMaps[affineMapId].reset(affineMap);
539 if (!affineMap) return ParseFailure;
MLIR Teamf85a6262018-06-27 11:03:08 -0700540
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700541 module->affineMapList.push_back(affineMap);
542 return affineMap ? ParseSuccess : ParseFailure;
543}
544
545///
546/// Parse a multi-dimensional affine expression
547/// affine-expr ::= `(` affine-expr `)`
548/// | affine-expr `+` affine-expr
549/// | affine-expr `-` affine-expr
550/// | `-`? integer-literal `*` affine-expr
551/// | `ceildiv` `(` affine-expr `,` integer-literal `)`
552/// | `floordiv` `(` affine-expr `,` integer-literal `)`
553/// | affine-expr `mod` integer-literal
554/// | bare-id
555/// | `-`? integer-literal
556/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
557///
558/// Use 'state' to check if valid identifiers appear.
559///
560AffineExpr *Parser::parseAffineExpr(AffineMapParserState &state) {
561 // TODO(bondhugula): complete support for this
562 // The code below is all placeholder / it is wrong / not complete
563 // Operator precedence not considered; pure left to right associativity
564 if (curToken.is(Token::comma)) {
565 emitError("expecting affine expression");
566 return nullptr;
567 }
568
569 while (curToken.isNot(Token::comma, Token::r_paren,
570 Token::eof, Token::error)) {
571 switch (curToken.getKind()) {
572 case Token::bare_identifier: {
573 // TODO(bondhugula): look up state to see if it's a symbol or dim_id and
574 // get its position
575 AffineExpr *expr = AffineDimExpr::get(0, context);
576 state.pushAffineExpr(expr);
577 consumeToken(Token::bare_identifier);
578 break;
579 }
580 case Token::plus: {
581 consumeToken(Token::plus);
582 if (state.topAffineExpr()) {
583 auto lChild = state.popAffineExpr();
584 auto rChild = parseAffineExpr(state);
585 if (rChild) {
586 auto binaryOpExpr = AffineAddExpr::get(lChild, rChild, context);
587 state.popAffineExpr();
588 state.pushAffineExpr(binaryOpExpr);
589 } else {
590 emitError("right operand of + missing");
591 }
592 } else {
593 emitError("left operand of + missing");
594 }
595 break;
596 }
597 case Token::integer: {
598 AffineExpr *expr = AffineConstantExpr::get(
599 curToken.getUnsignedIntegerValue().getValue(), context);
600 state.pushAffineExpr(expr);
601 consumeToken(Token::integer);
602 break;
603 }
604 case Token::l_paren: {
605 consumeToken(Token::l_paren);
606 break;
607 }
608 case Token::r_paren: {
609 consumeToken(Token::r_paren);
610 break;
611 }
612 default: {
613 emitError("affine map expr parse impl incomplete/unexpected token");
614 return nullptr;
615 }
616 }
617 }
618 if (!state.topAffineExpr()) {
619 // An error will be emitted by parse comma separated list on an empty list
620 return nullptr;
621 }
622 return state.topAffineExpr();
623}
624
625// Return empty string if no bare id was found
626StringRef Parser::parseDimOrSymbolId(SmallVectorImpl<StringRef> &dims,
627 SmallVectorImpl<StringRef> &symbols,
628 bool symbol = false) {
629 if (curToken.isNot(Token::bare_identifier)) {
630 emitError("expected bare identifier");
631 return StringRef();
632 }
633 // TODO(bondhugula): check whether the id already exists in either
634 // state.symbols or state.dims; report error if it does; otherwise create a
635 // new one.
636 StringRef ref = curToken.getSpelling();
637 consumeToken(Token::bare_identifier);
638 return ref;
639}
640
641ParseResult Parser::parseSymbolIdList(SmallVectorImpl<StringRef> &dims,
642 SmallVectorImpl<StringRef> &symbols) {
643 if (!consumeIf(Token::l_bracket)) return emitError("expected '['");
644
645 auto parseElt = [&]() -> ParseResult {
646 auto elt = parseDimOrSymbolId(dims, symbols, true);
647 // FIXME(bondhugula): assuming dim arg for now
648 if (!elt.empty()) {
649 symbols.push_back(elt);
650 return ParseSuccess;
651 }
652 return ParseFailure;
653 };
654 return parseCommaSeparatedList(Token::r_bracket, parseElt);
655}
656
657// TODO(andy,bondhugula)
658ParseResult Parser::parseDimIdList(SmallVectorImpl<StringRef> &dims,
659 SmallVectorImpl<StringRef> &symbols) {
660 if (!consumeIf(Token::l_paren))
661 return emitError("expected '(' at start of dimensional identifiers list");
662
663 auto parseElt = [&]() -> ParseResult {
664 auto elt = parseDimOrSymbolId(dims, symbols, false);
665 if (!elt.empty()) {
666 dims.push_back(elt);
667 return ParseSuccess;
668 }
669 return ParseFailure;
670 };
671
672 return parseCommaSeparatedList(Token::r_paren, parseElt);
673}
674
675/// Affine map definition.
676///
677/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
678/// ( `size` `(` dim-size (`,` dim-size)* `)` )?
679/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
680///
681AffineMap *Parser::parseAffineMapInline(StringRef mapId) {
682 SmallVector<StringRef, 4> dims;
683 SmallVector<StringRef, 4> symbols;
684
685 // List of dimensional identifiers.
686 if (parseDimIdList(dims, symbols)) return nullptr;
687
688 // Symbols are optional.
689 if (curToken.is(Token::l_bracket)) {
690 if (parseSymbolIdList(dims, symbols)) return nullptr;
691 }
692 if (!consumeIf(Token::arrow)) {
693 emitError("expected '->' or '['");
694 return nullptr;
695 }
696 if (!consumeIf(Token::l_paren)) {
697 emitError("expected '(' at start of affine map range");
698 return nullptr;
699 }
700
701 AffineMapParserState affState(dims, symbols);
702
703 SmallVector<AffineExpr *, 4> exprs;
704 auto parseElt = [&]() -> ParseResult {
705 auto elt = parseAffineExpr(affState);
706 ParseResult res = elt ? ParseSuccess : ParseFailure;
707 exprs.push_back(elt);
708 return res;
709 };
710
711 // Parse a multi-dimensional affine expression (a comma-separated list of 1-d
712 // affine expressions)
713 if (parseCommaSeparatedList(Token::r_paren, parseElt, false)) return nullptr;
714
715 // Parsed a valid affine map
716 auto *affineMap =
717 AffineMap::get(affState.dimCount(), affState.symbolCount(), exprs,
718 context);
719
720 return affineMap;
MLIR Teamf85a6262018-06-27 11:03:08 -0700721}
722
723//===----------------------------------------------------------------------===//
Chris Lattner4c95a502018-06-23 16:03:42 -0700724// Functions
725//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -0700726
Chris Lattnere79379a2018-06-22 10:39:19 -0700727
728/// Parse a function signature, starting with a name and including the parameter
729/// list.
730///
731/// argument-list ::= type (`,` type)* | /*empty*/
732/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
733///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700734ParseResult Parser::parseFunctionSignature(StringRef &name,
735 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700736 if (curToken.isNot(Token::at_identifier))
737 return emitError("expected a function identifier like '@foo'");
738
739 name = curToken.getSpelling().drop_front();
740 consumeToken(Token::at_identifier);
741
742 if (curToken.isNot(Token::l_paren))
743 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -0700744
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700745 SmallVector<Type*, 4> arguments;
746 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700747 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -0700748
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700749 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700750 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700751 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700752 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700753 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700754 }
Chris Lattnerf7e22732018-06-22 22:03:48 -0700755 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -0700756 return ParseSuccess;
757}
758
Chris Lattnere79379a2018-06-22 10:39:19 -0700759/// External function declarations.
760///
761/// ext-func ::= `extfunc` function-signature
762///
763ParseResult Parser::parseExtFunc() {
764 consumeToken(Token::kw_extfunc);
765
766 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700767 FunctionType *type = nullptr;
768 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -0700769 return ParseFailure;
770
771
772 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -0700773 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -0700774 return ParseSuccess;
775}
776
777
Chris Lattner4c95a502018-06-23 16:03:42 -0700778namespace {
779/// This class represents the transient parser state for the internals of a
780/// function as we are parsing it, e.g. the names for basic blocks. It handles
781/// forward references.
782class CFGFunctionParserState {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700783 public:
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700784 CFGFunction *function;
785 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
786
Chris Lattner4c95a502018-06-23 16:03:42 -0700787 CFGFunctionParserState(CFGFunction *function) : function(function) {}
788
789 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700790 /// already exist. The location specified is the point of use, which allows
791 /// us to diagnose references to blocks that are not defined precisely.
792 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
793 auto &blockAndLoc = blocksByName[name];
794 if (!blockAndLoc.first) {
795 blockAndLoc.first = new BasicBlock(function);
796 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -0700797 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700798 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -0700799 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700800};
801} // end anonymous namespace
802
803
804/// CFG function declarations.
805///
806/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
807///
808ParseResult Parser::parseCFGFunc() {
809 consumeToken(Token::kw_cfgfunc);
810
811 StringRef name;
812 FunctionType *type = nullptr;
813 if (parseFunctionSignature(name, type))
814 return ParseFailure;
815
816 if (!consumeIf(Token::l_brace))
817 return emitError("expected '{' in CFG function");
818
819 // Okay, the CFG function signature was parsed correctly, create the function.
820 auto function = new CFGFunction(name, type);
821
822 // Make sure we have at least one block.
823 if (curToken.is(Token::r_brace))
824 return emitError("CFG functions must have at least one basic block");
825
826 CFGFunctionParserState functionState(function);
827
828 // Parse the list of blocks.
829 while (!consumeIf(Token::r_brace))
830 if (parseBasicBlock(functionState))
831 return ParseFailure;
832
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700833 // Verify that all referenced blocks were defined. Iteration over a
834 // StringMap isn't determinstic, but this is good enough for our purposes.
835 for (auto &elt : functionState.blocksByName) {
836 auto *bb = elt.second.first;
837 if (!bb->getTerminator())
838 return emitError(elt.second.second,
839 "reference to an undefined basic block '" +
840 elt.first() + "'");
841 }
842
Chris Lattner4c95a502018-06-23 16:03:42 -0700843 module->functionList.push_back(function);
844 return ParseSuccess;
845}
846
847/// Basic block declaration.
848///
849/// basic-block ::= bb-label instruction* terminator-stmt
850/// bb-label ::= bb-id bb-arg-list? `:`
851/// bb-id ::= bare-id
852/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
853///
854ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
855 SMLoc nameLoc = curToken.getLoc();
856 auto name = curToken.getSpelling();
857 if (!consumeIf(Token::bare_identifier))
858 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700859
860 auto block = functionState.getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -0700861
862 // If this block has already been parsed, then this is a redefinition with the
863 // same block name.
864 if (block->getTerminator())
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700865 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
866
867 // References to blocks can occur in any order, but we need to reassemble the
868 // function in the order that occurs in the source file. Do this by moving
869 // each block to the end of the list as it is defined.
870 // FIXME: This is inefficient for large functions given that blockList is a
871 // vector. blockList will eventually be an ilist, which will make this fast.
872 auto &blockList = functionState.function->blockList;
873 if (blockList.back() != block) {
874 auto it = std::find(blockList.begin(), blockList.end(), block);
875 assert(it != blockList.end() && "Block has to be in the blockList");
876 std::swap(*it, blockList.back());
877 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700878
879 // TODO: parse bb argument list.
880
881 if (!consumeIf(Token::colon))
882 return emitError("expected ':' after basic block name");
883
Chris Lattnered65a732018-06-28 20:45:33 -0700884 // Parse the list of operations that make up the body of the block.
885 while (curToken.isNot(Token::kw_return, Token::kw_br)) {
886 if (parseCFGOperation(block, functionState))
887 return ParseFailure;
888 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700889
Chris Lattnered65a732018-06-28 20:45:33 -0700890 if (parseTerminator(block, functionState))
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700891 return ParseFailure;
Chris Lattner4c95a502018-06-23 16:03:42 -0700892
893 return ParseSuccess;
894}
895
896
Chris Lattnered65a732018-06-28 20:45:33 -0700897/// Parse the CFG operation.
898///
899/// TODO(clattner): This is a change from the MLIR spec as written, it is an
900/// experiment that will eliminate "builtin" instructions as a thing.
901///
902/// cfg-operation ::=
903/// (ssa-id `=`)? string '(' ssa-use-list? ')' attribute-dict?
904/// `:` function-type
905///
906ParseResult Parser::
907parseCFGOperation(BasicBlock *currentBB,
908 CFGFunctionParserState &functionState) {
909
910 // TODO: parse ssa-id.
911
912 if (curToken.isNot(Token::string))
913 return emitError("expected operation name in quotes");
914
915 auto name = curToken.getStringValue();
916 if (name.empty())
917 return emitError("empty operation name is invalid");
918
919 consumeToken(Token::string);
920
921 if (!consumeIf(Token::l_paren))
922 return emitError("expected '(' in operation");
923
924 // TODO: Parse operands.
925 if (!consumeIf(Token::r_paren))
926 return emitError("expected '(' in operation");
927
928 auto nameId = Identifier::get(name, context);
929 new OperationInst(nameId, currentBB);
930
931 // TODO: add instruction the per-function symbol table.
932 return ParseSuccess;
933}
934
935
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700936/// Parse the terminator instruction for a basic block.
937///
938/// terminator-stmt ::= `br` bb-id branch-use-list?
939/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
940/// terminator-stmt ::=
941/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
942/// terminator-stmt ::= `return` ssa-use-and-type-list?
943///
Chris Lattnered65a732018-06-28 20:45:33 -0700944ParseResult Parser::parseTerminator(BasicBlock *currentBB,
945 CFGFunctionParserState &functionState) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700946 switch (curToken.getKind()) {
947 default:
Chris Lattnered65a732018-06-28 20:45:33 -0700948 return emitError("expected terminator at end of basic block");
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700949
950 case Token::kw_return:
951 consumeToken(Token::kw_return);
Chris Lattnered65a732018-06-28 20:45:33 -0700952 new ReturnInst(currentBB);
953 return ParseSuccess;
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700954
955 case Token::kw_br: {
956 consumeToken(Token::kw_br);
957 auto destBB = functionState.getBlockNamed(curToken.getSpelling(),
958 curToken.getLoc());
959 if (!consumeIf(Token::bare_identifier))
Chris Lattnered65a732018-06-28 20:45:33 -0700960 return emitError("expected basic block name");
961 new BranchInst(destBB, currentBB);
962 return ParseSuccess;
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700963 }
964 }
965}
966
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700967/// ML function declarations.
968///
969/// ml-func ::= `mlfunc` ml-func-signature `{` ml-stmt* ml-return-stmt `}`
970///
971ParseResult Parser::parseMLFunc() {
972 consumeToken(Token::kw_mlfunc);
973
974 StringRef name;
975 FunctionType *type = nullptr;
976
977 // FIXME: Parse ML function signature (args + types)
978 // by passing pointer to SmallVector<identifier> into parseFunctionSignature
979 if (parseFunctionSignature(name, type))
980 return ParseFailure;
981
982 if (!consumeIf(Token::l_brace))
983 return emitError("expected '{' in ML function");
984
985 // Okay, the ML function signature was parsed correctly, create the function.
986 auto function = new MLFunction(name, type);
987
988 // Make sure we have at least one statement.
989 if (curToken.is(Token::r_brace))
990 return emitError("ML function must end with return statement");
991
992 // Parse the list of instructions.
993 while (!consumeIf(Token::kw_return)) {
994 auto *stmt = parseMLStatement(function);
995 if (!stmt)
996 return ParseFailure;
997 function->stmtList.push_back(stmt);
998 }
999
1000 // TODO: parse return statement operands
1001 if (!consumeIf(Token::r_brace))
1002 emitError("expected '}' in ML function");
1003
1004 module->functionList.push_back(function);
1005
1006 return ParseSuccess;
1007}
1008
1009/// Parse an MLStatement
1010/// TODO
1011///
1012MLStatement *Parser::parseMLStatement(MLFunction *currentFunction) {
1013 switch (curToken.getKind()) {
1014 default:
1015 return (emitError("expected ML statement"), nullptr);
1016
1017 // TODO: add parsing of ML statements
1018 }
1019}
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001020
Chris Lattner4c95a502018-06-23 16:03:42 -07001021//===----------------------------------------------------------------------===//
1022// Top-level entity parsing.
1023//===----------------------------------------------------------------------===//
1024
Chris Lattnere79379a2018-06-22 10:39:19 -07001025/// This is the top-level module parser.
1026Module *Parser::parseModule() {
1027 while (1) {
1028 switch (curToken.getKind()) {
1029 default:
1030 emitError("expected a top level entity");
1031 return nullptr;
1032
1033 // If we got to the end of the file, then we're done.
1034 case Token::eof:
1035 return module.release();
1036
1037 // If we got an error token, then the lexer already emitted an error, just
1038 // stop. Someday we could introduce error recovery if there was demand for
1039 // it.
1040 case Token::error:
1041 return nullptr;
1042
1043 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -07001044 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -07001045 break;
1046
Chris Lattner4c95a502018-06-23 16:03:42 -07001047 case Token::kw_cfgfunc:
1048 if (parseCFGFunc()) return nullptr;
1049 break;
Chris Lattner8da0c282018-06-29 11:15:56 -07001050 case Token::affine_map_identifier:
MLIR Teamf85a6262018-06-27 11:03:08 -07001051 if (parseAffineMapDef()) return nullptr;
1052 break;
Chris Lattner4c95a502018-06-23 16:03:42 -07001053
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001054 case Token::kw_mlfunc:
1055 if (parseMLFunc()) return nullptr;
1056 break;
1057
1058 // TODO: affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -07001059 }
1060 }
1061}
1062
1063//===----------------------------------------------------------------------===//
1064
1065/// This parses the file specified by the indicated SourceMgr and returns an
1066/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Jacques Pienaar9c411be2018-06-24 19:17:35 -07001067Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context,
1068 const SMDiagnosticHandlerTy &errorReporter) {
1069 return Parser(sourceMgr, context, errorReporter).parseModule();
Chris Lattnere79379a2018-06-22 10:39:19 -07001070}
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001071