blob: d97e18ba5c8a0532094f9befe3489076bfe90ed9 [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"
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
Uday Bondhugula015cbb12018-07-03 20:16:08 -070047/// Lower precedence ops (all at the same precedence level). LNoOp is false in
48/// the boolean sense.
49enum AffineLowPrecOp {
50 /// Null value.
51 LNoOp,
52 Add,
53 Sub
54};
55
56/// Higher precedence ops - all at the same precedence level. HNoOp is false in
57/// the boolean sense.
58enum AffineHighPrecOp {
59 /// Null value.
60 HNoOp,
61 Mul,
62 FloorDiv,
63 CeilDiv,
64 Mod
65};
66
Chris Lattnere79379a2018-06-22 10:39:19 -070067/// Main parser implementation.
68class Parser {
Chris Lattnered65a732018-06-28 20:45:33 -070069public:
Jacques Pienaar9c411be2018-06-24 19:17:35 -070070 Parser(llvm::SourceMgr &sourceMgr, MLIRContext *context,
Jacques Pienaar7b829702018-07-03 13:24:09 -070071 SMDiagnosticHandlerTy errorReporter)
72 : context(context), lex(sourceMgr, errorReporter),
73 curToken(lex.lexToken()), errorReporter(std::move(errorReporter)) {
Chris Lattnere79379a2018-06-22 10:39:19 -070074 module.reset(new Module());
75 }
76
77 Module *parseModule();
78private:
79 // State.
Chris Lattnerf7e22732018-06-22 22:03:48 -070080 MLIRContext *const context;
81
82 // The lexer for the source file we're parsing.
Chris Lattnere79379a2018-06-22 10:39:19 -070083 Lexer lex;
84
85 // This is the next token that hasn't been consumed yet.
86 Token curToken;
87
Jacques Pienaar9c411be2018-06-24 19:17:35 -070088 // The diagnostic error reporter.
Jacques Pienaar7b829702018-07-03 13:24:09 -070089 SMDiagnosticHandlerTy errorReporter;
Jacques Pienaar9c411be2018-06-24 19:17:35 -070090
Chris Lattnere79379a2018-06-22 10:39:19 -070091 // This is the result module we are parsing into.
92 std::unique_ptr<Module> module;
93
MLIR Teamf85a6262018-06-27 11:03:08 -070094 // A map from affine map identifier to AffineMap.
Chris Lattner7121b802018-07-04 20:45:39 -070095 llvm::StringMap<AffineMap*> affineMapDefinitions;
MLIR Teamf85a6262018-06-27 11:03:08 -070096
Chris Lattnere79379a2018-06-22 10:39:19 -070097private:
98 // Helper methods.
99
100 /// Emit an error and return failure.
Chris Lattner4c95a502018-06-23 16:03:42 -0700101 ParseResult emitError(const Twine &message) {
102 return emitError(curToken.getLoc(), message);
103 }
104 ParseResult emitError(SMLoc loc, const Twine &message);
Chris Lattnere79379a2018-06-22 10:39:19 -0700105
106 /// Advance the current lexer onto the next token.
107 void consumeToken() {
108 assert(curToken.isNot(Token::eof, Token::error) &&
109 "shouldn't advance past EOF or errors");
110 curToken = lex.lexToken();
111 }
112
113 /// Advance the current lexer onto the next token, asserting what the expected
114 /// current token is. This is preferred to the above method because it leads
115 /// to more self-documenting code with better checking.
Chris Lattner8da0c282018-06-29 11:15:56 -0700116 void consumeToken(Token::Kind kind) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700117 assert(curToken.is(kind) && "consumed an unexpected token");
118 consumeToken();
119 }
120
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700121 /// If the current token has the specified kind, consume it and return true.
122 /// If not, return false.
Chris Lattner8da0c282018-06-29 11:15:56 -0700123 bool consumeIf(Token::Kind kind) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700124 if (curToken.isNot(kind))
125 return false;
126 consumeToken(kind);
127 return true;
128 }
129
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700130 // Binary affine op parsing
131 AffineLowPrecOp consumeIfLowPrecOp();
132 AffineHighPrecOp consumeIfHighPrecOp();
133
Chris Lattner8da0c282018-06-29 11:15:56 -0700134 ParseResult parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700135 const std::function<ParseResult()> &parseElement,
136 bool allowEmptyList = true);
137
Chris Lattnerf7e22732018-06-22 22:03:48 -0700138 // We have two forms of parsing methods - those that return a non-null
139 // pointer on success, and those that return a ParseResult to indicate whether
140 // they returned a failure. The second class fills in by-reference arguments
141 // as the results of their action.
142
Chris Lattnere79379a2018-06-22 10:39:19 -0700143 // Type parsing.
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700144 Type *parsePrimitiveType();
Chris Lattnerf7e22732018-06-22 22:03:48 -0700145 Type *parseElementType();
146 VectorType *parseVectorType();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700147 ParseResult parseDimensionListRanked(SmallVectorImpl<int> &dimensions);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700148 Type *parseTensorType();
149 Type *parseMemRefType();
150 Type *parseFunctionType();
151 Type *parseType();
152 ParseResult parseTypeList(SmallVectorImpl<Type*> &elements);
Chris Lattnere79379a2018-06-22 10:39:19 -0700153
Chris Lattner7121b802018-07-04 20:45:39 -0700154 // Attribute parsing.
155 Attribute *parseAttribute();
156 ParseResult parseAttributeDict(SmallVectorImpl<NamedAttribute> &attributes);
157
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700158 // Parsing identifiers' lists for polyhedral structures.
159 ParseResult parseDimIdList(AffineMapParserState &state);
160 ParseResult parseSymbolIdList(AffineMapParserState &state);
161 ParseResult parseDimOrSymbolId(AffineMapParserState &state, bool dim);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700162
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700163 // Polyhedral structures.
MLIR Teamf85a6262018-06-27 11:03:08 -0700164 ParseResult parseAffineMapDef();
Chris Lattner7121b802018-07-04 20:45:39 -0700165 AffineMap *parseAffineMapInline(StringRef mapId);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700166 AffineExpr *parseAffineExpr(const AffineMapParserState &state);
167
168 AffineExpr *parseParentheticalExpr(const AffineMapParserState &state);
169 AffineExpr *parseIntegerExpr(const AffineMapParserState &state);
170 AffineExpr *parseBareIdExpr(const AffineMapParserState &state);
171
172 static AffineBinaryOpExpr *getBinaryAffineOpExpr(AffineHighPrecOp op,
173 AffineExpr *lhs,
174 AffineExpr *rhs,
175 MLIRContext *context);
176 static AffineBinaryOpExpr *getBinaryAffineOpExpr(AffineLowPrecOp op,
177 AffineExpr *lhs,
178 AffineExpr *rhs,
179 MLIRContext *context);
180 ParseResult parseAffineOperandExpr(const AffineMapParserState &state,
181 AffineExpr *&result);
182 ParseResult parseAffineLowPrecOpExpr(AffineExpr *llhs, AffineLowPrecOp llhsOp,
183 const AffineMapParserState &state,
184 AffineExpr *&result);
185 ParseResult parseAffineHighPrecOpExpr(AffineExpr *llhs,
186 AffineHighPrecOp llhsOp,
187 const AffineMapParserState &state,
188 AffineExpr *&result);
MLIR Teamf85a6262018-06-27 11:03:08 -0700189
Chris Lattner4c95a502018-06-23 16:03:42 -0700190 // Functions.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700191 ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
Chris Lattnere79379a2018-06-22 10:39:19 -0700192 ParseResult parseExtFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700193 ParseResult parseCFGFunc();
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700194 ParseResult parseMLFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700195 ParseResult parseBasicBlock(CFGFunctionParserState &functionState);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700196 Statement *parseStatement(ParentType parent);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700197
Chris Lattner3a467cc2018-07-01 20:28:00 -0700198 OperationInst *parseCFGOperation(CFGFunctionParserState &functionState);
199 TerminatorInst *parseTerminator(CFGFunctionParserState &functionState);
Chris Lattnered65a732018-06-28 20:45:33 -0700200
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700201 ForStmt *parseForStmt(ParentType parent);
202 IfStmt *parseIfStmt(ParentType parent);
203 ParseResult parseNestedStatements(NodeStmt *parent);
Chris Lattnere79379a2018-06-22 10:39:19 -0700204};
205} // end anonymous namespace
206
207//===----------------------------------------------------------------------===//
208// Helper methods.
209//===----------------------------------------------------------------------===//
210
Chris Lattner4c95a502018-06-23 16:03:42 -0700211ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700212 // If we hit a parse error in response to a lexer error, then the lexer
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700213 // already reported the error.
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700214 if (curToken.is(Token::error))
215 return ParseFailure;
216
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700217 errorReporter(
218 lex.getSourceMgr().GetMessage(loc, SourceMgr::DK_Error, message));
Chris Lattnere79379a2018-06-22 10:39:19 -0700219 return ParseFailure;
220}
221
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700222/// Parse a comma-separated list of elements, terminated with an arbitrary
223/// token. This allows empty lists if allowEmptyList is true.
224///
225/// abstract-list ::= rightToken // if allowEmptyList == true
226/// abstract-list ::= element (',' element)* rightToken
227///
228ParseResult Parser::
Chris Lattner8da0c282018-06-29 11:15:56 -0700229parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700230 const std::function<ParseResult()> &parseElement,
231 bool allowEmptyList) {
232 // Handle the empty case.
233 if (curToken.is(rightToken)) {
234 if (!allowEmptyList)
235 return emitError("expected list element");
236 consumeToken(rightToken);
237 return ParseSuccess;
238 }
239
240 // Non-empty case starts with an element.
241 if (parseElement())
242 return ParseFailure;
243
244 // Otherwise we have a list of comma separated elements.
245 while (consumeIf(Token::comma)) {
246 if (parseElement())
247 return ParseFailure;
248 }
249
250 // Consume the end character.
251 if (!consumeIf(rightToken))
Chris Lattner8da0c282018-06-29 11:15:56 -0700252 return emitError("expected ',' or '" + Token::getTokenSpelling(rightToken) +
253 "'");
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700254
255 return ParseSuccess;
256}
Chris Lattnere79379a2018-06-22 10:39:19 -0700257
258//===----------------------------------------------------------------------===//
259// Type Parsing
260//===----------------------------------------------------------------------===//
261
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700262/// Parse the low-level fixed dtypes in the system.
263///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700264/// primitive-type ::= `f16` | `bf16` | `f32` | `f64`
265/// primitive-type ::= integer-type
266/// primitive-type ::= `affineint`
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700267///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700268Type *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700269 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700270 default:
271 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700272 case Token::kw_bf16:
273 consumeToken(Token::kw_bf16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700274 return Type::getBF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700275 case Token::kw_f16:
276 consumeToken(Token::kw_f16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700277 return Type::getF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700278 case Token::kw_f32:
279 consumeToken(Token::kw_f32);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700280 return Type::getF32(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700281 case Token::kw_f64:
282 consumeToken(Token::kw_f64);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700283 return Type::getF64(context);
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700284 case Token::kw_affineint:
285 consumeToken(Token::kw_affineint);
286 return Type::getAffineInt(context);
287 case Token::inttype: {
288 auto width = curToken.getIntTypeBitwidth();
289 if (!width.hasValue())
290 return (emitError("invalid integer width"), nullptr);
291 consumeToken(Token::inttype);
292 return Type::getInt(width.getValue(), context);
293 }
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700294 }
295}
296
297/// Parse the element type of a tensor or memref type.
298///
299/// element-type ::= primitive-type | vector-type
300///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700301Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700302 if (curToken.is(Token::kw_vector))
303 return parseVectorType();
304
305 return parsePrimitiveType();
306}
307
308/// Parse a vector type.
309///
310/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
311/// const-dimension-list ::= (integer-literal `x`)+
312///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700313VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700314 consumeToken(Token::kw_vector);
315
316 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700317 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700318
319 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700320 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700321
322 SmallVector<unsigned, 4> dimensions;
323 while (curToken.is(Token::integer)) {
324 // Make sure this integer value is in bound and valid.
325 auto dimension = curToken.getUnsignedIntegerValue();
326 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700327 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700328 dimensions.push_back(dimension.getValue());
329
330 consumeToken(Token::integer);
331
332 // Make sure we have an 'x' or something like 'xbf32'.
333 if (curToken.isNot(Token::bare_identifier) ||
334 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700335 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700336
337 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
338 if (curToken.getSpelling().size() != 1)
339 lex.resetPointer(curToken.getSpelling().data()+1);
340
341 // Consume the 'x'.
342 consumeToken(Token::bare_identifier);
343 }
344
345 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700346 auto *elementType = parsePrimitiveType();
347 if (!elementType)
348 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700349
350 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700351 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700352
Chris Lattnerf7e22732018-06-22 22:03:48 -0700353 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700354}
355
356/// Parse a dimension list of a tensor or memref type. This populates the
357/// dimension list, returning -1 for the '?' dimensions.
358///
359/// dimension-list-ranked ::= (dimension `x`)*
360/// dimension ::= `?` | integer-literal
361///
362ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
363 while (curToken.isAny(Token::integer, Token::question)) {
364 if (consumeIf(Token::question)) {
365 dimensions.push_back(-1);
366 } else {
367 // Make sure this integer value is in bound and valid.
368 auto dimension = curToken.getUnsignedIntegerValue();
369 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
370 return emitError("invalid dimension");
371 dimensions.push_back((int)dimension.getValue());
372 consumeToken(Token::integer);
373 }
374
375 // Make sure we have an 'x' or something like 'xbf32'.
376 if (curToken.isNot(Token::bare_identifier) ||
377 curToken.getSpelling()[0] != 'x')
378 return emitError("expected 'x' in dimension list");
379
380 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
381 if (curToken.getSpelling().size() != 1)
382 lex.resetPointer(curToken.getSpelling().data()+1);
383
384 // Consume the 'x'.
385 consumeToken(Token::bare_identifier);
386 }
387
388 return ParseSuccess;
389}
390
391/// Parse a tensor type.
392///
393/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
394/// dimension-list ::= dimension-list-ranked | `??`
395///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700396Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700397 consumeToken(Token::kw_tensor);
398
399 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700400 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700401
402 bool isUnranked;
403 SmallVector<int, 4> dimensions;
404
405 if (consumeIf(Token::questionquestion)) {
406 isUnranked = true;
407 } else {
408 isUnranked = false;
409 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700410 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700411 }
412
413 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700414 auto elementType = parseElementType();
415 if (!elementType)
416 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700417
418 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700419 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700420
MLIR Team355ec862018-06-23 18:09:09 -0700421 if (isUnranked)
422 return UnrankedTensorType::get(elementType);
423 return RankedTensorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700424}
425
426/// Parse a memref type.
427///
428/// memref-type ::= `memref` `<` dimension-list-ranked element-type
429/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
430///
431/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
432/// memory-space ::= integer-literal /* | TODO: address-space-id */
433///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700434Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700435 consumeToken(Token::kw_memref);
436
437 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700438 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700439
440 SmallVector<int, 4> dimensions;
441 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700442 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700443
444 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700445 auto elementType = parseElementType();
446 if (!elementType)
447 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700448
449 // TODO: Parse semi-affine-map-composition.
450 // TODO: Parse memory-space.
451
452 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700453 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700454
Chris Lattnerf7e22732018-06-22 22:03:48 -0700455 // FIXME: Add an IR representation for memref types.
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700456 return Type::getInt(1, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700457}
458
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700459/// Parse a function type.
460///
461/// function-type ::= type-list-parens `->` type-list
462///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700463Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700464 assert(curToken.is(Token::l_paren));
465
Chris Lattnerf7e22732018-06-22 22:03:48 -0700466 SmallVector<Type*, 4> arguments;
467 if (parseTypeList(arguments))
468 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700469
470 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700471 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700472
Chris Lattnerf7e22732018-06-22 22:03:48 -0700473 SmallVector<Type*, 4> results;
474 if (parseTypeList(results))
475 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700476
Chris Lattnerf7e22732018-06-22 22:03:48 -0700477 return FunctionType::get(arguments, results, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700478}
479
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700480/// Parse an arbitrary type.
481///
482/// type ::= primitive-type
483/// | vector-type
484/// | tensor-type
485/// | memref-type
486/// | function-type
487/// element-type ::= primitive-type | vector-type
488///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700489Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700490 switch (curToken.getKind()) {
491 case Token::kw_memref: return parseMemRefType();
492 case Token::kw_tensor: return parseTensorType();
493 case Token::kw_vector: return parseVectorType();
494 case Token::l_paren: return parseFunctionType();
495 default:
496 return parsePrimitiveType();
497 }
498}
499
500/// Parse a "type list", which is a singular type, or a parenthesized list of
501/// types.
502///
503/// type-list ::= type-list-parens | type
504/// type-list-parens ::= `(` `)`
505/// | `(` type (`,` type)* `)`
506///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700507ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
508 auto parseElt = [&]() -> ParseResult {
509 auto elt = parseType();
510 elements.push_back(elt);
511 return elt ? ParseSuccess : ParseFailure;
512 };
513
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700514 // If there is no parens, then it must be a singular type.
515 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700516 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700517
Chris Lattnerf7e22732018-06-22 22:03:48 -0700518 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700519 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700520
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700521 return ParseSuccess;
522}
523
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700524namespace {
525/// This class represents the transient parser state while parsing an affine
526/// expression.
527class AffineMapParserState {
528 public:
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700529 explicit AffineMapParserState() {}
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700530
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700531 void addDim(StringRef sRef) { dims.insert({sRef, dims.size()}); }
532 void addSymbol(StringRef sRef) { symbols.insert({sRef, symbols.size()}); }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700533
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700534 unsigned getNumDims() const { return dims.size(); }
535 unsigned getNumSymbols() const { return symbols.size(); }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700536
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700537 // TODO(bondhugula): could just use an vector/ArrayRef and scan the numbers.
538 const llvm::StringMap<unsigned> &getDims() const { return dims; }
539 const llvm::StringMap<unsigned> &getSymbols() const { return symbols; }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700540
541 private:
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700542 llvm::StringMap<unsigned> dims;
543 llvm::StringMap<unsigned> symbols;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700544};
545} // end anonymous namespace
546
Chris Lattner4c95a502018-06-23 16:03:42 -0700547//===----------------------------------------------------------------------===//
Chris Lattner7121b802018-07-04 20:45:39 -0700548// Attribute parsing.
549//===----------------------------------------------------------------------===//
550
551
552/// Attribute parsing.
553///
554/// attribute-value ::= bool-literal
555/// | integer-literal
556/// | float-literal
557/// | string-literal
558/// | `[` (attribute-value (`,` attribute-value)*)? `]`
559///
560Attribute *Parser::parseAttribute() {
561 switch (curToken.getKind()) {
562 case Token::kw_true:
563 consumeToken(Token::kw_true);
564 return BoolAttr::get(true, context);
565 case Token::kw_false:
566 consumeToken(Token::kw_false);
567 return BoolAttr::get(false, context);
568
569 case Token::integer: {
570 auto val = curToken.getUInt64IntegerValue();
571 if (!val.hasValue() || (int64_t)val.getValue() < 0)
572 return (emitError("integer too large for attribute"), nullptr);
573 consumeToken(Token::integer);
574 return IntegerAttr::get((int64_t)val.getValue(), context);
575 }
576
577 case Token::minus: {
578 consumeToken(Token::minus);
579 if (curToken.is(Token::integer)) {
580 auto val = curToken.getUInt64IntegerValue();
581 if (!val.hasValue() || (int64_t)-val.getValue() >= 0)
582 return (emitError("integer too large for attribute"), nullptr);
583 consumeToken(Token::integer);
584 return IntegerAttr::get((int64_t)-val.getValue(), context);
585 }
586
587 return (emitError("expected constant integer or floating point value"),
588 nullptr);
589 }
590
591 case Token::string: {
592 auto val = curToken.getStringValue();
593 consumeToken(Token::string);
594 return StringAttr::get(val, context);
595 }
596
597 case Token::l_bracket: {
598 consumeToken(Token::l_bracket);
599 SmallVector<Attribute*, 4> elements;
600
601 auto parseElt = [&]() -> ParseResult {
602 elements.push_back(parseAttribute());
603 return elements.back() ? ParseSuccess : ParseFailure;
604 };
605
606 if (parseCommaSeparatedList(Token::r_bracket, parseElt))
607 return nullptr;
608 return ArrayAttr::get(elements, context);
609 }
610 default:
611 // TODO: Handle floating point.
612 return (emitError("expected constant attribute value"), nullptr);
613 }
614}
615
616
617/// Attribute dictionary.
618///
619/// attribute-dict ::= `{` `}`
620/// | `{` attribute-entry (`,` attribute-entry)* `}`
621/// attribute-entry ::= bare-id `:` attribute-value
622///
623ParseResult Parser::parseAttributeDict(
624 SmallVectorImpl<NamedAttribute> &attributes) {
625 consumeToken(Token::l_brace);
626
627 auto parseElt = [&]() -> ParseResult {
628 // We allow keywords as attribute names.
629 if (curToken.isNot(Token::bare_identifier, Token::inttype) &&
630 !curToken.isKeyword())
631 return emitError("expected attribute name");
632 auto nameId = Identifier::get(curToken.getSpelling(), context);
633 consumeToken();
634
635 if (!consumeIf(Token::colon))
636 return emitError("expected ':' in attribute list");
637
638 auto attr = parseAttribute();
639 if (!attr) return ParseFailure;
640
641 attributes.push_back({nameId, attr});
642 return ParseSuccess;
643 };
644
645 if (parseCommaSeparatedList(Token::r_brace, parseElt))
646 return ParseFailure;
647
648 return ParseSuccess;
649}
650
651//===----------------------------------------------------------------------===//
MLIR Teamf85a6262018-06-27 11:03:08 -0700652// Polyhedral structures.
653//===----------------------------------------------------------------------===//
654
655/// Affine map declaration.
656///
657/// affine-map-def ::= affine-map-id `=` affine-map-inline
MLIR Teamf85a6262018-06-27 11:03:08 -0700658///
659ParseResult Parser::parseAffineMapDef() {
Chris Lattner8da0c282018-06-29 11:15:56 -0700660 assert(curToken.is(Token::affine_map_identifier));
MLIR Teamf85a6262018-06-27 11:03:08 -0700661
662 StringRef affineMapId = curToken.getSpelling().drop_front();
Chris Lattner7121b802018-07-04 20:45:39 -0700663
664 // Check for redefinitions.
665 auto *&entry = affineMapDefinitions[affineMapId];
666 if (entry)
667 return emitError("redefinition of affine map id '" + affineMapId + "'");
668
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700669 consumeToken(Token::affine_map_identifier);
670
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700671 // Parse the '='
672 if (!consumeIf(Token::equal))
673 return emitError("expected '=' in affine map outlined definition");
MLIR Teamf85a6262018-06-27 11:03:08 -0700674
Chris Lattner7121b802018-07-04 20:45:39 -0700675 entry = parseAffineMapInline(affineMapId);
676 if (!entry)
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700677 return ParseFailure;
MLIR Teamf85a6262018-06-27 11:03:08 -0700678
Chris Lattner7121b802018-07-04 20:45:39 -0700679 module->affineMapList.push_back(entry);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700680 return ParseSuccess;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700681}
682
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700683/// Create an affine op expression
684AffineBinaryOpExpr *Parser::getBinaryAffineOpExpr(AffineHighPrecOp op,
685 AffineExpr *lhs,
686 AffineExpr *rhs,
687 MLIRContext *context) {
688 switch (op) {
689 case Mul:
690 return AffineMulExpr::get(lhs, rhs, context);
691 case FloorDiv:
692 return AffineFloorDivExpr::get(lhs, rhs, context);
693 case CeilDiv:
694 return AffineCeilDivExpr::get(lhs, rhs, context);
695 case Mod:
696 return AffineModExpr::get(lhs, rhs, context);
697 case HNoOp:
698 llvm_unreachable("can't create affine expression for null high prec op");
699 return nullptr;
700 }
701}
702
703AffineBinaryOpExpr *Parser::getBinaryAffineOpExpr(AffineLowPrecOp op,
704 AffineExpr *lhs,
705 AffineExpr *rhs,
706 MLIRContext *context) {
707 switch (op) {
708 case AffineLowPrecOp::Add:
709 return AffineAddExpr::get(lhs, rhs, context);
710 case AffineLowPrecOp::Sub:
711 return AffineSubExpr::get(lhs, rhs, context);
712 case AffineLowPrecOp::LNoOp:
713 llvm_unreachable("can't create affine expression for null low prec op");
714 return nullptr;
715 }
716}
717
718/// Parses an expression that can be a valid operand of an affine expression
719/// (where associativity may not have been specified through parentheses).
720// Eg: for an expression without parentheses (like i + j + k + l), each
721// of the four identifiers is an operand. For: i + j*k + l, j*k is not an
722// operand expression, it's an op expression and will be parsed via
723// parseAffineLowPrecOpExpression().
724ParseResult Parser::parseAffineOperandExpr(const AffineMapParserState &state,
725 AffineExpr *&result) {
726 result = parseParentheticalExpr(state);
727 if (!result)
728 result = parseBareIdExpr(state);
729 if (!result)
730 result = parseIntegerExpr(state);
731 return result ? ParseSuccess : ParseFailure;
732}
733
734/// Parse a high precedence op expression list: mul, div, and mod are high
735/// precedence binary ops, i.e., parse a
736/// expr_1 op_1 expr_2 op_2 ... expr_n
737/// where op_1, op_2 are all a AffineHighPrecOp (mul, div, mod).
738/// All affine binary ops are left associative.
739/// Given llhs, returns (llhs * lhs) * rhs, or (lhs * rhs) if llhs is null. If
740/// no rhs can be found, returns (llhs * lhs) or lhs if llhs is null.
741// TODO(bondhugula): check whether mul is w.r.t. a constant - otherwise, the
742/// map is semi-affine.
743ParseResult Parser::parseAffineHighPrecOpExpr(AffineExpr *llhs,
744 AffineHighPrecOp llhsOp,
745 const AffineMapParserState &state,
746 AffineExpr *&result) {
747 // FIXME: Assume for now that llhsOp is mul.
748 AffineExpr *lhs = nullptr;
749 if (parseAffineOperandExpr(state, lhs)) {
750 return ParseFailure;
751 }
752 AffineHighPrecOp op = HNoOp;
753 // Found an LHS. Parse the remaining expression.
754 if ((op = consumeIfHighPrecOp())) {
755 if (llhs) {
756 // TODO(bondhugula): check whether 'lhs' here is a constant (for affine
757 // maps); semi-affine maps allow symbols.
758 AffineExpr *expr =
759 Parser::getBinaryAffineOpExpr(llhsOp, llhs, lhs, context);
760 AffineExpr *subRes = nullptr;
761 if (parseAffineHighPrecOpExpr(expr, op, state, subRes)) {
762 if (!subRes)
763 emitError("missing right operand of multiply op");
764 // In spite of the error, setting result to prevent duplicate errors
765 // messages as the call stack unwinds. All of this due to left
766 // associativity.
767 result = expr;
768 return ParseFailure;
769 }
770 result = subRes ? subRes : expr;
771 return ParseSuccess;
772 }
773 // No LLHS, get RHS
774 AffineExpr *subRes = nullptr;
775 if (parseAffineHighPrecOpExpr(lhs, op, state, subRes)) {
776 // 'product' needs to be checked to prevent duplicate errors messages as
777 // the call stack unwinds. All of this due to left associativity.
778 if (!subRes)
779 emitError("missing right operand of multiply op");
780 return ParseFailure;
781 }
782 result = subRes;
783 return ParseSuccess;
784 }
785
786 // This is the last operand in this expression.
787 if (llhs) {
788 // TODO(bondhugula): check whether lhs here is a constant (for affine
789 // maps); semi-affine maps allow symbols.
790 result = Parser::getBinaryAffineOpExpr(llhsOp, llhs, lhs, context);
791 return ParseSuccess;
792 }
793
794 // No llhs, 'lhs' itself is the expression.
795 result = lhs;
796 return ParseSuccess;
797}
798
799/// Consume this token if it is a lower precedence affine op (there are only two
800/// precedence levels)
801AffineLowPrecOp Parser::consumeIfLowPrecOp() {
802 switch (curToken.getKind()) {
803 case Token::plus:
804 consumeToken(Token::plus);
805 return AffineLowPrecOp::Add;
806 case Token::minus:
807 consumeToken(Token::minus);
808 return AffineLowPrecOp::Sub;
809 default:
810 return AffineLowPrecOp::LNoOp;
811 }
812}
813
814/// Consume this token if it is a higher precedence affine op (there are only
815/// two precedence levels)
816AffineHighPrecOp Parser::consumeIfHighPrecOp() {
817 switch (curToken.getKind()) {
818 case Token::star:
819 consumeToken(Token::star);
820 return Mul;
821 case Token::kw_floordiv:
822 consumeToken(Token::kw_floordiv);
823 return FloorDiv;
824 case Token::kw_ceildiv:
825 consumeToken(Token::kw_ceildiv);
826 return CeilDiv;
827 case Token::kw_mod:
828 consumeToken(Token::kw_mod);
829 return Mod;
830 default:
831 return HNoOp;
832 }
833}
834
835/// Parse affine expressions that are bare-id's, integer constants,
836/// parenthetical affine expressions, and affine op expressions that are a
837/// composition of those.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700838///
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700839/// All binary op's associate from left to right.
840///
841/// {add, sub} have lower precedence than {mul, div, and mod}.
842///
843/// Add, sub'are themselves at the same precedence level. mul, div, and mod are
844/// at the same higher precedence level.
845///
846/// llhs: the affine expression appearing on the left of the one being parsed.
847/// This function will return ((llhs + lhs) + rhs) if llhs is non null, and
848/// lhs + rhs otherwise; if there is no rhs, llhs + lhs is returned if llhs is
849/// non-null; otherwise lhs is returned. This is to deal with left
850/// associativity.
851///
852/// Eg: when the expression is e1 + e2*e3 + e4, with e1 as llhs, this function
853/// will return the affine expr equivalent of (e1 + (e2*e3)) + e4.
854///
855// TODO(bondhugula): add support for unary op negation. Assuming for now that
856// the op to associate with llhs is add.
857ParseResult Parser::parseAffineLowPrecOpExpr(AffineExpr *llhs,
858 AffineLowPrecOp llhsOp,
859 const AffineMapParserState &state,
860 AffineExpr *&result) {
861 AffineExpr *lhs = nullptr;
862 if (parseAffineOperandExpr(state, lhs))
863 return ParseFailure;
864
865 // Found an LHS. Deal with the ops.
866 AffineLowPrecOp lOp;
867 AffineHighPrecOp rOp;
868 if ((lOp = consumeIfLowPrecOp())) {
869 if (llhs) {
870 AffineExpr *sum =
871 Parser::getBinaryAffineOpExpr(llhsOp, llhs, lhs, context);
872 AffineExpr *recSum = nullptr;
873 parseAffineLowPrecOpExpr(sum, lOp, state, recSum);
874 result = recSum ? recSum : sum;
875 return ParseSuccess;
876 }
877 // No LLHS, get RHS and form the expression.
878 if (parseAffineLowPrecOpExpr(lhs, lOp, state, result)) {
879 if (!result)
880 emitError("missing right operand of add op");
881 return ParseFailure;
882 }
883 return ParseSuccess;
884 } else if ((rOp = consumeIfHighPrecOp())) {
885 // We have a higher precedence op here. Get the rhs operand for the llhs
886 // through parseAffineHighPrecOpExpr.
887 AffineExpr *highRes = nullptr;
888 if (parseAffineHighPrecOpExpr(lhs, rOp, state, highRes)) {
889 // 'product' needs to be checked to prevent duplicate errors messages as
890 // the call stack unwinds. All of this due to left associativity.
891 if (!highRes)
892 emitError("missing right operand of binary op");
893 return ParseFailure;
894 }
895 // If llhs is null, the product forms the first operand of the yet to be
896 // found expression. If non-null, assume for now that the op to associate
897 // with llhs is add.
898 AffineExpr *expr =
899 llhs ? getBinaryAffineOpExpr(llhsOp, llhs, highRes, context) : highRes;
900 // Recurse for subsequent add's after the affine mul expression
901 AffineLowPrecOp nextOp = consumeIfLowPrecOp();
902 if (nextOp) {
903 AffineExpr *sumProd = nullptr;
904 parseAffineLowPrecOpExpr(expr, nextOp, state, sumProd);
905 result = sumProd ? sumProd : expr;
906 } else {
907 result = expr;
908 }
909 return ParseSuccess;
910 } else {
911 // Last operand in the expression list.
912 if (llhs) {
913 result = Parser::getBinaryAffineOpExpr(llhsOp, llhs, lhs, context);
914 return ParseSuccess;
915 }
916 // No llhs, 'lhs' itself is the expression.
917 result = lhs;
918 return ParseSuccess;
919 }
920}
921
922/// Parse an affine expression inside parentheses.
923/// affine-expr ::= `(` affine-expr `)`
924AffineExpr *Parser::parseParentheticalExpr(const AffineMapParserState &state) {
925 if (!consumeIf(Token::l_paren)) {
926 return nullptr;
927 }
928 auto *expr = parseAffineExpr(state);
929 if (!consumeIf(Token::r_paren)) {
930 emitError("expected ')'");
931 return nullptr;
932 }
933 if (!expr)
934 emitError("no expression inside parentheses");
935 return expr;
936}
937
938/// Parse a bare id that may appear in an affine expression.
939/// affine-expr ::= bare-id
940AffineExpr *Parser::parseBareIdExpr(const AffineMapParserState &state) {
941 if (curToken.is(Token::bare_identifier)) {
942 StringRef sRef = curToken.getSpelling();
943 const auto &dims = state.getDims();
944 const auto &symbols = state.getSymbols();
945 if (dims.count(sRef)) {
946 consumeToken(Token::bare_identifier);
947 return AffineDimExpr::get(dims.lookup(sRef), context);
948 }
949 if (symbols.count(sRef)) {
950 consumeToken(Token::bare_identifier);
951 return AffineSymbolExpr::get(symbols.lookup(sRef), context);
952 }
953 return emitError("identifier is neither dimensional nor symbolic"), nullptr;
954 }
955 return nullptr;
956}
957
958/// Parse an integral constant appearing in an affine expression.
959/// affine-expr ::= `-`? integer-literal
960/// TODO(bondhugula): handle negative numbers.
961AffineExpr *Parser::parseIntegerExpr(const AffineMapParserState &state) {
962 if (curToken.is(Token::integer)) {
963 auto *expr = AffineConstantExpr::get(
964 curToken.getUnsignedIntegerValue().getValue(), context);
965 consumeToken(Token::integer);
966 return expr;
967 }
968 return nullptr;
969}
970
971/// Parse an affine expression.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700972/// affine-expr ::= `(` affine-expr `)`
973/// | affine-expr `+` affine-expr
974/// | affine-expr `-` affine-expr
975/// | `-`? integer-literal `*` affine-expr
976/// | `ceildiv` `(` affine-expr `,` integer-literal `)`
977/// | `floordiv` `(` affine-expr `,` integer-literal `)`
978/// | affine-expr `mod` integer-literal
979/// | bare-id
980/// | `-`? integer-literal
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700981/// Use 'state' to check if valid identifiers appear.
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700982// TODO(bondhugula): check if mul, mod, div take integral constants
983AffineExpr *Parser::parseAffineExpr(const AffineMapParserState &state) {
984 switch (curToken.getKind()) {
985 case Token::l_paren:
986 case Token::kw_ceildiv:
987 case Token::kw_floordiv:
988 case Token::bare_identifier:
989 case Token::integer: {
990 AffineExpr *result = nullptr;
991 parseAffineLowPrecOpExpr(nullptr, AffineLowPrecOp::LNoOp, state, result);
992 return result;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700993 }
994
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700995 case Token::plus:
996 case Token::minus:
997 case Token::star:
998 emitError("left operand of binary op missing");
999 return nullptr;
1000
1001 default:
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001002 return nullptr;
1003 }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001004}
1005
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001006/// Parse a dim or symbol from the lists appearing before the actual expressions
1007/// of the affine map. Update state to store the dimensional/symbolic
1008/// identifier. 'dim': whether it's the dim list or symbol list that is being
1009/// parsed.
1010ParseResult Parser::parseDimOrSymbolId(AffineMapParserState &state, bool dim) {
1011 if (curToken.isNot(Token::bare_identifier))
1012 return emitError("expected bare identifier");
1013 auto sRef = curToken.getSpelling();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001014 consumeToken(Token::bare_identifier);
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001015 if (state.getDims().count(sRef) == 1)
1016 return emitError("dimensional identifier name reused");
1017 if (state.getSymbols().count(sRef) == 1)
1018 return emitError("symbolic identifier name reused");
1019 if (dim)
1020 state.addDim(sRef);
1021 else
1022 state.addSymbol(sRef);
1023 return ParseSuccess;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001024}
1025
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001026/// Parse the list of symbolic identifiers to an affine map.
1027ParseResult Parser::parseSymbolIdList(AffineMapParserState &state) {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001028 if (!consumeIf(Token::l_bracket)) return emitError("expected '['");
1029
1030 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001031 return parseDimOrSymbolId(state, false);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001032 };
1033 return parseCommaSeparatedList(Token::r_bracket, parseElt);
1034}
1035
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001036/// Parse the list of dimensional identifiers to an affine map.
1037ParseResult Parser::parseDimIdList(AffineMapParserState &state) {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001038 if (!consumeIf(Token::l_paren))
1039 return emitError("expected '(' at start of dimensional identifiers list");
1040
1041 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001042 return parseDimOrSymbolId(state, true);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001043 };
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001044 return parseCommaSeparatedList(Token::r_paren, parseElt);
1045}
1046
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001047/// Parse an affine map definition.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001048///
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001049/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001050/// ( `size` `(` dim-size (`,` dim-size)* `)` )?
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001051/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001052///
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001053/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
Chris Lattner7121b802018-07-04 20:45:39 -07001054AffineMap *Parser::parseAffineMapInline(StringRef mapId) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001055 AffineMapParserState state;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001056
1057 // List of dimensional identifiers.
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001058 if (parseDimIdList(state))
Chris Lattner7121b802018-07-04 20:45:39 -07001059 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001060
1061 // Symbols are optional.
1062 if (curToken.is(Token::l_bracket)) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001063 if (parseSymbolIdList(state))
Chris Lattner7121b802018-07-04 20:45:39 -07001064 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001065 }
1066 if (!consumeIf(Token::arrow)) {
Chris Lattner7121b802018-07-04 20:45:39 -07001067 return (emitError("expected '->' or '['"), nullptr);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001068 }
1069 if (!consumeIf(Token::l_paren)) {
1070 emitError("expected '(' at start of affine map range");
Chris Lattner7121b802018-07-04 20:45:39 -07001071 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001072 }
1073
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001074 SmallVector<AffineExpr *, 4> exprs;
1075 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001076 auto *elt = parseAffineExpr(state);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001077 ParseResult res = elt ? ParseSuccess : ParseFailure;
1078 exprs.push_back(elt);
1079 return res;
1080 };
1081
1082 // Parse a multi-dimensional affine expression (a comma-separated list of 1-d
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001083 // affine expressions); the list cannot be empty.
1084 // Grammar: multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
1085 if (parseCommaSeparatedList(Token::r_paren, parseElt, false))
Chris Lattner7121b802018-07-04 20:45:39 -07001086 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001087
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001088 // Parsed a valid affine map.
Chris Lattner7121b802018-07-04 20:45:39 -07001089 return AffineMap::get(state.getNumDims(), state.getNumSymbols(), exprs,
1090 context);
MLIR Teamf85a6262018-06-27 11:03:08 -07001091}
1092
1093//===----------------------------------------------------------------------===//
Chris Lattner4c95a502018-06-23 16:03:42 -07001094// Functions
1095//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -07001096
Chris Lattnere79379a2018-06-22 10:39:19 -07001097
1098/// Parse a function signature, starting with a name and including the parameter
1099/// list.
1100///
1101/// argument-list ::= type (`,` type)* | /*empty*/
1102/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
1103///
Chris Lattnerf7e22732018-06-22 22:03:48 -07001104ParseResult Parser::parseFunctionSignature(StringRef &name,
1105 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -07001106 if (curToken.isNot(Token::at_identifier))
1107 return emitError("expected a function identifier like '@foo'");
1108
1109 name = curToken.getSpelling().drop_front();
1110 consumeToken(Token::at_identifier);
1111
1112 if (curToken.isNot(Token::l_paren))
1113 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -07001114
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001115 SmallVector<Type*, 4> arguments;
1116 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001117 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -07001118
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001119 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -07001120 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001121 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -07001122 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001123 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001124 }
Chris Lattnerf7e22732018-06-22 22:03:48 -07001125 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -07001126 return ParseSuccess;
1127}
1128
Chris Lattnere79379a2018-06-22 10:39:19 -07001129/// External function declarations.
1130///
1131/// ext-func ::= `extfunc` function-signature
1132///
1133ParseResult Parser::parseExtFunc() {
1134 consumeToken(Token::kw_extfunc);
1135
1136 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -07001137 FunctionType *type = nullptr;
1138 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -07001139 return ParseFailure;
1140
Chris Lattnere79379a2018-06-22 10:39:19 -07001141 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -07001142 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -07001143 return ParseSuccess;
1144}
1145
1146
Chris Lattner4c95a502018-06-23 16:03:42 -07001147namespace {
1148/// This class represents the transient parser state for the internals of a
1149/// function as we are parsing it, e.g. the names for basic blocks. It handles
1150/// forward references.
1151class CFGFunctionParserState {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001152 public:
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001153 CFGFunction *function;
1154 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
1155
Chris Lattner4c95a502018-06-23 16:03:42 -07001156 CFGFunctionParserState(CFGFunction *function) : function(function) {}
1157
1158 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001159 /// already exist. The location specified is the point of use, which allows
1160 /// us to diagnose references to blocks that are not defined precisely.
1161 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
1162 auto &blockAndLoc = blocksByName[name];
1163 if (!blockAndLoc.first) {
Chris Lattner3a467cc2018-07-01 20:28:00 -07001164 blockAndLoc.first = new BasicBlock();
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001165 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -07001166 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001167 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -07001168 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001169};
1170} // end anonymous namespace
1171
1172
1173/// CFG function declarations.
1174///
1175/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
1176///
1177ParseResult Parser::parseCFGFunc() {
1178 consumeToken(Token::kw_cfgfunc);
1179
1180 StringRef name;
1181 FunctionType *type = nullptr;
1182 if (parseFunctionSignature(name, type))
1183 return ParseFailure;
1184
1185 if (!consumeIf(Token::l_brace))
1186 return emitError("expected '{' in CFG function");
1187
1188 // Okay, the CFG function signature was parsed correctly, create the function.
1189 auto function = new CFGFunction(name, type);
1190
1191 // Make sure we have at least one block.
1192 if (curToken.is(Token::r_brace))
1193 return emitError("CFG functions must have at least one basic block");
1194
1195 CFGFunctionParserState functionState(function);
1196
1197 // Parse the list of blocks.
1198 while (!consumeIf(Token::r_brace))
1199 if (parseBasicBlock(functionState))
1200 return ParseFailure;
1201
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001202 // Verify that all referenced blocks were defined. Iteration over a
1203 // StringMap isn't determinstic, but this is good enough for our purposes.
1204 for (auto &elt : functionState.blocksByName) {
1205 auto *bb = elt.second.first;
Chris Lattner3a467cc2018-07-01 20:28:00 -07001206 if (!bb->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001207 return emitError(elt.second.second,
1208 "reference to an undefined basic block '" +
1209 elt.first() + "'");
1210 }
1211
Chris Lattner4c95a502018-06-23 16:03:42 -07001212 module->functionList.push_back(function);
1213 return ParseSuccess;
1214}
1215
1216/// Basic block declaration.
1217///
1218/// basic-block ::= bb-label instruction* terminator-stmt
1219/// bb-label ::= bb-id bb-arg-list? `:`
1220/// bb-id ::= bare-id
1221/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
1222///
1223ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
1224 SMLoc nameLoc = curToken.getLoc();
1225 auto name = curToken.getSpelling();
1226 if (!consumeIf(Token::bare_identifier))
1227 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001228
1229 auto block = functionState.getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -07001230
1231 // If this block has already been parsed, then this is a redefinition with the
1232 // same block name.
Chris Lattner3a467cc2018-07-01 20:28:00 -07001233 if (block->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001234 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
1235
Chris Lattner3a467cc2018-07-01 20:28:00 -07001236 // Add the block to the function.
1237 functionState.function->push_back(block);
Chris Lattner4c95a502018-06-23 16:03:42 -07001238
1239 // TODO: parse bb argument list.
1240
1241 if (!consumeIf(Token::colon))
1242 return emitError("expected ':' after basic block name");
1243
Chris Lattnered65a732018-06-28 20:45:33 -07001244 // Parse the list of operations that make up the body of the block.
1245 while (curToken.isNot(Token::kw_return, Token::kw_br)) {
Chris Lattner3a467cc2018-07-01 20:28:00 -07001246 auto *inst = parseCFGOperation(functionState);
1247 if (!inst)
Chris Lattnered65a732018-06-28 20:45:33 -07001248 return ParseFailure;
Chris Lattner3a467cc2018-07-01 20:28:00 -07001249
1250 block->getOperations().push_back(inst);
Chris Lattnered65a732018-06-28 20:45:33 -07001251 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001252
Chris Lattner3a467cc2018-07-01 20:28:00 -07001253 auto *term = parseTerminator(functionState);
1254 if (!term)
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001255 return ParseFailure;
Chris Lattner3a467cc2018-07-01 20:28:00 -07001256 block->setTerminator(term);
Chris Lattner4c95a502018-06-23 16:03:42 -07001257
1258 return ParseSuccess;
1259}
1260
1261
Chris Lattnered65a732018-06-28 20:45:33 -07001262/// Parse the CFG operation.
1263///
1264/// TODO(clattner): This is a change from the MLIR spec as written, it is an
1265/// experiment that will eliminate "builtin" instructions as a thing.
1266///
1267/// cfg-operation ::=
1268/// (ssa-id `=`)? string '(' ssa-use-list? ')' attribute-dict?
1269/// `:` function-type
1270///
Chris Lattner3a467cc2018-07-01 20:28:00 -07001271OperationInst *Parser::
1272parseCFGOperation(CFGFunctionParserState &functionState) {
Chris Lattnered65a732018-06-28 20:45:33 -07001273
1274 // TODO: parse ssa-id.
1275
1276 if (curToken.isNot(Token::string))
Chris Lattner3a467cc2018-07-01 20:28:00 -07001277 return (emitError("expected operation name in quotes"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001278
1279 auto name = curToken.getStringValue();
1280 if (name.empty())
Chris Lattner3a467cc2018-07-01 20:28:00 -07001281 return (emitError("empty operation name is invalid"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001282
1283 consumeToken(Token::string);
1284
1285 if (!consumeIf(Token::l_paren))
Chris Lattner7121b802018-07-04 20:45:39 -07001286 return (emitError("expected '(' to start operand list"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001287
1288 // TODO: Parse operands.
1289 if (!consumeIf(Token::r_paren))
Chris Lattner7121b802018-07-04 20:45:39 -07001290 return (emitError("expected ')' in operand list"), nullptr);
1291
1292 SmallVector<NamedAttribute, 4> attributes;
1293 if (curToken.is(Token::l_brace)) {
1294 if (parseAttributeDict(attributes))
1295 return nullptr;
1296 }
Chris Lattnered65a732018-06-28 20:45:33 -07001297
1298 auto nameId = Identifier::get(name, context);
Chris Lattnerdf1a2fc2018-07-05 21:20:59 -07001299 return new OperationInst(nameId, attributes, context);
Chris Lattnered65a732018-06-28 20:45:33 -07001300}
1301
1302
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001303/// Parse the terminator instruction for a basic block.
1304///
1305/// terminator-stmt ::= `br` bb-id branch-use-list?
1306/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
1307/// terminator-stmt ::=
1308/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
1309/// terminator-stmt ::= `return` ssa-use-and-type-list?
1310///
Chris Lattner3a467cc2018-07-01 20:28:00 -07001311TerminatorInst *Parser::parseTerminator(CFGFunctionParserState &functionState) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001312 switch (curToken.getKind()) {
1313 default:
Chris Lattner3a467cc2018-07-01 20:28:00 -07001314 return (emitError("expected terminator at end of basic block"), nullptr);
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001315
1316 case Token::kw_return:
1317 consumeToken(Token::kw_return);
Chris Lattner3a467cc2018-07-01 20:28:00 -07001318 return new ReturnInst();
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001319
1320 case Token::kw_br: {
1321 consumeToken(Token::kw_br);
1322 auto destBB = functionState.getBlockNamed(curToken.getSpelling(),
1323 curToken.getLoc());
1324 if (!consumeIf(Token::bare_identifier))
Chris Lattner3a467cc2018-07-01 20:28:00 -07001325 return (emitError("expected basic block name"), nullptr);
1326 return new BranchInst(destBB);
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001327 }
1328 }
1329}
1330
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001331/// ML function declarations.
1332///
1333/// ml-func ::= `mlfunc` ml-func-signature `{` ml-stmt* ml-return-stmt `}`
1334///
1335ParseResult Parser::parseMLFunc() {
1336 consumeToken(Token::kw_mlfunc);
1337
1338 StringRef name;
1339 FunctionType *type = nullptr;
1340
1341 // FIXME: Parse ML function signature (args + types)
1342 // by passing pointer to SmallVector<identifier> into parseFunctionSignature
1343 if (parseFunctionSignature(name, type))
1344 return ParseFailure;
1345
1346 if (!consumeIf(Token::l_brace))
1347 return emitError("expected '{' in ML function");
1348
1349 // Okay, the ML function signature was parsed correctly, create the function.
1350 auto function = new MLFunction(name, type);
1351
1352 // Make sure we have at least one statement.
1353 if (curToken.is(Token::r_brace))
1354 return emitError("ML function must end with return statement");
1355
1356 // Parse the list of instructions.
1357 while (!consumeIf(Token::kw_return)) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001358 auto *stmt = parseStatement(function);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001359 if (!stmt)
1360 return ParseFailure;
1361 function->stmtList.push_back(stmt);
1362 }
1363
1364 // TODO: parse return statement operands
1365 if (!consumeIf(Token::r_brace))
1366 emitError("expected '}' in ML function");
1367
1368 module->functionList.push_back(function);
1369
1370 return ParseSuccess;
1371}
1372
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001373/// Statement.
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001374///
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001375/// ml-stmt ::= instruction | ml-for-stmt | ml-if-stmt
1376/// TODO: fix terminology in MLSpec document. ML functions
1377/// contain operation statements, not instructions.
1378///
1379Statement * Parser::parseStatement(ParentType parent) {
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001380 switch (curToken.getKind()) {
1381 default:
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001382 //TODO: parse OperationStmt
1383 return (emitError("expected statement"), nullptr);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001384
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001385 case Token::kw_for:
1386 return parseForStmt(parent);
1387
1388 case Token::kw_if:
1389 return parseIfStmt(parent);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001390 }
1391}
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001392
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001393/// For statement.
1394///
1395/// ml-for-stmt ::= `for` ssa-id `=` lower-bound `to` upper-bound
1396/// (`step` integer-literal)? `{` ml-stmt* `}`
1397///
1398ForStmt * Parser::parseForStmt(ParentType parent) {
1399 consumeToken(Token::kw_for);
1400
1401 //TODO: parse loop header
1402 ForStmt *stmt = new ForStmt(parent);
1403 if (parseNestedStatements(stmt)) {
1404 delete stmt;
1405 return nullptr;
1406 }
1407 return stmt;
1408}
1409
1410/// If statement.
1411///
1412/// ml-if-head ::= `if` ml-if-cond `{` ml-stmt* `}`
1413/// | ml-if-head `else` `if` ml-if-cond `{` ml-stmt* `}`
1414/// ml-if-stmt ::= ml-if-head
1415/// | ml-if-head `else` `{` ml-stmt* `}`
1416///
1417IfStmt * Parser::parseIfStmt(PointerUnion<MLFunction *, NodeStmt *> parent) {
1418 consumeToken(Token::kw_if);
1419
1420 //TODO: parse condition
1421 IfStmt *stmt = new IfStmt(parent);
1422 if (parseNestedStatements(stmt)) {
1423 delete stmt;
1424 return nullptr;
1425 }
1426
1427 int clauseNum = 0;
1428 while (consumeIf(Token::kw_else)) {
1429 if (consumeIf(Token::kw_if)) {
1430 //TODO: parse condition
1431 }
1432 ElseClause * clause = new ElseClause(stmt, clauseNum);
1433 ++clauseNum;
1434 if (parseNestedStatements(clause)) {
1435 delete clause;
1436 return nullptr;
1437 }
1438 }
1439
1440 return stmt;
1441}
1442
1443///
1444/// Parse `{` ml-stmt* `}`
1445///
1446ParseResult Parser::parseNestedStatements(NodeStmt *parent) {
1447 if (!consumeIf(Token::l_brace))
1448 return emitError("expected '{' before statement list");
1449
1450 if (consumeIf(Token::r_brace)) {
1451 // TODO: parse OperationStmt
1452 return ParseSuccess;
1453 }
1454
1455 while (!consumeIf(Token::r_brace)) {
1456 auto *stmt = parseStatement(parent);
1457 if (!stmt)
1458 return ParseFailure;
1459 parent->children.push_back(stmt);
1460 }
1461
1462 return ParseSuccess;
1463}
1464
Chris Lattner4c95a502018-06-23 16:03:42 -07001465//===----------------------------------------------------------------------===//
1466// Top-level entity parsing.
1467//===----------------------------------------------------------------------===//
1468
Chris Lattnere79379a2018-06-22 10:39:19 -07001469/// This is the top-level module parser.
1470Module *Parser::parseModule() {
1471 while (1) {
1472 switch (curToken.getKind()) {
1473 default:
1474 emitError("expected a top level entity");
1475 return nullptr;
1476
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001477 // If we got to the end of the file, then we're done.
Chris Lattnere79379a2018-06-22 10:39:19 -07001478 case Token::eof:
1479 return module.release();
1480
1481 // If we got an error token, then the lexer already emitted an error, just
1482 // stop. Someday we could introduce error recovery if there was demand for
1483 // it.
1484 case Token::error:
1485 return nullptr;
1486
1487 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -07001488 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -07001489 break;
1490
Chris Lattner4c95a502018-06-23 16:03:42 -07001491 case Token::kw_cfgfunc:
1492 if (parseCFGFunc()) return nullptr;
1493 break;
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001494
Chris Lattner8da0c282018-06-29 11:15:56 -07001495 case Token::affine_map_identifier:
MLIR Teamf85a6262018-06-27 11:03:08 -07001496 if (parseAffineMapDef()) return nullptr;
1497 break;
Chris Lattner4c95a502018-06-23 16:03:42 -07001498
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001499 case Token::kw_mlfunc:
1500 if (parseMLFunc()) return nullptr;
1501 break;
1502
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001503 // TODO: affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -07001504 }
1505 }
1506}
1507
1508//===----------------------------------------------------------------------===//
1509
Jacques Pienaar7b829702018-07-03 13:24:09 -07001510void mlir::defaultErrorReporter(const llvm::SMDiagnostic &error) {
1511 const auto &sourceMgr = *error.getSourceMgr();
1512 sourceMgr.PrintMessage(error.getLoc(), error.getKind(), error.getMessage());
1513}
1514
Chris Lattnere79379a2018-06-22 10:39:19 -07001515/// This parses the file specified by the indicated SourceMgr and returns an
1516/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Jacques Pienaar9c411be2018-06-24 19:17:35 -07001517Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context,
Jacques Pienaar7b829702018-07-03 13:24:09 -07001518 SMDiagnosticHandlerTy errorReporter) {
1519 return Parser(sourceMgr, context,
1520 errorReporter ? std::move(errorReporter) : defaultErrorReporter)
1521 .parseModule();
Chris Lattnere79379a2018-06-22 10:39:19 -07001522}