blob: 91f80e25582aabb54a185f1d4ceeef0febeee305 [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 Lattner3a467cc2018-07-01 20:28:00 -0700156 OperationInst *parseCFGOperation(CFGFunctionParserState &functionState);
157 TerminatorInst *parseTerminator(CFGFunctionParserState &functionState);
Chris Lattnered65a732018-06-28 20:45:33 -0700158
Chris Lattnere79379a2018-06-22 10:39:19 -0700159};
160} // end anonymous namespace
161
162//===----------------------------------------------------------------------===//
163// Helper methods.
164//===----------------------------------------------------------------------===//
165
Chris Lattner4c95a502018-06-23 16:03:42 -0700166ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700167 // If we hit a parse error in response to a lexer error, then the lexer
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700168 // already reported the error.
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700169 if (curToken.is(Token::error))
170 return ParseFailure;
171
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700172 errorReporter(
173 lex.getSourceMgr().GetMessage(loc, SourceMgr::DK_Error, message));
Chris Lattnere79379a2018-06-22 10:39:19 -0700174 return ParseFailure;
175}
176
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700177/// Parse a comma-separated list of elements, terminated with an arbitrary
178/// token. This allows empty lists if allowEmptyList is true.
179///
180/// abstract-list ::= rightToken // if allowEmptyList == true
181/// abstract-list ::= element (',' element)* rightToken
182///
183ParseResult Parser::
Chris Lattner8da0c282018-06-29 11:15:56 -0700184parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700185 const std::function<ParseResult()> &parseElement,
186 bool allowEmptyList) {
187 // Handle the empty case.
188 if (curToken.is(rightToken)) {
189 if (!allowEmptyList)
190 return emitError("expected list element");
191 consumeToken(rightToken);
192 return ParseSuccess;
193 }
194
195 // Non-empty case starts with an element.
196 if (parseElement())
197 return ParseFailure;
198
199 // Otherwise we have a list of comma separated elements.
200 while (consumeIf(Token::comma)) {
201 if (parseElement())
202 return ParseFailure;
203 }
204
205 // Consume the end character.
206 if (!consumeIf(rightToken))
Chris Lattner8da0c282018-06-29 11:15:56 -0700207 return emitError("expected ',' or '" + Token::getTokenSpelling(rightToken) +
208 "'");
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700209
210 return ParseSuccess;
211}
Chris Lattnere79379a2018-06-22 10:39:19 -0700212
213//===----------------------------------------------------------------------===//
214// Type Parsing
215//===----------------------------------------------------------------------===//
216
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700217/// Parse the low-level fixed dtypes in the system.
218///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700219/// primitive-type ::= `f16` | `bf16` | `f32` | `f64`
220/// primitive-type ::= integer-type
221/// primitive-type ::= `affineint`
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700222///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700223Type *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700224 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700225 default:
226 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700227 case Token::kw_bf16:
228 consumeToken(Token::kw_bf16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700229 return Type::getBF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700230 case Token::kw_f16:
231 consumeToken(Token::kw_f16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700232 return Type::getF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700233 case Token::kw_f32:
234 consumeToken(Token::kw_f32);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700235 return Type::getF32(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700236 case Token::kw_f64:
237 consumeToken(Token::kw_f64);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700238 return Type::getF64(context);
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700239 case Token::kw_affineint:
240 consumeToken(Token::kw_affineint);
241 return Type::getAffineInt(context);
242 case Token::inttype: {
243 auto width = curToken.getIntTypeBitwidth();
244 if (!width.hasValue())
245 return (emitError("invalid integer width"), nullptr);
246 consumeToken(Token::inttype);
247 return Type::getInt(width.getValue(), context);
248 }
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700249 }
250}
251
252/// Parse the element type of a tensor or memref type.
253///
254/// element-type ::= primitive-type | vector-type
255///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700256Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700257 if (curToken.is(Token::kw_vector))
258 return parseVectorType();
259
260 return parsePrimitiveType();
261}
262
263/// Parse a vector type.
264///
265/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
266/// const-dimension-list ::= (integer-literal `x`)+
267///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700268VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700269 consumeToken(Token::kw_vector);
270
271 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700272 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700273
274 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700275 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700276
277 SmallVector<unsigned, 4> dimensions;
278 while (curToken.is(Token::integer)) {
279 // Make sure this integer value is in bound and valid.
280 auto dimension = curToken.getUnsignedIntegerValue();
281 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700282 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700283 dimensions.push_back(dimension.getValue());
284
285 consumeToken(Token::integer);
286
287 // Make sure we have an 'x' or something like 'xbf32'.
288 if (curToken.isNot(Token::bare_identifier) ||
289 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700290 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700291
292 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
293 if (curToken.getSpelling().size() != 1)
294 lex.resetPointer(curToken.getSpelling().data()+1);
295
296 // Consume the 'x'.
297 consumeToken(Token::bare_identifier);
298 }
299
300 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700301 auto *elementType = parsePrimitiveType();
302 if (!elementType)
303 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700304
305 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700306 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700307
Chris Lattnerf7e22732018-06-22 22:03:48 -0700308 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700309}
310
311/// Parse a dimension list of a tensor or memref type. This populates the
312/// dimension list, returning -1 for the '?' dimensions.
313///
314/// dimension-list-ranked ::= (dimension `x`)*
315/// dimension ::= `?` | integer-literal
316///
317ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
318 while (curToken.isAny(Token::integer, Token::question)) {
319 if (consumeIf(Token::question)) {
320 dimensions.push_back(-1);
321 } else {
322 // Make sure this integer value is in bound and valid.
323 auto dimension = curToken.getUnsignedIntegerValue();
324 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
325 return emitError("invalid dimension");
326 dimensions.push_back((int)dimension.getValue());
327 consumeToken(Token::integer);
328 }
329
330 // Make sure we have an 'x' or something like 'xbf32'.
331 if (curToken.isNot(Token::bare_identifier) ||
332 curToken.getSpelling()[0] != 'x')
333 return emitError("expected 'x' in dimension list");
334
335 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
336 if (curToken.getSpelling().size() != 1)
337 lex.resetPointer(curToken.getSpelling().data()+1);
338
339 // Consume the 'x'.
340 consumeToken(Token::bare_identifier);
341 }
342
343 return ParseSuccess;
344}
345
346/// Parse a tensor type.
347///
348/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
349/// dimension-list ::= dimension-list-ranked | `??`
350///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700351Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700352 consumeToken(Token::kw_tensor);
353
354 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700355 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700356
357 bool isUnranked;
358 SmallVector<int, 4> dimensions;
359
360 if (consumeIf(Token::questionquestion)) {
361 isUnranked = true;
362 } else {
363 isUnranked = false;
364 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700365 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700366 }
367
368 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700369 auto elementType = parseElementType();
370 if (!elementType)
371 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700372
373 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700374 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700375
MLIR Team355ec862018-06-23 18:09:09 -0700376 if (isUnranked)
377 return UnrankedTensorType::get(elementType);
378 return RankedTensorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700379}
380
381/// Parse a memref type.
382///
383/// memref-type ::= `memref` `<` dimension-list-ranked element-type
384/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
385///
386/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
387/// memory-space ::= integer-literal /* | TODO: address-space-id */
388///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700389Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700390 consumeToken(Token::kw_memref);
391
392 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700393 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700394
395 SmallVector<int, 4> dimensions;
396 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700397 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700398
399 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700400 auto elementType = parseElementType();
401 if (!elementType)
402 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700403
404 // TODO: Parse semi-affine-map-composition.
405 // TODO: Parse memory-space.
406
407 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700408 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700409
Chris Lattnerf7e22732018-06-22 22:03:48 -0700410 // FIXME: Add an IR representation for memref types.
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700411 return Type::getInt(1, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700412}
413
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700414/// Parse a function type.
415///
416/// function-type ::= type-list-parens `->` type-list
417///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700418Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700419 assert(curToken.is(Token::l_paren));
420
Chris Lattnerf7e22732018-06-22 22:03:48 -0700421 SmallVector<Type*, 4> arguments;
422 if (parseTypeList(arguments))
423 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700424
425 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700426 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700427
Chris Lattnerf7e22732018-06-22 22:03:48 -0700428 SmallVector<Type*, 4> results;
429 if (parseTypeList(results))
430 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700431
Chris Lattnerf7e22732018-06-22 22:03:48 -0700432 return FunctionType::get(arguments, results, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700433}
434
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700435/// Parse an arbitrary type.
436///
437/// type ::= primitive-type
438/// | vector-type
439/// | tensor-type
440/// | memref-type
441/// | function-type
442/// element-type ::= primitive-type | vector-type
443///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700444Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700445 switch (curToken.getKind()) {
446 case Token::kw_memref: return parseMemRefType();
447 case Token::kw_tensor: return parseTensorType();
448 case Token::kw_vector: return parseVectorType();
449 case Token::l_paren: return parseFunctionType();
450 default:
451 return parsePrimitiveType();
452 }
453}
454
455/// Parse a "type list", which is a singular type, or a parenthesized list of
456/// types.
457///
458/// type-list ::= type-list-parens | type
459/// type-list-parens ::= `(` `)`
460/// | `(` type (`,` type)* `)`
461///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700462ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
463 auto parseElt = [&]() -> ParseResult {
464 auto elt = parseType();
465 elements.push_back(elt);
466 return elt ? ParseSuccess : ParseFailure;
467 };
468
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700469 // If there is no parens, then it must be a singular type.
470 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700471 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700472
Chris Lattnerf7e22732018-06-22 22:03:48 -0700473 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700474 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700475
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700476 return ParseSuccess;
477}
478
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700479namespace {
480/// This class represents the transient parser state while parsing an affine
481/// expression.
482class AffineMapParserState {
483 public:
484 explicit AffineMapParserState(ArrayRef<StringRef> dims,
485 ArrayRef<StringRef> symbols) :
486 dims_(dims), symbols_(symbols) {}
487
488 unsigned dimCount() const { return dims_.size(); }
489 unsigned symbolCount() const { return symbols_.size(); }
490
491 // Stack operations for affine expression parsing
492 // TODO(bondhugula): all of this will be improved/made more principled
493 void pushAffineExpr(AffineExpr *expr) { exprStack.push(expr); }
494 AffineExpr *popAffineExpr() {
495 auto *t = exprStack.top();
496 exprStack.pop();
497 return t;
498 }
499 AffineExpr *topAffineExpr() { return exprStack.top(); }
500
501 ArrayRef<StringRef> getDims() const { return dims_; }
502 ArrayRef<StringRef> getSymbols() const { return symbols_; }
503
504 private:
505 const ArrayRef<StringRef> dims_;
506 const ArrayRef<StringRef> symbols_;
507
508 // TEMP: stack to hold affine expressions
509 std::stack<AffineExpr *> exprStack;
510};
511} // end anonymous namespace
512
Chris Lattner4c95a502018-06-23 16:03:42 -0700513//===----------------------------------------------------------------------===//
MLIR Teamf85a6262018-06-27 11:03:08 -0700514// Polyhedral structures.
515//===----------------------------------------------------------------------===//
516
517/// Affine map declaration.
518///
519/// affine-map-def ::= affine-map-id `=` affine-map-inline
MLIR Teamf85a6262018-06-27 11:03:08 -0700520///
521ParseResult Parser::parseAffineMapDef() {
Chris Lattner8da0c282018-06-29 11:15:56 -0700522 assert(curToken.is(Token::affine_map_identifier));
MLIR Teamf85a6262018-06-27 11:03:08 -0700523
524 StringRef affineMapId = curToken.getSpelling().drop_front();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700525 consumeToken(Token::affine_map_identifier);
526
MLIR Teamf85a6262018-06-27 11:03:08 -0700527 // Check that 'affineMapId' is unique.
528 // TODO(andydavis) Add a unit test for this case.
529 if (affineMaps.count(affineMapId) > 0)
Chris Lattnered65a732018-06-28 20:45:33 -0700530 return emitError("redefinition of affine map id '" + affineMapId + "'");
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700531 // Parse the '='
532 if (!consumeIf(Token::equal))
533 return emitError("expected '=' in affine map outlined definition");
MLIR Teamf85a6262018-06-27 11:03:08 -0700534
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700535 auto *affineMap = parseAffineMapInline(affineMapId);
536 affineMaps[affineMapId].reset(affineMap);
537 if (!affineMap) return ParseFailure;
MLIR Teamf85a6262018-06-27 11:03:08 -0700538
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700539 module->affineMapList.push_back(affineMap);
540 return affineMap ? ParseSuccess : ParseFailure;
541}
542
543///
544/// Parse a multi-dimensional affine expression
545/// affine-expr ::= `(` affine-expr `)`
546/// | affine-expr `+` affine-expr
547/// | affine-expr `-` affine-expr
548/// | `-`? integer-literal `*` affine-expr
549/// | `ceildiv` `(` affine-expr `,` integer-literal `)`
550/// | `floordiv` `(` affine-expr `,` integer-literal `)`
551/// | affine-expr `mod` integer-literal
552/// | bare-id
553/// | `-`? integer-literal
554/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
555///
556/// Use 'state' to check if valid identifiers appear.
557///
558AffineExpr *Parser::parseAffineExpr(AffineMapParserState &state) {
559 // TODO(bondhugula): complete support for this
560 // The code below is all placeholder / it is wrong / not complete
561 // Operator precedence not considered; pure left to right associativity
562 if (curToken.is(Token::comma)) {
563 emitError("expecting affine expression");
564 return nullptr;
565 }
566
567 while (curToken.isNot(Token::comma, Token::r_paren,
568 Token::eof, Token::error)) {
569 switch (curToken.getKind()) {
570 case Token::bare_identifier: {
571 // TODO(bondhugula): look up state to see if it's a symbol or dim_id and
572 // get its position
573 AffineExpr *expr = AffineDimExpr::get(0, context);
574 state.pushAffineExpr(expr);
575 consumeToken(Token::bare_identifier);
576 break;
577 }
578 case Token::plus: {
579 consumeToken(Token::plus);
580 if (state.topAffineExpr()) {
581 auto lChild = state.popAffineExpr();
582 auto rChild = parseAffineExpr(state);
583 if (rChild) {
584 auto binaryOpExpr = AffineAddExpr::get(lChild, rChild, context);
585 state.popAffineExpr();
586 state.pushAffineExpr(binaryOpExpr);
587 } else {
588 emitError("right operand of + missing");
589 }
590 } else {
591 emitError("left operand of + missing");
592 }
593 break;
594 }
595 case Token::integer: {
596 AffineExpr *expr = AffineConstantExpr::get(
597 curToken.getUnsignedIntegerValue().getValue(), context);
598 state.pushAffineExpr(expr);
599 consumeToken(Token::integer);
600 break;
601 }
602 case Token::l_paren: {
603 consumeToken(Token::l_paren);
604 break;
605 }
606 case Token::r_paren: {
607 consumeToken(Token::r_paren);
608 break;
609 }
610 default: {
611 emitError("affine map expr parse impl incomplete/unexpected token");
612 return nullptr;
613 }
614 }
615 }
616 if (!state.topAffineExpr()) {
617 // An error will be emitted by parse comma separated list on an empty list
618 return nullptr;
619 }
620 return state.topAffineExpr();
621}
622
623// Return empty string if no bare id was found
624StringRef Parser::parseDimOrSymbolId(SmallVectorImpl<StringRef> &dims,
625 SmallVectorImpl<StringRef> &symbols,
626 bool symbol = false) {
627 if (curToken.isNot(Token::bare_identifier)) {
628 emitError("expected bare identifier");
629 return StringRef();
630 }
631 // TODO(bondhugula): check whether the id already exists in either
632 // state.symbols or state.dims; report error if it does; otherwise create a
633 // new one.
634 StringRef ref = curToken.getSpelling();
635 consumeToken(Token::bare_identifier);
636 return ref;
637}
638
639ParseResult Parser::parseSymbolIdList(SmallVectorImpl<StringRef> &dims,
640 SmallVectorImpl<StringRef> &symbols) {
641 if (!consumeIf(Token::l_bracket)) return emitError("expected '['");
642
643 auto parseElt = [&]() -> ParseResult {
644 auto elt = parseDimOrSymbolId(dims, symbols, true);
645 // FIXME(bondhugula): assuming dim arg for now
646 if (!elt.empty()) {
647 symbols.push_back(elt);
648 return ParseSuccess;
649 }
650 return ParseFailure;
651 };
652 return parseCommaSeparatedList(Token::r_bracket, parseElt);
653}
654
655// TODO(andy,bondhugula)
656ParseResult Parser::parseDimIdList(SmallVectorImpl<StringRef> &dims,
657 SmallVectorImpl<StringRef> &symbols) {
658 if (!consumeIf(Token::l_paren))
659 return emitError("expected '(' at start of dimensional identifiers list");
660
661 auto parseElt = [&]() -> ParseResult {
662 auto elt = parseDimOrSymbolId(dims, symbols, false);
663 if (!elt.empty()) {
664 dims.push_back(elt);
665 return ParseSuccess;
666 }
667 return ParseFailure;
668 };
669
670 return parseCommaSeparatedList(Token::r_paren, parseElt);
671}
672
673/// Affine map definition.
674///
675/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
676/// ( `size` `(` dim-size (`,` dim-size)* `)` )?
677/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
678///
679AffineMap *Parser::parseAffineMapInline(StringRef mapId) {
680 SmallVector<StringRef, 4> dims;
681 SmallVector<StringRef, 4> symbols;
682
683 // List of dimensional identifiers.
684 if (parseDimIdList(dims, symbols)) return nullptr;
685
686 // Symbols are optional.
687 if (curToken.is(Token::l_bracket)) {
688 if (parseSymbolIdList(dims, symbols)) return nullptr;
689 }
690 if (!consumeIf(Token::arrow)) {
691 emitError("expected '->' or '['");
692 return nullptr;
693 }
694 if (!consumeIf(Token::l_paren)) {
695 emitError("expected '(' at start of affine map range");
696 return nullptr;
697 }
698
699 AffineMapParserState affState(dims, symbols);
700
701 SmallVector<AffineExpr *, 4> exprs;
702 auto parseElt = [&]() -> ParseResult {
703 auto elt = parseAffineExpr(affState);
704 ParseResult res = elt ? ParseSuccess : ParseFailure;
705 exprs.push_back(elt);
706 return res;
707 };
708
709 // Parse a multi-dimensional affine expression (a comma-separated list of 1-d
710 // affine expressions)
711 if (parseCommaSeparatedList(Token::r_paren, parseElt, false)) return nullptr;
712
713 // Parsed a valid affine map
714 auto *affineMap =
715 AffineMap::get(affState.dimCount(), affState.symbolCount(), exprs,
716 context);
717
718 return affineMap;
MLIR Teamf85a6262018-06-27 11:03:08 -0700719}
720
721//===----------------------------------------------------------------------===//
Chris Lattner4c95a502018-06-23 16:03:42 -0700722// Functions
723//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -0700724
Chris Lattnere79379a2018-06-22 10:39:19 -0700725
726/// Parse a function signature, starting with a name and including the parameter
727/// list.
728///
729/// argument-list ::= type (`,` type)* | /*empty*/
730/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
731///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700732ParseResult Parser::parseFunctionSignature(StringRef &name,
733 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700734 if (curToken.isNot(Token::at_identifier))
735 return emitError("expected a function identifier like '@foo'");
736
737 name = curToken.getSpelling().drop_front();
738 consumeToken(Token::at_identifier);
739
740 if (curToken.isNot(Token::l_paren))
741 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -0700742
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700743 SmallVector<Type*, 4> arguments;
744 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700745 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -0700746
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700747 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700748 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700749 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700750 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700751 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700752 }
Chris Lattnerf7e22732018-06-22 22:03:48 -0700753 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -0700754 return ParseSuccess;
755}
756
Chris Lattnere79379a2018-06-22 10:39:19 -0700757/// External function declarations.
758///
759/// ext-func ::= `extfunc` function-signature
760///
761ParseResult Parser::parseExtFunc() {
762 consumeToken(Token::kw_extfunc);
763
764 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700765 FunctionType *type = nullptr;
766 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -0700767 return ParseFailure;
768
769
770 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -0700771 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -0700772 return ParseSuccess;
773}
774
775
Chris Lattner4c95a502018-06-23 16:03:42 -0700776namespace {
777/// This class represents the transient parser state for the internals of a
778/// function as we are parsing it, e.g. the names for basic blocks. It handles
779/// forward references.
780class CFGFunctionParserState {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700781 public:
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700782 CFGFunction *function;
783 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
784
Chris Lattner4c95a502018-06-23 16:03:42 -0700785 CFGFunctionParserState(CFGFunction *function) : function(function) {}
786
787 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700788 /// already exist. The location specified is the point of use, which allows
789 /// us to diagnose references to blocks that are not defined precisely.
790 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
791 auto &blockAndLoc = blocksByName[name];
792 if (!blockAndLoc.first) {
Chris Lattner3a467cc2018-07-01 20:28:00 -0700793 blockAndLoc.first = new BasicBlock();
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700794 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -0700795 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700796 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -0700797 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700798};
799} // end anonymous namespace
800
801
802/// CFG function declarations.
803///
804/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
805///
806ParseResult Parser::parseCFGFunc() {
807 consumeToken(Token::kw_cfgfunc);
808
809 StringRef name;
810 FunctionType *type = nullptr;
811 if (parseFunctionSignature(name, type))
812 return ParseFailure;
813
814 if (!consumeIf(Token::l_brace))
815 return emitError("expected '{' in CFG function");
816
817 // Okay, the CFG function signature was parsed correctly, create the function.
818 auto function = new CFGFunction(name, type);
819
820 // Make sure we have at least one block.
821 if (curToken.is(Token::r_brace))
822 return emitError("CFG functions must have at least one basic block");
823
824 CFGFunctionParserState functionState(function);
825
826 // Parse the list of blocks.
827 while (!consumeIf(Token::r_brace))
828 if (parseBasicBlock(functionState))
829 return ParseFailure;
830
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700831 // Verify that all referenced blocks were defined. Iteration over a
832 // StringMap isn't determinstic, but this is good enough for our purposes.
833 for (auto &elt : functionState.blocksByName) {
834 auto *bb = elt.second.first;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700835 if (!bb->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700836 return emitError(elt.second.second,
837 "reference to an undefined basic block '" +
838 elt.first() + "'");
839 }
840
Chris Lattner4c95a502018-06-23 16:03:42 -0700841 module->functionList.push_back(function);
842 return ParseSuccess;
843}
844
845/// Basic block declaration.
846///
847/// basic-block ::= bb-label instruction* terminator-stmt
848/// bb-label ::= bb-id bb-arg-list? `:`
849/// bb-id ::= bare-id
850/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
851///
852ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
853 SMLoc nameLoc = curToken.getLoc();
854 auto name = curToken.getSpelling();
855 if (!consumeIf(Token::bare_identifier))
856 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700857
858 auto block = functionState.getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -0700859
860 // If this block has already been parsed, then this is a redefinition with the
861 // same block name.
Chris Lattner3a467cc2018-07-01 20:28:00 -0700862 if (block->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700863 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
864
Chris Lattner3a467cc2018-07-01 20:28:00 -0700865 // Add the block to the function.
866 functionState.function->push_back(block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700867
868 // TODO: parse bb argument list.
869
870 if (!consumeIf(Token::colon))
871 return emitError("expected ':' after basic block name");
872
Chris Lattnered65a732018-06-28 20:45:33 -0700873 // Parse the list of operations that make up the body of the block.
874 while (curToken.isNot(Token::kw_return, Token::kw_br)) {
Chris Lattner3a467cc2018-07-01 20:28:00 -0700875 auto *inst = parseCFGOperation(functionState);
876 if (!inst)
Chris Lattnered65a732018-06-28 20:45:33 -0700877 return ParseFailure;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700878
879 block->getOperations().push_back(inst);
Chris Lattnered65a732018-06-28 20:45:33 -0700880 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700881
Chris Lattner3a467cc2018-07-01 20:28:00 -0700882 auto *term = parseTerminator(functionState);
883 if (!term)
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700884 return ParseFailure;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700885 block->setTerminator(term);
Chris Lattner4c95a502018-06-23 16:03:42 -0700886
887 return ParseSuccess;
888}
889
890
Chris Lattnered65a732018-06-28 20:45:33 -0700891/// Parse the CFG operation.
892///
893/// TODO(clattner): This is a change from the MLIR spec as written, it is an
894/// experiment that will eliminate "builtin" instructions as a thing.
895///
896/// cfg-operation ::=
897/// (ssa-id `=`)? string '(' ssa-use-list? ')' attribute-dict?
898/// `:` function-type
899///
Chris Lattner3a467cc2018-07-01 20:28:00 -0700900OperationInst *Parser::
901parseCFGOperation(CFGFunctionParserState &functionState) {
Chris Lattnered65a732018-06-28 20:45:33 -0700902
903 // TODO: parse ssa-id.
904
905 if (curToken.isNot(Token::string))
Chris Lattner3a467cc2018-07-01 20:28:00 -0700906 return (emitError("expected operation name in quotes"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -0700907
908 auto name = curToken.getStringValue();
909 if (name.empty())
Chris Lattner3a467cc2018-07-01 20:28:00 -0700910 return (emitError("empty operation name is invalid"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -0700911
912 consumeToken(Token::string);
913
914 if (!consumeIf(Token::l_paren))
Chris Lattner3a467cc2018-07-01 20:28:00 -0700915 return (emitError("expected '(' in operation"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -0700916
917 // TODO: Parse operands.
918 if (!consumeIf(Token::r_paren))
Chris Lattner3a467cc2018-07-01 20:28:00 -0700919 return (emitError("expected '(' in operation"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -0700920
921 auto nameId = Identifier::get(name, context);
Chris Lattner3a467cc2018-07-01 20:28:00 -0700922 return new OperationInst(nameId);
Chris Lattnered65a732018-06-28 20:45:33 -0700923}
924
925
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700926/// Parse the terminator instruction for a basic block.
927///
928/// terminator-stmt ::= `br` bb-id branch-use-list?
929/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
930/// terminator-stmt ::=
931/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
932/// terminator-stmt ::= `return` ssa-use-and-type-list?
933///
Chris Lattner3a467cc2018-07-01 20:28:00 -0700934TerminatorInst *Parser::parseTerminator(CFGFunctionParserState &functionState) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700935 switch (curToken.getKind()) {
936 default:
Chris Lattner3a467cc2018-07-01 20:28:00 -0700937 return (emitError("expected terminator at end of basic block"), nullptr);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700938
939 case Token::kw_return:
940 consumeToken(Token::kw_return);
Chris Lattner3a467cc2018-07-01 20:28:00 -0700941 return new ReturnInst();
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700942
943 case Token::kw_br: {
944 consumeToken(Token::kw_br);
945 auto destBB = functionState.getBlockNamed(curToken.getSpelling(),
946 curToken.getLoc());
947 if (!consumeIf(Token::bare_identifier))
Chris Lattner3a467cc2018-07-01 20:28:00 -0700948 return (emitError("expected basic block name"), nullptr);
949 return new BranchInst(destBB);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700950 }
951 }
952}
953
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700954/// ML function declarations.
955///
956/// ml-func ::= `mlfunc` ml-func-signature `{` ml-stmt* ml-return-stmt `}`
957///
958ParseResult Parser::parseMLFunc() {
959 consumeToken(Token::kw_mlfunc);
960
961 StringRef name;
962 FunctionType *type = nullptr;
963
964 // FIXME: Parse ML function signature (args + types)
965 // by passing pointer to SmallVector<identifier> into parseFunctionSignature
966 if (parseFunctionSignature(name, type))
967 return ParseFailure;
968
969 if (!consumeIf(Token::l_brace))
970 return emitError("expected '{' in ML function");
971
972 // Okay, the ML function signature was parsed correctly, create the function.
973 auto function = new MLFunction(name, type);
974
975 // Make sure we have at least one statement.
976 if (curToken.is(Token::r_brace))
977 return emitError("ML function must end with return statement");
978
979 // Parse the list of instructions.
980 while (!consumeIf(Token::kw_return)) {
981 auto *stmt = parseMLStatement(function);
982 if (!stmt)
983 return ParseFailure;
984 function->stmtList.push_back(stmt);
985 }
986
987 // TODO: parse return statement operands
988 if (!consumeIf(Token::r_brace))
989 emitError("expected '}' in ML function");
990
991 module->functionList.push_back(function);
992
993 return ParseSuccess;
994}
995
996/// Parse an MLStatement
997/// TODO
998///
999MLStatement *Parser::parseMLStatement(MLFunction *currentFunction) {
1000 switch (curToken.getKind()) {
1001 default:
1002 return (emitError("expected ML statement"), nullptr);
1003
1004 // TODO: add parsing of ML statements
1005 }
1006}
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001007
Chris Lattner4c95a502018-06-23 16:03:42 -07001008//===----------------------------------------------------------------------===//
1009// Top-level entity parsing.
1010//===----------------------------------------------------------------------===//
1011
Chris Lattnere79379a2018-06-22 10:39:19 -07001012/// This is the top-level module parser.
1013Module *Parser::parseModule() {
1014 while (1) {
1015 switch (curToken.getKind()) {
1016 default:
1017 emitError("expected a top level entity");
1018 return nullptr;
1019
1020 // If we got to the end of the file, then we're done.
1021 case Token::eof:
1022 return module.release();
1023
1024 // If we got an error token, then the lexer already emitted an error, just
1025 // stop. Someday we could introduce error recovery if there was demand for
1026 // it.
1027 case Token::error:
1028 return nullptr;
1029
1030 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -07001031 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -07001032 break;
1033
Chris Lattner4c95a502018-06-23 16:03:42 -07001034 case Token::kw_cfgfunc:
1035 if (parseCFGFunc()) return nullptr;
1036 break;
Chris Lattner8da0c282018-06-29 11:15:56 -07001037 case Token::affine_map_identifier:
MLIR Teamf85a6262018-06-27 11:03:08 -07001038 if (parseAffineMapDef()) return nullptr;
1039 break;
Chris Lattner4c95a502018-06-23 16:03:42 -07001040
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001041 case Token::kw_mlfunc:
1042 if (parseMLFunc()) return nullptr;
1043 break;
1044
1045 // TODO: affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -07001046 }
1047 }
1048}
1049
1050//===----------------------------------------------------------------------===//
1051
1052/// This parses the file specified by the indicated SourceMgr and returns an
1053/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Jacques Pienaar9c411be2018-06-24 19:17:35 -07001054Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context,
1055 const SMDiagnosticHandlerTy &errorReporter) {
1056 return Parser(sourceMgr, context, errorReporter).parseModule();
Chris Lattnere79379a2018-06-22 10:39:19 -07001057}
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001058