blob: f9849a7dbd7fce402b147623b5d53c7efde490d7 [file] [log] [blame]
Chris Lattnere79379a2018-06-22 10:39:19 -07001//===- Parser.cpp - MLIR Parser Implementation ----------------------------===//
2//
3// Copyright 2019 The MLIR Authors.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16// =============================================================================
17//
18// This file implements the parser for the MLIR textual form.
19//
20//===----------------------------------------------------------------------===//
21
22#include "mlir/Parser.h"
23#include "Lexer.h"
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070024#include "mlir/IR/AffineExpr.h"
MLIR Teamf85a6262018-06-27 11:03:08 -070025#include "mlir/IR/AffineMap.h"
Chris Lattner7121b802018-07-04 20:45:39 -070026#include "mlir/IR/Attributes.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070027#include "mlir/IR/CFGFunction.h"
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -070028#include "mlir/IR/MLFunction.h"
Chris Lattner21e67f62018-07-06 10:46:19 -070029#include "mlir/IR/Module.h"
30#include "mlir/IR/OperationSet.h"
Chris Lattnerf7e22732018-06-22 22:03:48 -070031#include "mlir/IR/Types.h"
Chris Lattnere79379a2018-06-22 10:39:19 -070032#include "llvm/Support/SourceMgr.h"
33using namespace mlir;
34using llvm::SourceMgr;
Chris Lattner4c95a502018-06-23 16:03:42 -070035using llvm::SMLoc;
Chris Lattnere79379a2018-06-22 10:39:19 -070036
37namespace {
Chris Lattner4c95a502018-06-23 16:03:42 -070038class CFGFunctionParserState;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070039class AffineMapParserState;
Chris Lattner4c95a502018-06-23 16:03:42 -070040
Chris Lattnerf7e22732018-06-22 22:03:48 -070041/// Simple enum to make code read better in cases that would otherwise return a
42/// bool value. Failure is "true" in a boolean context.
Chris Lattnere79379a2018-06-22 10:39:19 -070043enum ParseResult {
44 ParseSuccess,
45 ParseFailure
46};
47
Uday Bondhugula015cbb12018-07-03 20:16:08 -070048/// Lower precedence ops (all at the same precedence level). LNoOp is false in
49/// the boolean sense.
50enum AffineLowPrecOp {
51 /// Null value.
52 LNoOp,
53 Add,
54 Sub
55};
56
57/// Higher precedence ops - all at the same precedence level. HNoOp is false in
58/// the boolean sense.
59enum AffineHighPrecOp {
60 /// Null value.
61 HNoOp,
62 Mul,
63 FloorDiv,
64 CeilDiv,
65 Mod
66};
67
Chris Lattnere79379a2018-06-22 10:39:19 -070068/// Main parser implementation.
69class Parser {
Chris Lattnered65a732018-06-28 20:45:33 -070070public:
Jacques Pienaar9c411be2018-06-24 19:17:35 -070071 Parser(llvm::SourceMgr &sourceMgr, MLIRContext *context,
Jacques Pienaar7b829702018-07-03 13:24:09 -070072 SMDiagnosticHandlerTy errorReporter)
73 : context(context), lex(sourceMgr, errorReporter),
74 curToken(lex.lexToken()), errorReporter(std::move(errorReporter)) {
Chris Lattnere79379a2018-06-22 10:39:19 -070075 module.reset(new Module());
76 }
77
78 Module *parseModule();
79private:
80 // State.
Chris Lattnerf7e22732018-06-22 22:03:48 -070081 MLIRContext *const context;
82
83 // The lexer for the source file we're parsing.
Chris Lattnere79379a2018-06-22 10:39:19 -070084 Lexer lex;
85
86 // This is the next token that hasn't been consumed yet.
87 Token curToken;
88
Jacques Pienaar9c411be2018-06-24 19:17:35 -070089 // The diagnostic error reporter.
Jacques Pienaar7b829702018-07-03 13:24:09 -070090 SMDiagnosticHandlerTy errorReporter;
Jacques Pienaar9c411be2018-06-24 19:17:35 -070091
Chris Lattnere79379a2018-06-22 10:39:19 -070092 // This is the result module we are parsing into.
93 std::unique_ptr<Module> module;
94
MLIR Teamf85a6262018-06-27 11:03:08 -070095 // A map from affine map identifier to AffineMap.
Chris Lattner7121b802018-07-04 20:45:39 -070096 llvm::StringMap<AffineMap*> affineMapDefinitions;
MLIR Teamf85a6262018-06-27 11:03:08 -070097
Chris Lattnere79379a2018-06-22 10:39:19 -070098private:
99 // Helper methods.
100
101 /// Emit an error and return failure.
Chris Lattner4c95a502018-06-23 16:03:42 -0700102 ParseResult emitError(const Twine &message) {
103 return emitError(curToken.getLoc(), message);
104 }
105 ParseResult emitError(SMLoc loc, const Twine &message);
Chris Lattnere79379a2018-06-22 10:39:19 -0700106
107 /// Advance the current lexer onto the next token.
108 void consumeToken() {
109 assert(curToken.isNot(Token::eof, Token::error) &&
110 "shouldn't advance past EOF or errors");
111 curToken = lex.lexToken();
112 }
113
114 /// Advance the current lexer onto the next token, asserting what the expected
115 /// current token is. This is preferred to the above method because it leads
116 /// to more self-documenting code with better checking.
Chris Lattner8da0c282018-06-29 11:15:56 -0700117 void consumeToken(Token::Kind kind) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700118 assert(curToken.is(kind) && "consumed an unexpected token");
119 consumeToken();
120 }
121
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700122 /// If the current token has the specified kind, consume it and return true.
123 /// If not, return false.
Chris Lattner8da0c282018-06-29 11:15:56 -0700124 bool consumeIf(Token::Kind kind) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700125 if (curToken.isNot(kind))
126 return false;
127 consumeToken(kind);
128 return true;
129 }
130
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700131 // Binary affine op parsing
132 AffineLowPrecOp consumeIfLowPrecOp();
133 AffineHighPrecOp consumeIfHighPrecOp();
134
Chris Lattner8da0c282018-06-29 11:15:56 -0700135 ParseResult parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700136 const std::function<ParseResult()> &parseElement,
137 bool allowEmptyList = true);
138
Chris Lattnerf7e22732018-06-22 22:03:48 -0700139 // We have two forms of parsing methods - those that return a non-null
140 // pointer on success, and those that return a ParseResult to indicate whether
141 // they returned a failure. The second class fills in by-reference arguments
142 // as the results of their action.
143
Chris Lattnere79379a2018-06-22 10:39:19 -0700144 // Type parsing.
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700145 Type *parsePrimitiveType();
Chris Lattnerf7e22732018-06-22 22:03:48 -0700146 Type *parseElementType();
147 VectorType *parseVectorType();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700148 ParseResult parseDimensionListRanked(SmallVectorImpl<int> &dimensions);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700149 Type *parseTensorType();
150 Type *parseMemRefType();
151 Type *parseFunctionType();
152 Type *parseType();
153 ParseResult parseTypeList(SmallVectorImpl<Type*> &elements);
Chris Lattnere79379a2018-06-22 10:39:19 -0700154
Chris Lattner7121b802018-07-04 20:45:39 -0700155 // Attribute parsing.
156 Attribute *parseAttribute();
157 ParseResult parseAttributeDict(SmallVectorImpl<NamedAttribute> &attributes);
158
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700159 // Parsing identifiers' lists for polyhedral structures.
160 ParseResult parseDimIdList(AffineMapParserState &state);
161 ParseResult parseSymbolIdList(AffineMapParserState &state);
162 ParseResult parseDimOrSymbolId(AffineMapParserState &state, bool dim);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700163
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700164 // Polyhedral structures.
MLIR Teamf85a6262018-06-27 11:03:08 -0700165 ParseResult parseAffineMapDef();
Chris Lattner7121b802018-07-04 20:45:39 -0700166 AffineMap *parseAffineMapInline(StringRef mapId);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700167 AffineExpr *parseAffineExpr(const AffineMapParserState &state);
168
169 AffineExpr *parseParentheticalExpr(const AffineMapParserState &state);
170 AffineExpr *parseIntegerExpr(const AffineMapParserState &state);
171 AffineExpr *parseBareIdExpr(const AffineMapParserState &state);
172
173 static AffineBinaryOpExpr *getBinaryAffineOpExpr(AffineHighPrecOp op,
174 AffineExpr *lhs,
175 AffineExpr *rhs,
176 MLIRContext *context);
177 static AffineBinaryOpExpr *getBinaryAffineOpExpr(AffineLowPrecOp op,
178 AffineExpr *lhs,
179 AffineExpr *rhs,
180 MLIRContext *context);
181 ParseResult parseAffineOperandExpr(const AffineMapParserState &state,
182 AffineExpr *&result);
183 ParseResult parseAffineLowPrecOpExpr(AffineExpr *llhs, AffineLowPrecOp llhsOp,
184 const AffineMapParserState &state,
185 AffineExpr *&result);
186 ParseResult parseAffineHighPrecOpExpr(AffineExpr *llhs,
187 AffineHighPrecOp llhsOp,
188 const AffineMapParserState &state,
189 AffineExpr *&result);
MLIR Teamf85a6262018-06-27 11:03:08 -0700190
Chris Lattner4c95a502018-06-23 16:03:42 -0700191 // Functions.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700192 ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
Chris Lattnere79379a2018-06-22 10:39:19 -0700193 ParseResult parseExtFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700194 ParseResult parseCFGFunc();
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700195 ParseResult parseMLFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700196 ParseResult parseBasicBlock(CFGFunctionParserState &functionState);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700197 Statement *parseStatement(ParentType parent);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700198
Chris Lattner3a467cc2018-07-01 20:28:00 -0700199 OperationInst *parseCFGOperation(CFGFunctionParserState &functionState);
200 TerminatorInst *parseTerminator(CFGFunctionParserState &functionState);
Chris Lattnered65a732018-06-28 20:45:33 -0700201
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700202 ForStmt *parseForStmt(ParentType parent);
203 IfStmt *parseIfStmt(ParentType parent);
204 ParseResult parseNestedStatements(NodeStmt *parent);
Chris Lattnere79379a2018-06-22 10:39:19 -0700205};
206} // end anonymous namespace
207
208//===----------------------------------------------------------------------===//
209// Helper methods.
210//===----------------------------------------------------------------------===//
211
Chris Lattner4c95a502018-06-23 16:03:42 -0700212ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700213 // If we hit a parse error in response to a lexer error, then the lexer
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700214 // already reported the error.
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700215 if (curToken.is(Token::error))
216 return ParseFailure;
217
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700218 errorReporter(
219 lex.getSourceMgr().GetMessage(loc, SourceMgr::DK_Error, message));
Chris Lattnere79379a2018-06-22 10:39:19 -0700220 return ParseFailure;
221}
222
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700223/// Parse a comma-separated list of elements, terminated with an arbitrary
224/// token. This allows empty lists if allowEmptyList is true.
225///
226/// abstract-list ::= rightToken // if allowEmptyList == true
227/// abstract-list ::= element (',' element)* rightToken
228///
229ParseResult Parser::
Chris Lattner8da0c282018-06-29 11:15:56 -0700230parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700231 const std::function<ParseResult()> &parseElement,
232 bool allowEmptyList) {
233 // Handle the empty case.
234 if (curToken.is(rightToken)) {
235 if (!allowEmptyList)
236 return emitError("expected list element");
237 consumeToken(rightToken);
238 return ParseSuccess;
239 }
240
241 // Non-empty case starts with an element.
242 if (parseElement())
243 return ParseFailure;
244
245 // Otherwise we have a list of comma separated elements.
246 while (consumeIf(Token::comma)) {
247 if (parseElement())
248 return ParseFailure;
249 }
250
251 // Consume the end character.
252 if (!consumeIf(rightToken))
Chris Lattner8da0c282018-06-29 11:15:56 -0700253 return emitError("expected ',' or '" + Token::getTokenSpelling(rightToken) +
254 "'");
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700255
256 return ParseSuccess;
257}
Chris Lattnere79379a2018-06-22 10:39:19 -0700258
259//===----------------------------------------------------------------------===//
260// Type Parsing
261//===----------------------------------------------------------------------===//
262
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700263/// Parse the low-level fixed dtypes in the system.
264///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700265/// primitive-type ::= `f16` | `bf16` | `f32` | `f64`
266/// primitive-type ::= integer-type
267/// primitive-type ::= `affineint`
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700268///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700269Type *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700270 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700271 default:
272 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700273 case Token::kw_bf16:
274 consumeToken(Token::kw_bf16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700275 return Type::getBF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700276 case Token::kw_f16:
277 consumeToken(Token::kw_f16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700278 return Type::getF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700279 case Token::kw_f32:
280 consumeToken(Token::kw_f32);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700281 return Type::getF32(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700282 case Token::kw_f64:
283 consumeToken(Token::kw_f64);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700284 return Type::getF64(context);
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700285 case Token::kw_affineint:
286 consumeToken(Token::kw_affineint);
287 return Type::getAffineInt(context);
288 case Token::inttype: {
289 auto width = curToken.getIntTypeBitwidth();
290 if (!width.hasValue())
291 return (emitError("invalid integer width"), nullptr);
292 consumeToken(Token::inttype);
293 return Type::getInt(width.getValue(), context);
294 }
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700295 }
296}
297
298/// Parse the element type of a tensor or memref type.
299///
300/// element-type ::= primitive-type | vector-type
301///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700302Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700303 if (curToken.is(Token::kw_vector))
304 return parseVectorType();
305
306 return parsePrimitiveType();
307}
308
309/// Parse a vector type.
310///
311/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
312/// const-dimension-list ::= (integer-literal `x`)+
313///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700314VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700315 consumeToken(Token::kw_vector);
316
317 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700318 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700319
320 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700321 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700322
323 SmallVector<unsigned, 4> dimensions;
324 while (curToken.is(Token::integer)) {
325 // Make sure this integer value is in bound and valid.
326 auto dimension = curToken.getUnsignedIntegerValue();
327 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700328 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700329 dimensions.push_back(dimension.getValue());
330
331 consumeToken(Token::integer);
332
333 // Make sure we have an 'x' or something like 'xbf32'.
334 if (curToken.isNot(Token::bare_identifier) ||
335 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700336 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700337
338 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
339 if (curToken.getSpelling().size() != 1)
340 lex.resetPointer(curToken.getSpelling().data()+1);
341
342 // Consume the 'x'.
343 consumeToken(Token::bare_identifier);
344 }
345
346 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700347 auto *elementType = parsePrimitiveType();
348 if (!elementType)
349 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700350
351 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700352 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700353
Chris Lattnerf7e22732018-06-22 22:03:48 -0700354 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700355}
356
357/// Parse a dimension list of a tensor or memref type. This populates the
358/// dimension list, returning -1 for the '?' dimensions.
359///
360/// dimension-list-ranked ::= (dimension `x`)*
361/// dimension ::= `?` | integer-literal
362///
363ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
364 while (curToken.isAny(Token::integer, Token::question)) {
365 if (consumeIf(Token::question)) {
366 dimensions.push_back(-1);
367 } else {
368 // Make sure this integer value is in bound and valid.
369 auto dimension = curToken.getUnsignedIntegerValue();
370 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
371 return emitError("invalid dimension");
372 dimensions.push_back((int)dimension.getValue());
373 consumeToken(Token::integer);
374 }
375
376 // Make sure we have an 'x' or something like 'xbf32'.
377 if (curToken.isNot(Token::bare_identifier) ||
378 curToken.getSpelling()[0] != 'x')
379 return emitError("expected 'x' in dimension list");
380
381 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
382 if (curToken.getSpelling().size() != 1)
383 lex.resetPointer(curToken.getSpelling().data()+1);
384
385 // Consume the 'x'.
386 consumeToken(Token::bare_identifier);
387 }
388
389 return ParseSuccess;
390}
391
392/// Parse a tensor type.
393///
394/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
395/// dimension-list ::= dimension-list-ranked | `??`
396///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700397Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700398 consumeToken(Token::kw_tensor);
399
400 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700401 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700402
403 bool isUnranked;
404 SmallVector<int, 4> dimensions;
405
406 if (consumeIf(Token::questionquestion)) {
407 isUnranked = true;
408 } else {
409 isUnranked = false;
410 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700411 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700412 }
413
414 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700415 auto elementType = parseElementType();
416 if (!elementType)
417 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700418
419 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700420 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700421
MLIR Team355ec862018-06-23 18:09:09 -0700422 if (isUnranked)
423 return UnrankedTensorType::get(elementType);
424 return RankedTensorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700425}
426
427/// Parse a memref type.
428///
429/// memref-type ::= `memref` `<` dimension-list-ranked element-type
430/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
431///
432/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
433/// memory-space ::= integer-literal /* | TODO: address-space-id */
434///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700435Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700436 consumeToken(Token::kw_memref);
437
438 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700439 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700440
441 SmallVector<int, 4> dimensions;
442 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700443 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700444
445 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700446 auto elementType = parseElementType();
447 if (!elementType)
448 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700449
450 // TODO: Parse semi-affine-map-composition.
451 // TODO: Parse memory-space.
452
453 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700454 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700455
Chris Lattnerf7e22732018-06-22 22:03:48 -0700456 // FIXME: Add an IR representation for memref types.
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700457 return Type::getInt(1, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700458}
459
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700460/// Parse a function type.
461///
462/// function-type ::= type-list-parens `->` type-list
463///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700464Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700465 assert(curToken.is(Token::l_paren));
466
Chris Lattnerf7e22732018-06-22 22:03:48 -0700467 SmallVector<Type*, 4> arguments;
468 if (parseTypeList(arguments))
469 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700470
471 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700472 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700473
Chris Lattnerf7e22732018-06-22 22:03:48 -0700474 SmallVector<Type*, 4> results;
475 if (parseTypeList(results))
476 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700477
Chris Lattnerf7e22732018-06-22 22:03:48 -0700478 return FunctionType::get(arguments, results, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700479}
480
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700481/// Parse an arbitrary type.
482///
483/// type ::= primitive-type
484/// | vector-type
485/// | tensor-type
486/// | memref-type
487/// | function-type
488/// element-type ::= primitive-type | vector-type
489///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700490Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700491 switch (curToken.getKind()) {
492 case Token::kw_memref: return parseMemRefType();
493 case Token::kw_tensor: return parseTensorType();
494 case Token::kw_vector: return parseVectorType();
495 case Token::l_paren: return parseFunctionType();
496 default:
497 return parsePrimitiveType();
498 }
499}
500
501/// Parse a "type list", which is a singular type, or a parenthesized list of
502/// types.
503///
504/// type-list ::= type-list-parens | type
505/// type-list-parens ::= `(` `)`
506/// | `(` type (`,` type)* `)`
507///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700508ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
509 auto parseElt = [&]() -> ParseResult {
510 auto elt = parseType();
511 elements.push_back(elt);
512 return elt ? ParseSuccess : ParseFailure;
513 };
514
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700515 // If there is no parens, then it must be a singular type.
516 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700517 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700518
Chris Lattnerf7e22732018-06-22 22:03:48 -0700519 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700520 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700521
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700522 return ParseSuccess;
523}
524
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700525namespace {
526/// This class represents the transient parser state while parsing an affine
527/// expression.
528class AffineMapParserState {
529 public:
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700530 explicit AffineMapParserState() {}
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700531
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700532 void addDim(StringRef sRef) { dims.insert({sRef, dims.size()}); }
533 void addSymbol(StringRef sRef) { symbols.insert({sRef, symbols.size()}); }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700534
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700535 unsigned getNumDims() const { return dims.size(); }
536 unsigned getNumSymbols() const { return symbols.size(); }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700537
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700538 // TODO(bondhugula): could just use an vector/ArrayRef and scan the numbers.
539 const llvm::StringMap<unsigned> &getDims() const { return dims; }
540 const llvm::StringMap<unsigned> &getSymbols() const { return symbols; }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700541
542 private:
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700543 llvm::StringMap<unsigned> dims;
544 llvm::StringMap<unsigned> symbols;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700545};
546} // end anonymous namespace
547
Chris Lattner4c95a502018-06-23 16:03:42 -0700548//===----------------------------------------------------------------------===//
Chris Lattner7121b802018-07-04 20:45:39 -0700549// Attribute parsing.
550//===----------------------------------------------------------------------===//
551
552
553/// Attribute parsing.
554///
555/// attribute-value ::= bool-literal
556/// | integer-literal
557/// | float-literal
558/// | string-literal
559/// | `[` (attribute-value (`,` attribute-value)*)? `]`
560///
561Attribute *Parser::parseAttribute() {
562 switch (curToken.getKind()) {
563 case Token::kw_true:
564 consumeToken(Token::kw_true);
565 return BoolAttr::get(true, context);
566 case Token::kw_false:
567 consumeToken(Token::kw_false);
568 return BoolAttr::get(false, context);
569
570 case Token::integer: {
571 auto val = curToken.getUInt64IntegerValue();
572 if (!val.hasValue() || (int64_t)val.getValue() < 0)
573 return (emitError("integer too large for attribute"), nullptr);
574 consumeToken(Token::integer);
575 return IntegerAttr::get((int64_t)val.getValue(), context);
576 }
577
578 case Token::minus: {
579 consumeToken(Token::minus);
580 if (curToken.is(Token::integer)) {
581 auto val = curToken.getUInt64IntegerValue();
582 if (!val.hasValue() || (int64_t)-val.getValue() >= 0)
583 return (emitError("integer too large for attribute"), nullptr);
584 consumeToken(Token::integer);
585 return IntegerAttr::get((int64_t)-val.getValue(), context);
586 }
587
588 return (emitError("expected constant integer or floating point value"),
589 nullptr);
590 }
591
592 case Token::string: {
593 auto val = curToken.getStringValue();
594 consumeToken(Token::string);
595 return StringAttr::get(val, context);
596 }
597
598 case Token::l_bracket: {
599 consumeToken(Token::l_bracket);
600 SmallVector<Attribute*, 4> elements;
601
602 auto parseElt = [&]() -> ParseResult {
603 elements.push_back(parseAttribute());
604 return elements.back() ? ParseSuccess : ParseFailure;
605 };
606
607 if (parseCommaSeparatedList(Token::r_bracket, parseElt))
608 return nullptr;
609 return ArrayAttr::get(elements, context);
610 }
611 default:
612 // TODO: Handle floating point.
613 return (emitError("expected constant attribute value"), nullptr);
614 }
615}
616
617
618/// Attribute dictionary.
619///
620/// attribute-dict ::= `{` `}`
621/// | `{` attribute-entry (`,` attribute-entry)* `}`
622/// attribute-entry ::= bare-id `:` attribute-value
623///
624ParseResult Parser::parseAttributeDict(
625 SmallVectorImpl<NamedAttribute> &attributes) {
626 consumeToken(Token::l_brace);
627
628 auto parseElt = [&]() -> ParseResult {
629 // We allow keywords as attribute names.
630 if (curToken.isNot(Token::bare_identifier, Token::inttype) &&
631 !curToken.isKeyword())
632 return emitError("expected attribute name");
633 auto nameId = Identifier::get(curToken.getSpelling(), context);
634 consumeToken();
635
636 if (!consumeIf(Token::colon))
637 return emitError("expected ':' in attribute list");
638
639 auto attr = parseAttribute();
640 if (!attr) return ParseFailure;
641
642 attributes.push_back({nameId, attr});
643 return ParseSuccess;
644 };
645
646 if (parseCommaSeparatedList(Token::r_brace, parseElt))
647 return ParseFailure;
648
649 return ParseSuccess;
650}
651
652//===----------------------------------------------------------------------===//
MLIR Teamf85a6262018-06-27 11:03:08 -0700653// Polyhedral structures.
654//===----------------------------------------------------------------------===//
655
656/// Affine map declaration.
657///
658/// affine-map-def ::= affine-map-id `=` affine-map-inline
MLIR Teamf85a6262018-06-27 11:03:08 -0700659///
660ParseResult Parser::parseAffineMapDef() {
Chris Lattner8da0c282018-06-29 11:15:56 -0700661 assert(curToken.is(Token::affine_map_identifier));
MLIR Teamf85a6262018-06-27 11:03:08 -0700662
663 StringRef affineMapId = curToken.getSpelling().drop_front();
Chris Lattner7121b802018-07-04 20:45:39 -0700664
665 // Check for redefinitions.
666 auto *&entry = affineMapDefinitions[affineMapId];
667 if (entry)
668 return emitError("redefinition of affine map id '" + affineMapId + "'");
669
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700670 consumeToken(Token::affine_map_identifier);
671
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700672 // Parse the '='
673 if (!consumeIf(Token::equal))
674 return emitError("expected '=' in affine map outlined definition");
MLIR Teamf85a6262018-06-27 11:03:08 -0700675
Chris Lattner7121b802018-07-04 20:45:39 -0700676 entry = parseAffineMapInline(affineMapId);
677 if (!entry)
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700678 return ParseFailure;
MLIR Teamf85a6262018-06-27 11:03:08 -0700679
Chris Lattner7121b802018-07-04 20:45:39 -0700680 module->affineMapList.push_back(entry);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700681 return ParseSuccess;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700682}
683
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700684/// Create an affine op expression
685AffineBinaryOpExpr *Parser::getBinaryAffineOpExpr(AffineHighPrecOp op,
686 AffineExpr *lhs,
687 AffineExpr *rhs,
688 MLIRContext *context) {
689 switch (op) {
690 case Mul:
691 return AffineMulExpr::get(lhs, rhs, context);
692 case FloorDiv:
693 return AffineFloorDivExpr::get(lhs, rhs, context);
694 case CeilDiv:
695 return AffineCeilDivExpr::get(lhs, rhs, context);
696 case Mod:
697 return AffineModExpr::get(lhs, rhs, context);
698 case HNoOp:
699 llvm_unreachable("can't create affine expression for null high prec op");
700 return nullptr;
701 }
702}
703
704AffineBinaryOpExpr *Parser::getBinaryAffineOpExpr(AffineLowPrecOp op,
705 AffineExpr *lhs,
706 AffineExpr *rhs,
707 MLIRContext *context) {
708 switch (op) {
709 case AffineLowPrecOp::Add:
710 return AffineAddExpr::get(lhs, rhs, context);
711 case AffineLowPrecOp::Sub:
712 return AffineSubExpr::get(lhs, rhs, context);
713 case AffineLowPrecOp::LNoOp:
714 llvm_unreachable("can't create affine expression for null low prec op");
715 return nullptr;
716 }
717}
718
719/// Parses an expression that can be a valid operand of an affine expression
720/// (where associativity may not have been specified through parentheses).
721// Eg: for an expression without parentheses (like i + j + k + l), each
722// of the four identifiers is an operand. For: i + j*k + l, j*k is not an
723// operand expression, it's an op expression and will be parsed via
724// parseAffineLowPrecOpExpression().
725ParseResult Parser::parseAffineOperandExpr(const AffineMapParserState &state,
726 AffineExpr *&result) {
727 result = parseParentheticalExpr(state);
728 if (!result)
729 result = parseBareIdExpr(state);
730 if (!result)
731 result = parseIntegerExpr(state);
732 return result ? ParseSuccess : ParseFailure;
733}
734
735/// Parse a high precedence op expression list: mul, div, and mod are high
736/// precedence binary ops, i.e., parse a
737/// expr_1 op_1 expr_2 op_2 ... expr_n
738/// where op_1, op_2 are all a AffineHighPrecOp (mul, div, mod).
739/// All affine binary ops are left associative.
740/// Given llhs, returns (llhs * lhs) * rhs, or (lhs * rhs) if llhs is null. If
741/// no rhs can be found, returns (llhs * lhs) or lhs if llhs is null.
742// TODO(bondhugula): check whether mul is w.r.t. a constant - otherwise, the
743/// map is semi-affine.
744ParseResult Parser::parseAffineHighPrecOpExpr(AffineExpr *llhs,
745 AffineHighPrecOp llhsOp,
746 const AffineMapParserState &state,
747 AffineExpr *&result) {
748 // FIXME: Assume for now that llhsOp is mul.
749 AffineExpr *lhs = nullptr;
750 if (parseAffineOperandExpr(state, lhs)) {
751 return ParseFailure;
752 }
753 AffineHighPrecOp op = HNoOp;
754 // Found an LHS. Parse the remaining expression.
755 if ((op = consumeIfHighPrecOp())) {
756 if (llhs) {
757 // TODO(bondhugula): check whether 'lhs' here is a constant (for affine
758 // maps); semi-affine maps allow symbols.
759 AffineExpr *expr =
760 Parser::getBinaryAffineOpExpr(llhsOp, llhs, lhs, context);
761 AffineExpr *subRes = nullptr;
762 if (parseAffineHighPrecOpExpr(expr, op, state, subRes)) {
763 if (!subRes)
764 emitError("missing right operand of multiply op");
765 // In spite of the error, setting result to prevent duplicate errors
766 // messages as the call stack unwinds. All of this due to left
767 // associativity.
768 result = expr;
769 return ParseFailure;
770 }
771 result = subRes ? subRes : expr;
772 return ParseSuccess;
773 }
774 // No LLHS, get RHS
775 AffineExpr *subRes = nullptr;
776 if (parseAffineHighPrecOpExpr(lhs, op, state, subRes)) {
777 // 'product' needs to be checked to prevent duplicate errors messages as
778 // the call stack unwinds. All of this due to left associativity.
779 if (!subRes)
780 emitError("missing right operand of multiply op");
781 return ParseFailure;
782 }
783 result = subRes;
784 return ParseSuccess;
785 }
786
787 // This is the last operand in this expression.
788 if (llhs) {
789 // TODO(bondhugula): check whether lhs here is a constant (for affine
790 // maps); semi-affine maps allow symbols.
791 result = Parser::getBinaryAffineOpExpr(llhsOp, llhs, lhs, context);
792 return ParseSuccess;
793 }
794
795 // No llhs, 'lhs' itself is the expression.
796 result = lhs;
797 return ParseSuccess;
798}
799
800/// Consume this token if it is a lower precedence affine op (there are only two
801/// precedence levels)
802AffineLowPrecOp Parser::consumeIfLowPrecOp() {
803 switch (curToken.getKind()) {
804 case Token::plus:
805 consumeToken(Token::plus);
806 return AffineLowPrecOp::Add;
807 case Token::minus:
808 consumeToken(Token::minus);
809 return AffineLowPrecOp::Sub;
810 default:
811 return AffineLowPrecOp::LNoOp;
812 }
813}
814
815/// Consume this token if it is a higher precedence affine op (there are only
816/// two precedence levels)
817AffineHighPrecOp Parser::consumeIfHighPrecOp() {
818 switch (curToken.getKind()) {
819 case Token::star:
820 consumeToken(Token::star);
821 return Mul;
822 case Token::kw_floordiv:
823 consumeToken(Token::kw_floordiv);
824 return FloorDiv;
825 case Token::kw_ceildiv:
826 consumeToken(Token::kw_ceildiv);
827 return CeilDiv;
828 case Token::kw_mod:
829 consumeToken(Token::kw_mod);
830 return Mod;
831 default:
832 return HNoOp;
833 }
834}
835
836/// Parse affine expressions that are bare-id's, integer constants,
837/// parenthetical affine expressions, and affine op expressions that are a
838/// composition of those.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700839///
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700840/// All binary op's associate from left to right.
841///
842/// {add, sub} have lower precedence than {mul, div, and mod}.
843///
844/// Add, sub'are themselves at the same precedence level. mul, div, and mod are
845/// at the same higher precedence level.
846///
847/// llhs: the affine expression appearing on the left of the one being parsed.
848/// This function will return ((llhs + lhs) + rhs) if llhs is non null, and
849/// lhs + rhs otherwise; if there is no rhs, llhs + lhs is returned if llhs is
850/// non-null; otherwise lhs is returned. This is to deal with left
851/// associativity.
852///
853/// Eg: when the expression is e1 + e2*e3 + e4, with e1 as llhs, this function
854/// will return the affine expr equivalent of (e1 + (e2*e3)) + e4.
855///
856// TODO(bondhugula): add support for unary op negation. Assuming for now that
857// the op to associate with llhs is add.
858ParseResult Parser::parseAffineLowPrecOpExpr(AffineExpr *llhs,
859 AffineLowPrecOp llhsOp,
860 const AffineMapParserState &state,
861 AffineExpr *&result) {
862 AffineExpr *lhs = nullptr;
863 if (parseAffineOperandExpr(state, lhs))
864 return ParseFailure;
865
866 // Found an LHS. Deal with the ops.
867 AffineLowPrecOp lOp;
868 AffineHighPrecOp rOp;
869 if ((lOp = consumeIfLowPrecOp())) {
870 if (llhs) {
871 AffineExpr *sum =
872 Parser::getBinaryAffineOpExpr(llhsOp, llhs, lhs, context);
873 AffineExpr *recSum = nullptr;
874 parseAffineLowPrecOpExpr(sum, lOp, state, recSum);
875 result = recSum ? recSum : sum;
876 return ParseSuccess;
877 }
878 // No LLHS, get RHS and form the expression.
879 if (parseAffineLowPrecOpExpr(lhs, lOp, state, result)) {
880 if (!result)
881 emitError("missing right operand of add op");
882 return ParseFailure;
883 }
884 return ParseSuccess;
885 } else if ((rOp = consumeIfHighPrecOp())) {
886 // We have a higher precedence op here. Get the rhs operand for the llhs
887 // through parseAffineHighPrecOpExpr.
888 AffineExpr *highRes = nullptr;
889 if (parseAffineHighPrecOpExpr(lhs, rOp, state, highRes)) {
890 // 'product' needs to be checked to prevent duplicate errors messages as
891 // the call stack unwinds. All of this due to left associativity.
892 if (!highRes)
893 emitError("missing right operand of binary op");
894 return ParseFailure;
895 }
896 // If llhs is null, the product forms the first operand of the yet to be
897 // found expression. If non-null, assume for now that the op to associate
898 // with llhs is add.
899 AffineExpr *expr =
900 llhs ? getBinaryAffineOpExpr(llhsOp, llhs, highRes, context) : highRes;
901 // Recurse for subsequent add's after the affine mul expression
902 AffineLowPrecOp nextOp = consumeIfLowPrecOp();
903 if (nextOp) {
904 AffineExpr *sumProd = nullptr;
905 parseAffineLowPrecOpExpr(expr, nextOp, state, sumProd);
906 result = sumProd ? sumProd : expr;
907 } else {
908 result = expr;
909 }
910 return ParseSuccess;
911 } else {
912 // Last operand in the expression list.
913 if (llhs) {
914 result = Parser::getBinaryAffineOpExpr(llhsOp, llhs, lhs, context);
915 return ParseSuccess;
916 }
917 // No llhs, 'lhs' itself is the expression.
918 result = lhs;
919 return ParseSuccess;
920 }
921}
922
923/// Parse an affine expression inside parentheses.
924/// affine-expr ::= `(` affine-expr `)`
925AffineExpr *Parser::parseParentheticalExpr(const AffineMapParserState &state) {
926 if (!consumeIf(Token::l_paren)) {
927 return nullptr;
928 }
929 auto *expr = parseAffineExpr(state);
930 if (!consumeIf(Token::r_paren)) {
931 emitError("expected ')'");
932 return nullptr;
933 }
934 if (!expr)
935 emitError("no expression inside parentheses");
936 return expr;
937}
938
939/// Parse a bare id that may appear in an affine expression.
940/// affine-expr ::= bare-id
941AffineExpr *Parser::parseBareIdExpr(const AffineMapParserState &state) {
942 if (curToken.is(Token::bare_identifier)) {
943 StringRef sRef = curToken.getSpelling();
944 const auto &dims = state.getDims();
945 const auto &symbols = state.getSymbols();
946 if (dims.count(sRef)) {
947 consumeToken(Token::bare_identifier);
948 return AffineDimExpr::get(dims.lookup(sRef), context);
949 }
950 if (symbols.count(sRef)) {
951 consumeToken(Token::bare_identifier);
952 return AffineSymbolExpr::get(symbols.lookup(sRef), context);
953 }
954 return emitError("identifier is neither dimensional nor symbolic"), nullptr;
955 }
956 return nullptr;
957}
958
959/// Parse an integral constant appearing in an affine expression.
960/// affine-expr ::= `-`? integer-literal
961/// TODO(bondhugula): handle negative numbers.
962AffineExpr *Parser::parseIntegerExpr(const AffineMapParserState &state) {
963 if (curToken.is(Token::integer)) {
964 auto *expr = AffineConstantExpr::get(
965 curToken.getUnsignedIntegerValue().getValue(), context);
966 consumeToken(Token::integer);
967 return expr;
968 }
969 return nullptr;
970}
971
972/// Parse an affine expression.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700973/// affine-expr ::= `(` affine-expr `)`
974/// | affine-expr `+` affine-expr
975/// | affine-expr `-` affine-expr
976/// | `-`? integer-literal `*` affine-expr
977/// | `ceildiv` `(` affine-expr `,` integer-literal `)`
978/// | `floordiv` `(` affine-expr `,` integer-literal `)`
979/// | affine-expr `mod` integer-literal
980/// | bare-id
981/// | `-`? integer-literal
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700982/// Use 'state' to check if valid identifiers appear.
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700983// TODO(bondhugula): check if mul, mod, div take integral constants
984AffineExpr *Parser::parseAffineExpr(const AffineMapParserState &state) {
985 switch (curToken.getKind()) {
986 case Token::l_paren:
987 case Token::kw_ceildiv:
988 case Token::kw_floordiv:
989 case Token::bare_identifier:
990 case Token::integer: {
991 AffineExpr *result = nullptr;
992 parseAffineLowPrecOpExpr(nullptr, AffineLowPrecOp::LNoOp, state, result);
993 return result;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700994 }
995
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700996 case Token::plus:
997 case Token::minus:
998 case Token::star:
999 emitError("left operand of binary op missing");
1000 return nullptr;
1001
1002 default:
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001003 return nullptr;
1004 }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001005}
1006
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001007/// Parse a dim or symbol from the lists appearing before the actual expressions
1008/// of the affine map. Update state to store the dimensional/symbolic
1009/// identifier. 'dim': whether it's the dim list or symbol list that is being
1010/// parsed.
1011ParseResult Parser::parseDimOrSymbolId(AffineMapParserState &state, bool dim) {
1012 if (curToken.isNot(Token::bare_identifier))
1013 return emitError("expected bare identifier");
1014 auto sRef = curToken.getSpelling();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001015 consumeToken(Token::bare_identifier);
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001016 if (state.getDims().count(sRef) == 1)
1017 return emitError("dimensional identifier name reused");
1018 if (state.getSymbols().count(sRef) == 1)
1019 return emitError("symbolic identifier name reused");
1020 if (dim)
1021 state.addDim(sRef);
1022 else
1023 state.addSymbol(sRef);
1024 return ParseSuccess;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001025}
1026
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001027/// Parse the list of symbolic identifiers to an affine map.
1028ParseResult Parser::parseSymbolIdList(AffineMapParserState &state) {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001029 if (!consumeIf(Token::l_bracket)) return emitError("expected '['");
1030
1031 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001032 return parseDimOrSymbolId(state, false);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001033 };
1034 return parseCommaSeparatedList(Token::r_bracket, parseElt);
1035}
1036
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001037/// Parse the list of dimensional identifiers to an affine map.
1038ParseResult Parser::parseDimIdList(AffineMapParserState &state) {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001039 if (!consumeIf(Token::l_paren))
1040 return emitError("expected '(' at start of dimensional identifiers list");
1041
1042 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001043 return parseDimOrSymbolId(state, true);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001044 };
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001045 return parseCommaSeparatedList(Token::r_paren, parseElt);
1046}
1047
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001048/// Parse an affine map definition.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001049///
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001050/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001051/// ( `size` `(` dim-size (`,` dim-size)* `)` )?
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001052/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001053///
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001054/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
Chris Lattner7121b802018-07-04 20:45:39 -07001055AffineMap *Parser::parseAffineMapInline(StringRef mapId) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001056 AffineMapParserState state;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001057
1058 // List of dimensional identifiers.
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001059 if (parseDimIdList(state))
Chris Lattner7121b802018-07-04 20:45:39 -07001060 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001061
1062 // Symbols are optional.
1063 if (curToken.is(Token::l_bracket)) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001064 if (parseSymbolIdList(state))
Chris Lattner7121b802018-07-04 20:45:39 -07001065 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001066 }
1067 if (!consumeIf(Token::arrow)) {
Chris Lattner7121b802018-07-04 20:45:39 -07001068 return (emitError("expected '->' or '['"), nullptr);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001069 }
1070 if (!consumeIf(Token::l_paren)) {
1071 emitError("expected '(' at start of affine map range");
Chris Lattner7121b802018-07-04 20:45:39 -07001072 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001073 }
1074
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001075 SmallVector<AffineExpr *, 4> exprs;
1076 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001077 auto *elt = parseAffineExpr(state);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001078 ParseResult res = elt ? ParseSuccess : ParseFailure;
1079 exprs.push_back(elt);
1080 return res;
1081 };
1082
1083 // Parse a multi-dimensional affine expression (a comma-separated list of 1-d
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001084 // affine expressions); the list cannot be empty.
1085 // Grammar: multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
1086 if (parseCommaSeparatedList(Token::r_paren, parseElt, false))
Chris Lattner7121b802018-07-04 20:45:39 -07001087 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001088
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001089 // Parsed a valid affine map.
Chris Lattner7121b802018-07-04 20:45:39 -07001090 return AffineMap::get(state.getNumDims(), state.getNumSymbols(), exprs,
1091 context);
MLIR Teamf85a6262018-06-27 11:03:08 -07001092}
1093
1094//===----------------------------------------------------------------------===//
Chris Lattner4c95a502018-06-23 16:03:42 -07001095// Functions
1096//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -07001097
Chris Lattnere79379a2018-06-22 10:39:19 -07001098
1099/// Parse a function signature, starting with a name and including the parameter
1100/// list.
1101///
1102/// argument-list ::= type (`,` type)* | /*empty*/
1103/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
1104///
Chris Lattnerf7e22732018-06-22 22:03:48 -07001105ParseResult Parser::parseFunctionSignature(StringRef &name,
1106 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -07001107 if (curToken.isNot(Token::at_identifier))
1108 return emitError("expected a function identifier like '@foo'");
1109
1110 name = curToken.getSpelling().drop_front();
1111 consumeToken(Token::at_identifier);
1112
1113 if (curToken.isNot(Token::l_paren))
1114 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -07001115
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001116 SmallVector<Type*, 4> arguments;
1117 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001118 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -07001119
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001120 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -07001121 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001122 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -07001123 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001124 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001125 }
Chris Lattnerf7e22732018-06-22 22:03:48 -07001126 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -07001127 return ParseSuccess;
1128}
1129
Chris Lattnere79379a2018-06-22 10:39:19 -07001130/// External function declarations.
1131///
1132/// ext-func ::= `extfunc` function-signature
1133///
1134ParseResult Parser::parseExtFunc() {
1135 consumeToken(Token::kw_extfunc);
1136
1137 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -07001138 FunctionType *type = nullptr;
1139 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -07001140 return ParseFailure;
1141
Chris Lattnere79379a2018-06-22 10:39:19 -07001142 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -07001143 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -07001144 return ParseSuccess;
1145}
1146
1147
Chris Lattner4c95a502018-06-23 16:03:42 -07001148namespace {
1149/// This class represents the transient parser state for the internals of a
1150/// function as we are parsing it, e.g. the names for basic blocks. It handles
1151/// forward references.
1152class CFGFunctionParserState {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001153 public:
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001154 CFGFunction *function;
1155 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
1156
Chris Lattner4c95a502018-06-23 16:03:42 -07001157 CFGFunctionParserState(CFGFunction *function) : function(function) {}
1158
1159 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001160 /// already exist. The location specified is the point of use, which allows
1161 /// us to diagnose references to blocks that are not defined precisely.
1162 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
1163 auto &blockAndLoc = blocksByName[name];
1164 if (!blockAndLoc.first) {
Chris Lattner3a467cc2018-07-01 20:28:00 -07001165 blockAndLoc.first = new BasicBlock();
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001166 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -07001167 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001168 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -07001169 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001170};
1171} // end anonymous namespace
1172
1173
1174/// CFG function declarations.
1175///
1176/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
1177///
1178ParseResult Parser::parseCFGFunc() {
1179 consumeToken(Token::kw_cfgfunc);
1180
1181 StringRef name;
1182 FunctionType *type = nullptr;
1183 if (parseFunctionSignature(name, type))
1184 return ParseFailure;
1185
1186 if (!consumeIf(Token::l_brace))
1187 return emitError("expected '{' in CFG function");
1188
1189 // Okay, the CFG function signature was parsed correctly, create the function.
1190 auto function = new CFGFunction(name, type);
1191
1192 // Make sure we have at least one block.
1193 if (curToken.is(Token::r_brace))
1194 return emitError("CFG functions must have at least one basic block");
1195
1196 CFGFunctionParserState functionState(function);
1197
1198 // Parse the list of blocks.
1199 while (!consumeIf(Token::r_brace))
1200 if (parseBasicBlock(functionState))
1201 return ParseFailure;
1202
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001203 // Verify that all referenced blocks were defined. Iteration over a
1204 // StringMap isn't determinstic, but this is good enough for our purposes.
1205 for (auto &elt : functionState.blocksByName) {
1206 auto *bb = elt.second.first;
Chris Lattner3a467cc2018-07-01 20:28:00 -07001207 if (!bb->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001208 return emitError(elt.second.second,
1209 "reference to an undefined basic block '" +
1210 elt.first() + "'");
1211 }
1212
Chris Lattner4c95a502018-06-23 16:03:42 -07001213 module->functionList.push_back(function);
1214 return ParseSuccess;
1215}
1216
1217/// Basic block declaration.
1218///
1219/// basic-block ::= bb-label instruction* terminator-stmt
1220/// bb-label ::= bb-id bb-arg-list? `:`
1221/// bb-id ::= bare-id
1222/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
1223///
1224ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
1225 SMLoc nameLoc = curToken.getLoc();
1226 auto name = curToken.getSpelling();
1227 if (!consumeIf(Token::bare_identifier))
1228 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001229
1230 auto block = functionState.getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -07001231
1232 // If this block has already been parsed, then this is a redefinition with the
1233 // same block name.
Chris Lattner3a467cc2018-07-01 20:28:00 -07001234 if (block->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001235 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
1236
Chris Lattner3a467cc2018-07-01 20:28:00 -07001237 // Add the block to the function.
1238 functionState.function->push_back(block);
Chris Lattner4c95a502018-06-23 16:03:42 -07001239
1240 // TODO: parse bb argument list.
1241
1242 if (!consumeIf(Token::colon))
1243 return emitError("expected ':' after basic block name");
1244
Chris Lattnered65a732018-06-28 20:45:33 -07001245 // Parse the list of operations that make up the body of the block.
1246 while (curToken.isNot(Token::kw_return, Token::kw_br)) {
Chris Lattner21e67f62018-07-06 10:46:19 -07001247 auto loc = curToken.getLoc();
Chris Lattner3a467cc2018-07-01 20:28:00 -07001248 auto *inst = parseCFGOperation(functionState);
1249 if (!inst)
Chris Lattnered65a732018-06-28 20:45:33 -07001250 return ParseFailure;
Chris Lattner3a467cc2018-07-01 20:28:00 -07001251
Chris Lattner21e67f62018-07-06 10:46:19 -07001252 // We just parsed an operation. If it is a recognized one, verify that it
1253 // is structurally as we expect. If not, produce an error with a reasonable
1254 // source location.
1255 if (auto *opInfo = inst->getAbstractOperation(context))
1256 if (auto error = opInfo->verifyInvariants(inst))
1257 return emitError(loc, error);
1258
Chris Lattner3a467cc2018-07-01 20:28:00 -07001259 block->getOperations().push_back(inst);
Chris Lattnered65a732018-06-28 20:45:33 -07001260 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001261
Chris Lattner3a467cc2018-07-01 20:28:00 -07001262 auto *term = parseTerminator(functionState);
1263 if (!term)
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001264 return ParseFailure;
Chris Lattner3a467cc2018-07-01 20:28:00 -07001265 block->setTerminator(term);
Chris Lattner4c95a502018-06-23 16:03:42 -07001266
1267 return ParseSuccess;
1268}
1269
1270
Chris Lattnered65a732018-06-28 20:45:33 -07001271/// Parse the CFG operation.
1272///
1273/// TODO(clattner): This is a change from the MLIR spec as written, it is an
1274/// experiment that will eliminate "builtin" instructions as a thing.
1275///
1276/// cfg-operation ::=
1277/// (ssa-id `=`)? string '(' ssa-use-list? ')' attribute-dict?
1278/// `:` function-type
1279///
Chris Lattner3a467cc2018-07-01 20:28:00 -07001280OperationInst *Parser::
1281parseCFGOperation(CFGFunctionParserState &functionState) {
Chris Lattnered65a732018-06-28 20:45:33 -07001282
1283 // TODO: parse ssa-id.
1284
1285 if (curToken.isNot(Token::string))
Chris Lattner3a467cc2018-07-01 20:28:00 -07001286 return (emitError("expected operation name in quotes"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001287
1288 auto name = curToken.getStringValue();
1289 if (name.empty())
Chris Lattner3a467cc2018-07-01 20:28:00 -07001290 return (emitError("empty operation name is invalid"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001291
1292 consumeToken(Token::string);
1293
1294 if (!consumeIf(Token::l_paren))
Chris Lattner7121b802018-07-04 20:45:39 -07001295 return (emitError("expected '(' to start operand list"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001296
1297 // TODO: Parse operands.
1298 if (!consumeIf(Token::r_paren))
Chris Lattner7121b802018-07-04 20:45:39 -07001299 return (emitError("expected ')' in operand list"), nullptr);
1300
1301 SmallVector<NamedAttribute, 4> attributes;
1302 if (curToken.is(Token::l_brace)) {
1303 if (parseAttributeDict(attributes))
1304 return nullptr;
1305 }
Chris Lattnered65a732018-06-28 20:45:33 -07001306
1307 auto nameId = Identifier::get(name, context);
Chris Lattnerdf1a2fc2018-07-05 21:20:59 -07001308 return new OperationInst(nameId, attributes, context);
Chris Lattnered65a732018-06-28 20:45:33 -07001309}
1310
1311
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001312/// Parse the terminator instruction for a basic block.
1313///
1314/// terminator-stmt ::= `br` bb-id branch-use-list?
1315/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
1316/// terminator-stmt ::=
1317/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
1318/// terminator-stmt ::= `return` ssa-use-and-type-list?
1319///
Chris Lattner3a467cc2018-07-01 20:28:00 -07001320TerminatorInst *Parser::parseTerminator(CFGFunctionParserState &functionState) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001321 switch (curToken.getKind()) {
1322 default:
Chris Lattner3a467cc2018-07-01 20:28:00 -07001323 return (emitError("expected terminator at end of basic block"), nullptr);
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001324
1325 case Token::kw_return:
1326 consumeToken(Token::kw_return);
Chris Lattner3a467cc2018-07-01 20:28:00 -07001327 return new ReturnInst();
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001328
1329 case Token::kw_br: {
1330 consumeToken(Token::kw_br);
1331 auto destBB = functionState.getBlockNamed(curToken.getSpelling(),
1332 curToken.getLoc());
1333 if (!consumeIf(Token::bare_identifier))
Chris Lattner3a467cc2018-07-01 20:28:00 -07001334 return (emitError("expected basic block name"), nullptr);
1335 return new BranchInst(destBB);
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001336 }
1337 }
1338}
1339
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001340/// ML function declarations.
1341///
1342/// ml-func ::= `mlfunc` ml-func-signature `{` ml-stmt* ml-return-stmt `}`
1343///
1344ParseResult Parser::parseMLFunc() {
1345 consumeToken(Token::kw_mlfunc);
1346
1347 StringRef name;
1348 FunctionType *type = nullptr;
1349
1350 // FIXME: Parse ML function signature (args + types)
1351 // by passing pointer to SmallVector<identifier> into parseFunctionSignature
1352 if (parseFunctionSignature(name, type))
1353 return ParseFailure;
1354
1355 if (!consumeIf(Token::l_brace))
1356 return emitError("expected '{' in ML function");
1357
1358 // Okay, the ML function signature was parsed correctly, create the function.
1359 auto function = new MLFunction(name, type);
1360
1361 // Make sure we have at least one statement.
1362 if (curToken.is(Token::r_brace))
1363 return emitError("ML function must end with return statement");
1364
1365 // Parse the list of instructions.
1366 while (!consumeIf(Token::kw_return)) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001367 auto *stmt = parseStatement(function);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001368 if (!stmt)
1369 return ParseFailure;
1370 function->stmtList.push_back(stmt);
1371 }
1372
1373 // TODO: parse return statement operands
1374 if (!consumeIf(Token::r_brace))
1375 emitError("expected '}' in ML function");
1376
1377 module->functionList.push_back(function);
1378
1379 return ParseSuccess;
1380}
1381
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001382/// Statement.
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001383///
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001384/// ml-stmt ::= instruction | ml-for-stmt | ml-if-stmt
1385/// TODO: fix terminology in MLSpec document. ML functions
1386/// contain operation statements, not instructions.
1387///
1388Statement * Parser::parseStatement(ParentType parent) {
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001389 switch (curToken.getKind()) {
1390 default:
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001391 //TODO: parse OperationStmt
1392 return (emitError("expected statement"), nullptr);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001393
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001394 case Token::kw_for:
1395 return parseForStmt(parent);
1396
1397 case Token::kw_if:
1398 return parseIfStmt(parent);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001399 }
1400}
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001401
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001402/// For statement.
1403///
1404/// ml-for-stmt ::= `for` ssa-id `=` lower-bound `to` upper-bound
1405/// (`step` integer-literal)? `{` ml-stmt* `}`
1406///
1407ForStmt * Parser::parseForStmt(ParentType parent) {
1408 consumeToken(Token::kw_for);
1409
1410 //TODO: parse loop header
1411 ForStmt *stmt = new ForStmt(parent);
1412 if (parseNestedStatements(stmt)) {
1413 delete stmt;
1414 return nullptr;
1415 }
1416 return stmt;
1417}
1418
1419/// If statement.
1420///
1421/// ml-if-head ::= `if` ml-if-cond `{` ml-stmt* `}`
1422/// | ml-if-head `else` `if` ml-if-cond `{` ml-stmt* `}`
1423/// ml-if-stmt ::= ml-if-head
1424/// | ml-if-head `else` `{` ml-stmt* `}`
1425///
1426IfStmt * Parser::parseIfStmt(PointerUnion<MLFunction *, NodeStmt *> parent) {
1427 consumeToken(Token::kw_if);
1428
1429 //TODO: parse condition
1430 IfStmt *stmt = new IfStmt(parent);
1431 if (parseNestedStatements(stmt)) {
1432 delete stmt;
1433 return nullptr;
1434 }
1435
1436 int clauseNum = 0;
1437 while (consumeIf(Token::kw_else)) {
1438 if (consumeIf(Token::kw_if)) {
1439 //TODO: parse condition
1440 }
1441 ElseClause * clause = new ElseClause(stmt, clauseNum);
1442 ++clauseNum;
1443 if (parseNestedStatements(clause)) {
1444 delete clause;
1445 return nullptr;
1446 }
1447 }
1448
1449 return stmt;
1450}
1451
1452///
1453/// Parse `{` ml-stmt* `}`
1454///
1455ParseResult Parser::parseNestedStatements(NodeStmt *parent) {
1456 if (!consumeIf(Token::l_brace))
1457 return emitError("expected '{' before statement list");
1458
1459 if (consumeIf(Token::r_brace)) {
1460 // TODO: parse OperationStmt
1461 return ParseSuccess;
1462 }
1463
1464 while (!consumeIf(Token::r_brace)) {
1465 auto *stmt = parseStatement(parent);
1466 if (!stmt)
1467 return ParseFailure;
1468 parent->children.push_back(stmt);
1469 }
1470
1471 return ParseSuccess;
1472}
1473
Chris Lattner4c95a502018-06-23 16:03:42 -07001474//===----------------------------------------------------------------------===//
1475// Top-level entity parsing.
1476//===----------------------------------------------------------------------===//
1477
Chris Lattnere79379a2018-06-22 10:39:19 -07001478/// This is the top-level module parser.
1479Module *Parser::parseModule() {
1480 while (1) {
1481 switch (curToken.getKind()) {
1482 default:
1483 emitError("expected a top level entity");
1484 return nullptr;
1485
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001486 // If we got to the end of the file, then we're done.
Chris Lattnere79379a2018-06-22 10:39:19 -07001487 case Token::eof:
1488 return module.release();
1489
1490 // If we got an error token, then the lexer already emitted an error, just
1491 // stop. Someday we could introduce error recovery if there was demand for
1492 // it.
1493 case Token::error:
1494 return nullptr;
1495
1496 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -07001497 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -07001498 break;
1499
Chris Lattner4c95a502018-06-23 16:03:42 -07001500 case Token::kw_cfgfunc:
1501 if (parseCFGFunc()) return nullptr;
1502 break;
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001503
Chris Lattner8da0c282018-06-29 11:15:56 -07001504 case Token::affine_map_identifier:
MLIR Teamf85a6262018-06-27 11:03:08 -07001505 if (parseAffineMapDef()) return nullptr;
1506 break;
Chris Lattner4c95a502018-06-23 16:03:42 -07001507
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001508 case Token::kw_mlfunc:
1509 if (parseMLFunc()) return nullptr;
1510 break;
1511
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001512 // TODO: affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -07001513 }
1514 }
1515}
1516
1517//===----------------------------------------------------------------------===//
1518
Jacques Pienaar7b829702018-07-03 13:24:09 -07001519void mlir::defaultErrorReporter(const llvm::SMDiagnostic &error) {
1520 const auto &sourceMgr = *error.getSourceMgr();
1521 sourceMgr.PrintMessage(error.getLoc(), error.getKind(), error.getMessage());
1522}
1523
Chris Lattnere79379a2018-06-22 10:39:19 -07001524/// This parses the file specified by the indicated SourceMgr and returns an
1525/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Jacques Pienaar9c411be2018-06-24 19:17:35 -07001526Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context,
Jacques Pienaar7b829702018-07-03 13:24:09 -07001527 SMDiagnosticHandlerTy errorReporter) {
Chris Lattner21e67f62018-07-06 10:46:19 -07001528 auto *result =
1529 Parser(sourceMgr, context,
1530 errorReporter ? std::move(errorReporter) : defaultErrorReporter)
1531 .parseModule();
1532
1533 // Make sure the parse module has no other structural problems detected by the
1534 // verifier.
1535 if (result)
1536 result->verify();
1537 return result;
Chris Lattnere79379a2018-06-22 10:39:19 -07001538}