blob: 94d14689bdad13cb9e965d13836b4519e84919a2 [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 Lattner78276e32018-07-07 15:48:26 -0700191 // SSA
192 ParseResult parseSSAUse();
193 ParseResult parseOptionalSSAUseList(Token::Kind endToken);
194 ParseResult parseSSAUseAndType();
195 ParseResult parseOptionalSSAUseAndTypeList(Token::Kind endToken);
196
Chris Lattner4c95a502018-06-23 16:03:42 -0700197 // Functions.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700198 ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
Chris Lattnere79379a2018-06-22 10:39:19 -0700199 ParseResult parseExtFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700200 ParseResult parseCFGFunc();
201 ParseResult parseBasicBlock(CFGFunctionParserState &functionState);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700202 Statement *parseStatement(ParentType parent);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700203
Chris Lattner3a467cc2018-07-01 20:28:00 -0700204 OperationInst *parseCFGOperation(CFGFunctionParserState &functionState);
205 TerminatorInst *parseTerminator(CFGFunctionParserState &functionState);
Chris Lattnered65a732018-06-28 20:45:33 -0700206
Chris Lattner78276e32018-07-07 15:48:26 -0700207 ParseResult parseMLFunc();
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700208 ForStmt *parseForStmt(ParentType parent);
209 IfStmt *parseIfStmt(ParentType parent);
210 ParseResult parseNestedStatements(NodeStmt *parent);
Chris Lattnere79379a2018-06-22 10:39:19 -0700211};
212} // end anonymous namespace
213
214//===----------------------------------------------------------------------===//
215// Helper methods.
216//===----------------------------------------------------------------------===//
217
Chris Lattner4c95a502018-06-23 16:03:42 -0700218ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700219 // If we hit a parse error in response to a lexer error, then the lexer
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700220 // already reported the error.
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700221 if (curToken.is(Token::error))
222 return ParseFailure;
223
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700224 errorReporter(
225 lex.getSourceMgr().GetMessage(loc, SourceMgr::DK_Error, message));
Chris Lattnere79379a2018-06-22 10:39:19 -0700226 return ParseFailure;
227}
228
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700229/// Parse a comma-separated list of elements, terminated with an arbitrary
230/// token. This allows empty lists if allowEmptyList is true.
231///
232/// abstract-list ::= rightToken // if allowEmptyList == true
233/// abstract-list ::= element (',' element)* rightToken
234///
235ParseResult Parser::
Chris Lattner8da0c282018-06-29 11:15:56 -0700236parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700237 const std::function<ParseResult()> &parseElement,
238 bool allowEmptyList) {
239 // Handle the empty case.
240 if (curToken.is(rightToken)) {
241 if (!allowEmptyList)
242 return emitError("expected list element");
243 consumeToken(rightToken);
244 return ParseSuccess;
245 }
246
247 // Non-empty case starts with an element.
248 if (parseElement())
249 return ParseFailure;
250
251 // Otherwise we have a list of comma separated elements.
252 while (consumeIf(Token::comma)) {
253 if (parseElement())
254 return ParseFailure;
255 }
256
257 // Consume the end character.
258 if (!consumeIf(rightToken))
Chris Lattner8da0c282018-06-29 11:15:56 -0700259 return emitError("expected ',' or '" + Token::getTokenSpelling(rightToken) +
260 "'");
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700261
262 return ParseSuccess;
263}
Chris Lattnere79379a2018-06-22 10:39:19 -0700264
265//===----------------------------------------------------------------------===//
266// Type Parsing
267//===----------------------------------------------------------------------===//
268
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700269/// Parse the low-level fixed dtypes in the system.
270///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700271/// primitive-type ::= `f16` | `bf16` | `f32` | `f64`
272/// primitive-type ::= integer-type
273/// primitive-type ::= `affineint`
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700274///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700275Type *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700276 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700277 default:
278 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700279 case Token::kw_bf16:
280 consumeToken(Token::kw_bf16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700281 return Type::getBF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700282 case Token::kw_f16:
283 consumeToken(Token::kw_f16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700284 return Type::getF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700285 case Token::kw_f32:
286 consumeToken(Token::kw_f32);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700287 return Type::getF32(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700288 case Token::kw_f64:
289 consumeToken(Token::kw_f64);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700290 return Type::getF64(context);
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700291 case Token::kw_affineint:
292 consumeToken(Token::kw_affineint);
293 return Type::getAffineInt(context);
294 case Token::inttype: {
295 auto width = curToken.getIntTypeBitwidth();
296 if (!width.hasValue())
297 return (emitError("invalid integer width"), nullptr);
298 consumeToken(Token::inttype);
299 return Type::getInt(width.getValue(), context);
300 }
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700301 }
302}
303
304/// Parse the element type of a tensor or memref type.
305///
306/// element-type ::= primitive-type | vector-type
307///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700308Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700309 if (curToken.is(Token::kw_vector))
310 return parseVectorType();
311
312 return parsePrimitiveType();
313}
314
315/// Parse a vector type.
316///
317/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
318/// const-dimension-list ::= (integer-literal `x`)+
319///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700320VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700321 consumeToken(Token::kw_vector);
322
323 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700324 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700325
326 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700327 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700328
329 SmallVector<unsigned, 4> dimensions;
330 while (curToken.is(Token::integer)) {
331 // Make sure this integer value is in bound and valid.
332 auto dimension = curToken.getUnsignedIntegerValue();
333 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700334 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700335 dimensions.push_back(dimension.getValue());
336
337 consumeToken(Token::integer);
338
339 // Make sure we have an 'x' or something like 'xbf32'.
340 if (curToken.isNot(Token::bare_identifier) ||
341 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700342 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700343
344 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
345 if (curToken.getSpelling().size() != 1)
346 lex.resetPointer(curToken.getSpelling().data()+1);
347
348 // Consume the 'x'.
349 consumeToken(Token::bare_identifier);
350 }
351
352 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700353 auto *elementType = parsePrimitiveType();
354 if (!elementType)
355 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700356
357 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700358 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700359
Chris Lattnerf7e22732018-06-22 22:03:48 -0700360 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700361}
362
363/// Parse a dimension list of a tensor or memref type. This populates the
364/// dimension list, returning -1 for the '?' dimensions.
365///
366/// dimension-list-ranked ::= (dimension `x`)*
367/// dimension ::= `?` | integer-literal
368///
369ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
370 while (curToken.isAny(Token::integer, Token::question)) {
371 if (consumeIf(Token::question)) {
372 dimensions.push_back(-1);
373 } else {
374 // Make sure this integer value is in bound and valid.
375 auto dimension = curToken.getUnsignedIntegerValue();
376 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
377 return emitError("invalid dimension");
378 dimensions.push_back((int)dimension.getValue());
379 consumeToken(Token::integer);
380 }
381
382 // Make sure we have an 'x' or something like 'xbf32'.
383 if (curToken.isNot(Token::bare_identifier) ||
384 curToken.getSpelling()[0] != 'x')
385 return emitError("expected 'x' in dimension list");
386
387 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
388 if (curToken.getSpelling().size() != 1)
389 lex.resetPointer(curToken.getSpelling().data()+1);
390
391 // Consume the 'x'.
392 consumeToken(Token::bare_identifier);
393 }
394
395 return ParseSuccess;
396}
397
398/// Parse a tensor type.
399///
400/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
401/// dimension-list ::= dimension-list-ranked | `??`
402///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700403Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700404 consumeToken(Token::kw_tensor);
405
406 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700407 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700408
409 bool isUnranked;
410 SmallVector<int, 4> dimensions;
411
412 if (consumeIf(Token::questionquestion)) {
413 isUnranked = true;
414 } else {
415 isUnranked = false;
416 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700417 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700418 }
419
420 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700421 auto elementType = parseElementType();
422 if (!elementType)
423 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700424
425 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700426 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700427
MLIR Team355ec862018-06-23 18:09:09 -0700428 if (isUnranked)
429 return UnrankedTensorType::get(elementType);
430 return RankedTensorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700431}
432
433/// Parse a memref type.
434///
435/// memref-type ::= `memref` `<` dimension-list-ranked element-type
436/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
437///
438/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
439/// memory-space ::= integer-literal /* | TODO: address-space-id */
440///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700441Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700442 consumeToken(Token::kw_memref);
443
444 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700445 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700446
447 SmallVector<int, 4> dimensions;
448 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700449 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700450
451 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700452 auto elementType = parseElementType();
453 if (!elementType)
454 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700455
456 // TODO: Parse semi-affine-map-composition.
457 // TODO: Parse memory-space.
458
459 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700460 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700461
Chris Lattnerf7e22732018-06-22 22:03:48 -0700462 // FIXME: Add an IR representation for memref types.
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700463 return Type::getInt(1, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700464}
465
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700466/// Parse a function type.
467///
468/// function-type ::= type-list-parens `->` type-list
469///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700470Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700471 assert(curToken.is(Token::l_paren));
472
Chris Lattnerf7e22732018-06-22 22:03:48 -0700473 SmallVector<Type*, 4> arguments;
474 if (parseTypeList(arguments))
475 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700476
477 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700478 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700479
Chris Lattnerf7e22732018-06-22 22:03:48 -0700480 SmallVector<Type*, 4> results;
481 if (parseTypeList(results))
482 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700483
Chris Lattnerf7e22732018-06-22 22:03:48 -0700484 return FunctionType::get(arguments, results, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700485}
486
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700487/// Parse an arbitrary type.
488///
489/// type ::= primitive-type
490/// | vector-type
491/// | tensor-type
492/// | memref-type
493/// | function-type
494/// element-type ::= primitive-type | vector-type
495///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700496Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700497 switch (curToken.getKind()) {
498 case Token::kw_memref: return parseMemRefType();
499 case Token::kw_tensor: return parseTensorType();
500 case Token::kw_vector: return parseVectorType();
501 case Token::l_paren: return parseFunctionType();
502 default:
503 return parsePrimitiveType();
504 }
505}
506
507/// Parse a "type list", which is a singular type, or a parenthesized list of
508/// types.
509///
510/// type-list ::= type-list-parens | type
511/// type-list-parens ::= `(` `)`
512/// | `(` type (`,` type)* `)`
513///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700514ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
515 auto parseElt = [&]() -> ParseResult {
516 auto elt = parseType();
517 elements.push_back(elt);
518 return elt ? ParseSuccess : ParseFailure;
519 };
520
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700521 // If there is no parens, then it must be a singular type.
522 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700523 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700524
Chris Lattnerf7e22732018-06-22 22:03:48 -0700525 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700526 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700527
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700528 return ParseSuccess;
529}
530
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700531namespace {
532/// This class represents the transient parser state while parsing an affine
533/// expression.
534class AffineMapParserState {
535 public:
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700536 explicit AffineMapParserState() {}
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700537
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700538 void addDim(StringRef sRef) { dims.insert({sRef, dims.size()}); }
539 void addSymbol(StringRef sRef) { symbols.insert({sRef, symbols.size()}); }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700540
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700541 unsigned getNumDims() const { return dims.size(); }
542 unsigned getNumSymbols() const { return symbols.size(); }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700543
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700544 // TODO(bondhugula): could just use an vector/ArrayRef and scan the numbers.
545 const llvm::StringMap<unsigned> &getDims() const { return dims; }
546 const llvm::StringMap<unsigned> &getSymbols() const { return symbols; }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700547
548 private:
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700549 llvm::StringMap<unsigned> dims;
550 llvm::StringMap<unsigned> symbols;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700551};
552} // end anonymous namespace
553
Chris Lattner4c95a502018-06-23 16:03:42 -0700554//===----------------------------------------------------------------------===//
Chris Lattner7121b802018-07-04 20:45:39 -0700555// Attribute parsing.
556//===----------------------------------------------------------------------===//
557
558
559/// Attribute parsing.
560///
561/// attribute-value ::= bool-literal
562/// | integer-literal
563/// | float-literal
564/// | string-literal
565/// | `[` (attribute-value (`,` attribute-value)*)? `]`
566///
567Attribute *Parser::parseAttribute() {
568 switch (curToken.getKind()) {
569 case Token::kw_true:
570 consumeToken(Token::kw_true);
571 return BoolAttr::get(true, context);
572 case Token::kw_false:
573 consumeToken(Token::kw_false);
574 return BoolAttr::get(false, context);
575
576 case Token::integer: {
577 auto val = curToken.getUInt64IntegerValue();
578 if (!val.hasValue() || (int64_t)val.getValue() < 0)
579 return (emitError("integer too large for attribute"), nullptr);
580 consumeToken(Token::integer);
581 return IntegerAttr::get((int64_t)val.getValue(), context);
582 }
583
584 case Token::minus: {
585 consumeToken(Token::minus);
586 if (curToken.is(Token::integer)) {
587 auto val = curToken.getUInt64IntegerValue();
588 if (!val.hasValue() || (int64_t)-val.getValue() >= 0)
589 return (emitError("integer too large for attribute"), nullptr);
590 consumeToken(Token::integer);
591 return IntegerAttr::get((int64_t)-val.getValue(), context);
592 }
593
594 return (emitError("expected constant integer or floating point value"),
595 nullptr);
596 }
597
598 case Token::string: {
599 auto val = curToken.getStringValue();
600 consumeToken(Token::string);
601 return StringAttr::get(val, context);
602 }
603
604 case Token::l_bracket: {
605 consumeToken(Token::l_bracket);
606 SmallVector<Attribute*, 4> elements;
607
608 auto parseElt = [&]() -> ParseResult {
609 elements.push_back(parseAttribute());
610 return elements.back() ? ParseSuccess : ParseFailure;
611 };
612
613 if (parseCommaSeparatedList(Token::r_bracket, parseElt))
614 return nullptr;
615 return ArrayAttr::get(elements, context);
616 }
617 default:
618 // TODO: Handle floating point.
619 return (emitError("expected constant attribute value"), nullptr);
620 }
621}
622
623
624/// Attribute dictionary.
625///
626/// attribute-dict ::= `{` `}`
627/// | `{` attribute-entry (`,` attribute-entry)* `}`
628/// attribute-entry ::= bare-id `:` attribute-value
629///
630ParseResult Parser::parseAttributeDict(
631 SmallVectorImpl<NamedAttribute> &attributes) {
632 consumeToken(Token::l_brace);
633
634 auto parseElt = [&]() -> ParseResult {
635 // We allow keywords as attribute names.
636 if (curToken.isNot(Token::bare_identifier, Token::inttype) &&
637 !curToken.isKeyword())
638 return emitError("expected attribute name");
639 auto nameId = Identifier::get(curToken.getSpelling(), context);
640 consumeToken();
641
642 if (!consumeIf(Token::colon))
643 return emitError("expected ':' in attribute list");
644
645 auto attr = parseAttribute();
646 if (!attr) return ParseFailure;
647
648 attributes.push_back({nameId, attr});
649 return ParseSuccess;
650 };
651
652 if (parseCommaSeparatedList(Token::r_brace, parseElt))
653 return ParseFailure;
654
655 return ParseSuccess;
656}
657
658//===----------------------------------------------------------------------===//
MLIR Teamf85a6262018-06-27 11:03:08 -0700659// Polyhedral structures.
660//===----------------------------------------------------------------------===//
661
662/// Affine map declaration.
663///
664/// affine-map-def ::= affine-map-id `=` affine-map-inline
MLIR Teamf85a6262018-06-27 11:03:08 -0700665///
666ParseResult Parser::parseAffineMapDef() {
Chris Lattner78276e32018-07-07 15:48:26 -0700667 assert(curToken.is(Token::hash_identifier));
MLIR Teamf85a6262018-06-27 11:03:08 -0700668
669 StringRef affineMapId = curToken.getSpelling().drop_front();
Chris Lattner7121b802018-07-04 20:45:39 -0700670
671 // Check for redefinitions.
672 auto *&entry = affineMapDefinitions[affineMapId];
673 if (entry)
674 return emitError("redefinition of affine map id '" + affineMapId + "'");
675
Chris Lattner78276e32018-07-07 15:48:26 -0700676 consumeToken(Token::hash_identifier);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700677
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700678 // Parse the '='
679 if (!consumeIf(Token::equal))
680 return emitError("expected '=' in affine map outlined definition");
MLIR Teamf85a6262018-06-27 11:03:08 -0700681
Chris Lattner7121b802018-07-04 20:45:39 -0700682 entry = parseAffineMapInline(affineMapId);
683 if (!entry)
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700684 return ParseFailure;
MLIR Teamf85a6262018-06-27 11:03:08 -0700685
Chris Lattner7121b802018-07-04 20:45:39 -0700686 module->affineMapList.push_back(entry);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700687 return ParseSuccess;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700688}
689
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700690/// Create an affine op expression
691AffineBinaryOpExpr *Parser::getBinaryAffineOpExpr(AffineHighPrecOp op,
692 AffineExpr *lhs,
693 AffineExpr *rhs,
694 MLIRContext *context) {
695 switch (op) {
696 case Mul:
697 return AffineMulExpr::get(lhs, rhs, context);
698 case FloorDiv:
699 return AffineFloorDivExpr::get(lhs, rhs, context);
700 case CeilDiv:
701 return AffineCeilDivExpr::get(lhs, rhs, context);
702 case Mod:
703 return AffineModExpr::get(lhs, rhs, context);
704 case HNoOp:
705 llvm_unreachable("can't create affine expression for null high prec op");
706 return nullptr;
707 }
708}
709
710AffineBinaryOpExpr *Parser::getBinaryAffineOpExpr(AffineLowPrecOp op,
711 AffineExpr *lhs,
712 AffineExpr *rhs,
713 MLIRContext *context) {
714 switch (op) {
715 case AffineLowPrecOp::Add:
716 return AffineAddExpr::get(lhs, rhs, context);
717 case AffineLowPrecOp::Sub:
718 return AffineSubExpr::get(lhs, rhs, context);
719 case AffineLowPrecOp::LNoOp:
720 llvm_unreachable("can't create affine expression for null low prec op");
721 return nullptr;
722 }
723}
724
725/// Parses an expression that can be a valid operand of an affine expression
726/// (where associativity may not have been specified through parentheses).
727// Eg: for an expression without parentheses (like i + j + k + l), each
728// of the four identifiers is an operand. For: i + j*k + l, j*k is not an
729// operand expression, it's an op expression and will be parsed via
730// parseAffineLowPrecOpExpression().
731ParseResult Parser::parseAffineOperandExpr(const AffineMapParserState &state,
732 AffineExpr *&result) {
733 result = parseParentheticalExpr(state);
734 if (!result)
735 result = parseBareIdExpr(state);
736 if (!result)
737 result = parseIntegerExpr(state);
738 return result ? ParseSuccess : ParseFailure;
739}
740
741/// Parse a high precedence op expression list: mul, div, and mod are high
742/// precedence binary ops, i.e., parse a
743/// expr_1 op_1 expr_2 op_2 ... expr_n
744/// where op_1, op_2 are all a AffineHighPrecOp (mul, div, mod).
745/// All affine binary ops are left associative.
746/// Given llhs, returns (llhs * lhs) * rhs, or (lhs * rhs) if llhs is null. If
747/// no rhs can be found, returns (llhs * lhs) or lhs if llhs is null.
748// TODO(bondhugula): check whether mul is w.r.t. a constant - otherwise, the
749/// map is semi-affine.
750ParseResult Parser::parseAffineHighPrecOpExpr(AffineExpr *llhs,
751 AffineHighPrecOp llhsOp,
752 const AffineMapParserState &state,
753 AffineExpr *&result) {
754 // FIXME: Assume for now that llhsOp is mul.
755 AffineExpr *lhs = nullptr;
756 if (parseAffineOperandExpr(state, lhs)) {
757 return ParseFailure;
758 }
759 AffineHighPrecOp op = HNoOp;
760 // Found an LHS. Parse the remaining expression.
761 if ((op = consumeIfHighPrecOp())) {
762 if (llhs) {
763 // TODO(bondhugula): check whether 'lhs' here is a constant (for affine
764 // maps); semi-affine maps allow symbols.
765 AffineExpr *expr =
766 Parser::getBinaryAffineOpExpr(llhsOp, llhs, lhs, context);
767 AffineExpr *subRes = nullptr;
768 if (parseAffineHighPrecOpExpr(expr, op, state, subRes)) {
769 if (!subRes)
770 emitError("missing right operand of multiply op");
771 // In spite of the error, setting result to prevent duplicate errors
772 // messages as the call stack unwinds. All of this due to left
773 // associativity.
774 result = expr;
775 return ParseFailure;
776 }
777 result = subRes ? subRes : expr;
778 return ParseSuccess;
779 }
780 // No LLHS, get RHS
781 AffineExpr *subRes = nullptr;
782 if (parseAffineHighPrecOpExpr(lhs, op, state, subRes)) {
783 // 'product' needs to be checked to prevent duplicate errors messages as
784 // the call stack unwinds. All of this due to left associativity.
785 if (!subRes)
786 emitError("missing right operand of multiply op");
787 return ParseFailure;
788 }
789 result = subRes;
790 return ParseSuccess;
791 }
792
793 // This is the last operand in this expression.
794 if (llhs) {
795 // TODO(bondhugula): check whether lhs here is a constant (for affine
796 // maps); semi-affine maps allow symbols.
797 result = Parser::getBinaryAffineOpExpr(llhsOp, llhs, lhs, context);
798 return ParseSuccess;
799 }
800
801 // No llhs, 'lhs' itself is the expression.
802 result = lhs;
803 return ParseSuccess;
804}
805
806/// Consume this token if it is a lower precedence affine op (there are only two
807/// precedence levels)
808AffineLowPrecOp Parser::consumeIfLowPrecOp() {
809 switch (curToken.getKind()) {
810 case Token::plus:
811 consumeToken(Token::plus);
812 return AffineLowPrecOp::Add;
813 case Token::minus:
814 consumeToken(Token::minus);
815 return AffineLowPrecOp::Sub;
816 default:
817 return AffineLowPrecOp::LNoOp;
818 }
819}
820
821/// Consume this token if it is a higher precedence affine op (there are only
822/// two precedence levels)
823AffineHighPrecOp Parser::consumeIfHighPrecOp() {
824 switch (curToken.getKind()) {
825 case Token::star:
826 consumeToken(Token::star);
827 return Mul;
828 case Token::kw_floordiv:
829 consumeToken(Token::kw_floordiv);
830 return FloorDiv;
831 case Token::kw_ceildiv:
832 consumeToken(Token::kw_ceildiv);
833 return CeilDiv;
834 case Token::kw_mod:
835 consumeToken(Token::kw_mod);
836 return Mod;
837 default:
838 return HNoOp;
839 }
840}
841
842/// Parse affine expressions that are bare-id's, integer constants,
843/// parenthetical affine expressions, and affine op expressions that are a
844/// composition of those.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700845///
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700846/// All binary op's associate from left to right.
847///
848/// {add, sub} have lower precedence than {mul, div, and mod}.
849///
850/// Add, sub'are themselves at the same precedence level. mul, div, and mod are
851/// at the same higher precedence level.
852///
853/// llhs: the affine expression appearing on the left of the one being parsed.
854/// This function will return ((llhs + lhs) + rhs) if llhs is non null, and
855/// lhs + rhs otherwise; if there is no rhs, llhs + lhs is returned if llhs is
856/// non-null; otherwise lhs is returned. This is to deal with left
857/// associativity.
858///
859/// Eg: when the expression is e1 + e2*e3 + e4, with e1 as llhs, this function
860/// will return the affine expr equivalent of (e1 + (e2*e3)) + e4.
861///
862// TODO(bondhugula): add support for unary op negation. Assuming for now that
863// the op to associate with llhs is add.
864ParseResult Parser::parseAffineLowPrecOpExpr(AffineExpr *llhs,
865 AffineLowPrecOp llhsOp,
866 const AffineMapParserState &state,
867 AffineExpr *&result) {
868 AffineExpr *lhs = nullptr;
869 if (parseAffineOperandExpr(state, lhs))
870 return ParseFailure;
871
872 // Found an LHS. Deal with the ops.
873 AffineLowPrecOp lOp;
874 AffineHighPrecOp rOp;
875 if ((lOp = consumeIfLowPrecOp())) {
876 if (llhs) {
877 AffineExpr *sum =
878 Parser::getBinaryAffineOpExpr(llhsOp, llhs, lhs, context);
879 AffineExpr *recSum = nullptr;
880 parseAffineLowPrecOpExpr(sum, lOp, state, recSum);
881 result = recSum ? recSum : sum;
882 return ParseSuccess;
883 }
884 // No LLHS, get RHS and form the expression.
885 if (parseAffineLowPrecOpExpr(lhs, lOp, state, result)) {
886 if (!result)
887 emitError("missing right operand of add op");
888 return ParseFailure;
889 }
890 return ParseSuccess;
891 } else if ((rOp = consumeIfHighPrecOp())) {
892 // We have a higher precedence op here. Get the rhs operand for the llhs
893 // through parseAffineHighPrecOpExpr.
894 AffineExpr *highRes = nullptr;
895 if (parseAffineHighPrecOpExpr(lhs, rOp, state, highRes)) {
896 // 'product' needs to be checked to prevent duplicate errors messages as
897 // the call stack unwinds. All of this due to left associativity.
898 if (!highRes)
899 emitError("missing right operand of binary op");
900 return ParseFailure;
901 }
902 // If llhs is null, the product forms the first operand of the yet to be
903 // found expression. If non-null, assume for now that the op to associate
904 // with llhs is add.
905 AffineExpr *expr =
906 llhs ? getBinaryAffineOpExpr(llhsOp, llhs, highRes, context) : highRes;
907 // Recurse for subsequent add's after the affine mul expression
908 AffineLowPrecOp nextOp = consumeIfLowPrecOp();
909 if (nextOp) {
910 AffineExpr *sumProd = nullptr;
911 parseAffineLowPrecOpExpr(expr, nextOp, state, sumProd);
912 result = sumProd ? sumProd : expr;
913 } else {
914 result = expr;
915 }
916 return ParseSuccess;
917 } else {
918 // Last operand in the expression list.
919 if (llhs) {
920 result = Parser::getBinaryAffineOpExpr(llhsOp, llhs, lhs, context);
921 return ParseSuccess;
922 }
923 // No llhs, 'lhs' itself is the expression.
924 result = lhs;
925 return ParseSuccess;
926 }
927}
928
929/// Parse an affine expression inside parentheses.
930/// affine-expr ::= `(` affine-expr `)`
931AffineExpr *Parser::parseParentheticalExpr(const AffineMapParserState &state) {
932 if (!consumeIf(Token::l_paren)) {
933 return nullptr;
934 }
935 auto *expr = parseAffineExpr(state);
936 if (!consumeIf(Token::r_paren)) {
937 emitError("expected ')'");
938 return nullptr;
939 }
940 if (!expr)
941 emitError("no expression inside parentheses");
942 return expr;
943}
944
945/// Parse a bare id that may appear in an affine expression.
946/// affine-expr ::= bare-id
947AffineExpr *Parser::parseBareIdExpr(const AffineMapParserState &state) {
948 if (curToken.is(Token::bare_identifier)) {
949 StringRef sRef = curToken.getSpelling();
950 const auto &dims = state.getDims();
951 const auto &symbols = state.getSymbols();
952 if (dims.count(sRef)) {
953 consumeToken(Token::bare_identifier);
954 return AffineDimExpr::get(dims.lookup(sRef), context);
955 }
956 if (symbols.count(sRef)) {
957 consumeToken(Token::bare_identifier);
958 return AffineSymbolExpr::get(symbols.lookup(sRef), context);
959 }
960 return emitError("identifier is neither dimensional nor symbolic"), nullptr;
961 }
962 return nullptr;
963}
964
965/// Parse an integral constant appearing in an affine expression.
966/// affine-expr ::= `-`? integer-literal
967/// TODO(bondhugula): handle negative numbers.
968AffineExpr *Parser::parseIntegerExpr(const AffineMapParserState &state) {
969 if (curToken.is(Token::integer)) {
970 auto *expr = AffineConstantExpr::get(
971 curToken.getUnsignedIntegerValue().getValue(), context);
972 consumeToken(Token::integer);
973 return expr;
974 }
975 return nullptr;
976}
977
978/// Parse an affine expression.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700979/// affine-expr ::= `(` affine-expr `)`
980/// | affine-expr `+` affine-expr
981/// | affine-expr `-` affine-expr
982/// | `-`? integer-literal `*` affine-expr
983/// | `ceildiv` `(` affine-expr `,` integer-literal `)`
984/// | `floordiv` `(` affine-expr `,` integer-literal `)`
985/// | affine-expr `mod` integer-literal
986/// | bare-id
987/// | `-`? integer-literal
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700988/// Use 'state' to check if valid identifiers appear.
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700989// TODO(bondhugula): check if mul, mod, div take integral constants
990AffineExpr *Parser::parseAffineExpr(const AffineMapParserState &state) {
991 switch (curToken.getKind()) {
992 case Token::l_paren:
993 case Token::kw_ceildiv:
994 case Token::kw_floordiv:
995 case Token::bare_identifier:
996 case Token::integer: {
997 AffineExpr *result = nullptr;
998 parseAffineLowPrecOpExpr(nullptr, AffineLowPrecOp::LNoOp, state, result);
999 return result;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001000 }
1001
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001002 case Token::plus:
1003 case Token::minus:
1004 case Token::star:
1005 emitError("left operand of binary op missing");
1006 return nullptr;
1007
1008 default:
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001009 return nullptr;
1010 }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001011}
1012
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001013/// Parse a dim or symbol from the lists appearing before the actual expressions
1014/// of the affine map. Update state to store the dimensional/symbolic
1015/// identifier. 'dim': whether it's the dim list or symbol list that is being
1016/// parsed.
1017ParseResult Parser::parseDimOrSymbolId(AffineMapParserState &state, bool dim) {
1018 if (curToken.isNot(Token::bare_identifier))
1019 return emitError("expected bare identifier");
1020 auto sRef = curToken.getSpelling();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001021 consumeToken(Token::bare_identifier);
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001022 if (state.getDims().count(sRef) == 1)
1023 return emitError("dimensional identifier name reused");
1024 if (state.getSymbols().count(sRef) == 1)
1025 return emitError("symbolic identifier name reused");
1026 if (dim)
1027 state.addDim(sRef);
1028 else
1029 state.addSymbol(sRef);
1030 return ParseSuccess;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001031}
1032
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001033/// Parse the list of symbolic identifiers to an affine map.
1034ParseResult Parser::parseSymbolIdList(AffineMapParserState &state) {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001035 if (!consumeIf(Token::l_bracket)) return emitError("expected '['");
1036
1037 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001038 return parseDimOrSymbolId(state, false);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001039 };
1040 return parseCommaSeparatedList(Token::r_bracket, parseElt);
1041}
1042
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001043/// Parse the list of dimensional identifiers to an affine map.
1044ParseResult Parser::parseDimIdList(AffineMapParserState &state) {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001045 if (!consumeIf(Token::l_paren))
1046 return emitError("expected '(' at start of dimensional identifiers list");
1047
1048 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001049 return parseDimOrSymbolId(state, true);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001050 };
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001051 return parseCommaSeparatedList(Token::r_paren, parseElt);
1052}
1053
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001054/// Parse an affine map definition.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001055///
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001056/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001057/// ( `size` `(` dim-size (`,` dim-size)* `)` )?
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001058/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001059///
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001060/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
Chris Lattner7121b802018-07-04 20:45:39 -07001061AffineMap *Parser::parseAffineMapInline(StringRef mapId) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001062 AffineMapParserState state;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001063
1064 // List of dimensional identifiers.
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001065 if (parseDimIdList(state))
Chris Lattner7121b802018-07-04 20:45:39 -07001066 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001067
1068 // Symbols are optional.
1069 if (curToken.is(Token::l_bracket)) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001070 if (parseSymbolIdList(state))
Chris Lattner7121b802018-07-04 20:45:39 -07001071 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001072 }
1073 if (!consumeIf(Token::arrow)) {
Chris Lattner7121b802018-07-04 20:45:39 -07001074 return (emitError("expected '->' or '['"), nullptr);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001075 }
1076 if (!consumeIf(Token::l_paren)) {
1077 emitError("expected '(' at start of affine map range");
Chris Lattner7121b802018-07-04 20:45:39 -07001078 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001079 }
1080
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001081 SmallVector<AffineExpr *, 4> exprs;
1082 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001083 auto *elt = parseAffineExpr(state);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001084 ParseResult res = elt ? ParseSuccess : ParseFailure;
1085 exprs.push_back(elt);
1086 return res;
1087 };
1088
1089 // Parse a multi-dimensional affine expression (a comma-separated list of 1-d
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001090 // affine expressions); the list cannot be empty.
1091 // Grammar: multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
1092 if (parseCommaSeparatedList(Token::r_paren, parseElt, false))
Chris Lattner7121b802018-07-04 20:45:39 -07001093 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001094
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001095 // Parsed a valid affine map.
Chris Lattner7121b802018-07-04 20:45:39 -07001096 return AffineMap::get(state.getNumDims(), state.getNumSymbols(), exprs,
1097 context);
MLIR Teamf85a6262018-06-27 11:03:08 -07001098}
1099
1100//===----------------------------------------------------------------------===//
Chris Lattner78276e32018-07-07 15:48:26 -07001101// SSA
Chris Lattner4c95a502018-06-23 16:03:42 -07001102//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -07001103
Chris Lattner78276e32018-07-07 15:48:26 -07001104/// Parse a SSA operand for an instruction or statement.
1105///
1106/// ssa-use ::= ssa-id | ssa-constant
1107///
1108ParseResult Parser::parseSSAUse() {
1109 if (curToken.is(Token::percent_identifier)) {
1110 StringRef name = curToken.getSpelling().drop_front();
1111 consumeToken(Token::percent_identifier);
1112 // TODO: Return this use.
1113 (void)name;
1114 return ParseSuccess;
1115 }
1116
1117 // TODO: Parse SSA constants.
1118
1119 return emitError("expected SSA operand");
1120}
1121
1122/// Parse a (possibly empty) list of SSA operands.
1123///
1124/// ssa-use-list ::= ssa-use (`,` ssa-use)*
1125/// ssa-use-list-opt ::= ssa-use-list?
1126///
1127ParseResult Parser::parseOptionalSSAUseList(Token::Kind endToken) {
1128 // TODO: Build and return this.
1129 return parseCommaSeparatedList(
1130 endToken, [&]() -> ParseResult { return parseSSAUse(); });
1131}
1132
1133/// Parse an SSA use with an associated type.
1134///
1135/// ssa-use-and-type ::= ssa-use `:` type
1136ParseResult Parser::parseSSAUseAndType() {
1137 if (parseSSAUse())
1138 return ParseFailure;
1139
1140 if (!consumeIf(Token::colon))
1141 return emitError("expected ':' and type for SSA operand");
1142
1143 if (!parseType())
1144 return ParseFailure;
1145
1146 return ParseSuccess;
1147}
1148
1149/// Parse a (possibly empty) list of SSA operands with types.
1150///
1151/// ssa-use-and-type-list ::= ssa-use-and-type (`,` ssa-use-and-type)*
1152///
1153ParseResult Parser::parseOptionalSSAUseAndTypeList(Token::Kind endToken) {
1154 // TODO: Build and return this.
1155 return parseCommaSeparatedList(
1156 endToken, [&]() -> ParseResult { return parseSSAUseAndType(); });
1157}
1158
1159//===----------------------------------------------------------------------===//
1160// Functions
1161//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -07001162
1163/// Parse a function signature, starting with a name and including the parameter
1164/// list.
1165///
1166/// argument-list ::= type (`,` type)* | /*empty*/
1167/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
1168///
Chris Lattnerf7e22732018-06-22 22:03:48 -07001169ParseResult Parser::parseFunctionSignature(StringRef &name,
1170 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -07001171 if (curToken.isNot(Token::at_identifier))
1172 return emitError("expected a function identifier like '@foo'");
1173
1174 name = curToken.getSpelling().drop_front();
1175 consumeToken(Token::at_identifier);
1176
1177 if (curToken.isNot(Token::l_paren))
1178 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -07001179
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001180 SmallVector<Type*, 4> arguments;
1181 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001182 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -07001183
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001184 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -07001185 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001186 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -07001187 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001188 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001189 }
Chris Lattnerf7e22732018-06-22 22:03:48 -07001190 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -07001191 return ParseSuccess;
1192}
1193
Chris Lattnere79379a2018-06-22 10:39:19 -07001194/// External function declarations.
1195///
1196/// ext-func ::= `extfunc` function-signature
1197///
1198ParseResult Parser::parseExtFunc() {
1199 consumeToken(Token::kw_extfunc);
1200
1201 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -07001202 FunctionType *type = nullptr;
1203 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -07001204 return ParseFailure;
1205
Chris Lattnere79379a2018-06-22 10:39:19 -07001206 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -07001207 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -07001208 return ParseSuccess;
1209}
1210
1211
Chris Lattner4c95a502018-06-23 16:03:42 -07001212namespace {
1213/// This class represents the transient parser state for the internals of a
1214/// function as we are parsing it, e.g. the names for basic blocks. It handles
1215/// forward references.
1216class CFGFunctionParserState {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001217 public:
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001218 CFGFunction *function;
1219 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
1220
Chris Lattner4c95a502018-06-23 16:03:42 -07001221 CFGFunctionParserState(CFGFunction *function) : function(function) {}
1222
1223 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001224 /// already exist. The location specified is the point of use, which allows
1225 /// us to diagnose references to blocks that are not defined precisely.
1226 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
1227 auto &blockAndLoc = blocksByName[name];
1228 if (!blockAndLoc.first) {
Chris Lattner3a467cc2018-07-01 20:28:00 -07001229 blockAndLoc.first = new BasicBlock();
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001230 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -07001231 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001232 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -07001233 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001234};
1235} // end anonymous namespace
1236
1237
1238/// CFG function declarations.
1239///
1240/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
1241///
1242ParseResult Parser::parseCFGFunc() {
1243 consumeToken(Token::kw_cfgfunc);
1244
1245 StringRef name;
1246 FunctionType *type = nullptr;
1247 if (parseFunctionSignature(name, type))
1248 return ParseFailure;
1249
1250 if (!consumeIf(Token::l_brace))
1251 return emitError("expected '{' in CFG function");
1252
1253 // Okay, the CFG function signature was parsed correctly, create the function.
1254 auto function = new CFGFunction(name, type);
1255
1256 // Make sure we have at least one block.
1257 if (curToken.is(Token::r_brace))
1258 return emitError("CFG functions must have at least one basic block");
1259
1260 CFGFunctionParserState functionState(function);
1261
1262 // Parse the list of blocks.
1263 while (!consumeIf(Token::r_brace))
1264 if (parseBasicBlock(functionState))
1265 return ParseFailure;
1266
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001267 // Verify that all referenced blocks were defined. Iteration over a
1268 // StringMap isn't determinstic, but this is good enough for our purposes.
1269 for (auto &elt : functionState.blocksByName) {
1270 auto *bb = elt.second.first;
Chris Lattner3a467cc2018-07-01 20:28:00 -07001271 if (!bb->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001272 return emitError(elt.second.second,
1273 "reference to an undefined basic block '" +
1274 elt.first() + "'");
1275 }
1276
Chris Lattner4c95a502018-06-23 16:03:42 -07001277 module->functionList.push_back(function);
1278 return ParseSuccess;
1279}
1280
1281/// Basic block declaration.
1282///
1283/// basic-block ::= bb-label instruction* terminator-stmt
1284/// bb-label ::= bb-id bb-arg-list? `:`
1285/// bb-id ::= bare-id
1286/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
1287///
1288ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
1289 SMLoc nameLoc = curToken.getLoc();
1290 auto name = curToken.getSpelling();
1291 if (!consumeIf(Token::bare_identifier))
1292 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001293
1294 auto block = functionState.getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -07001295
1296 // If this block has already been parsed, then this is a redefinition with the
1297 // same block name.
Chris Lattner3a467cc2018-07-01 20:28:00 -07001298 if (block->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001299 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
1300
Chris Lattner3a467cc2018-07-01 20:28:00 -07001301 // Add the block to the function.
1302 functionState.function->push_back(block);
Chris Lattner4c95a502018-06-23 16:03:42 -07001303
Chris Lattner78276e32018-07-07 15:48:26 -07001304 // If an argument list is present, parse it.
1305 if (consumeIf(Token::l_paren)) {
1306 if (parseOptionalSSAUseAndTypeList(Token::r_paren))
1307 return ParseFailure;
1308
1309 // TODO: attach it.
1310 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001311
1312 if (!consumeIf(Token::colon))
1313 return emitError("expected ':' after basic block name");
1314
Chris Lattnered65a732018-06-28 20:45:33 -07001315 // Parse the list of operations that make up the body of the block.
1316 while (curToken.isNot(Token::kw_return, Token::kw_br)) {
Chris Lattner21e67f62018-07-06 10:46:19 -07001317 auto loc = curToken.getLoc();
Chris Lattner3a467cc2018-07-01 20:28:00 -07001318 auto *inst = parseCFGOperation(functionState);
1319 if (!inst)
Chris Lattnered65a732018-06-28 20:45:33 -07001320 return ParseFailure;
Chris Lattner3a467cc2018-07-01 20:28:00 -07001321
Chris Lattner21e67f62018-07-06 10:46:19 -07001322 // We just parsed an operation. If it is a recognized one, verify that it
1323 // is structurally as we expect. If not, produce an error with a reasonable
1324 // source location.
1325 if (auto *opInfo = inst->getAbstractOperation(context))
1326 if (auto error = opInfo->verifyInvariants(inst))
1327 return emitError(loc, error);
1328
Chris Lattner3a467cc2018-07-01 20:28:00 -07001329 block->getOperations().push_back(inst);
Chris Lattnered65a732018-06-28 20:45:33 -07001330 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001331
Chris Lattner3a467cc2018-07-01 20:28:00 -07001332 auto *term = parseTerminator(functionState);
1333 if (!term)
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001334 return ParseFailure;
Chris Lattner3a467cc2018-07-01 20:28:00 -07001335 block->setTerminator(term);
Chris Lattner4c95a502018-06-23 16:03:42 -07001336
1337 return ParseSuccess;
1338}
1339
1340
Chris Lattnered65a732018-06-28 20:45:33 -07001341/// Parse the CFG operation.
1342///
1343/// TODO(clattner): This is a change from the MLIR spec as written, it is an
1344/// experiment that will eliminate "builtin" instructions as a thing.
1345///
1346/// cfg-operation ::=
1347/// (ssa-id `=`)? string '(' ssa-use-list? ')' attribute-dict?
1348/// `:` function-type
1349///
Chris Lattner3a467cc2018-07-01 20:28:00 -07001350OperationInst *Parser::
1351parseCFGOperation(CFGFunctionParserState &functionState) {
Chris Lattnered65a732018-06-28 20:45:33 -07001352
Chris Lattner78276e32018-07-07 15:48:26 -07001353 StringRef resultID;
1354 if (curToken.is(Token::percent_identifier)) {
1355 resultID = curToken.getSpelling().drop_front();
1356 consumeToken();
1357 if (!consumeIf(Token::equal))
1358 return (emitError("expected '=' after SSA name"), nullptr);
1359 }
Chris Lattnered65a732018-06-28 20:45:33 -07001360
1361 if (curToken.isNot(Token::string))
Chris Lattner3a467cc2018-07-01 20:28:00 -07001362 return (emitError("expected operation name in quotes"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001363
1364 auto name = curToken.getStringValue();
1365 if (name.empty())
Chris Lattner3a467cc2018-07-01 20:28:00 -07001366 return (emitError("empty operation name is invalid"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001367
1368 consumeToken(Token::string);
1369
1370 if (!consumeIf(Token::l_paren))
Chris Lattner7121b802018-07-04 20:45:39 -07001371 return (emitError("expected '(' to start operand list"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001372
Chris Lattner78276e32018-07-07 15:48:26 -07001373 // Parse the operand list.
1374 parseOptionalSSAUseList(Token::r_paren);
Chris Lattner7121b802018-07-04 20:45:39 -07001375
1376 SmallVector<NamedAttribute, 4> attributes;
1377 if (curToken.is(Token::l_brace)) {
1378 if (parseAttributeDict(attributes))
1379 return nullptr;
1380 }
Chris Lattnered65a732018-06-28 20:45:33 -07001381
Chris Lattner78276e32018-07-07 15:48:26 -07001382 // TODO: Don't drop result name and operand names on the floor.
Chris Lattnered65a732018-06-28 20:45:33 -07001383 auto nameId = Identifier::get(name, context);
Chris Lattnerdf1a2fc2018-07-05 21:20:59 -07001384 return new OperationInst(nameId, attributes, context);
Chris Lattnered65a732018-06-28 20:45:33 -07001385}
1386
1387
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001388/// Parse the terminator instruction for a basic block.
1389///
1390/// terminator-stmt ::= `br` bb-id branch-use-list?
1391/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
1392/// terminator-stmt ::=
1393/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
1394/// terminator-stmt ::= `return` ssa-use-and-type-list?
1395///
Chris Lattner3a467cc2018-07-01 20:28:00 -07001396TerminatorInst *Parser::parseTerminator(CFGFunctionParserState &functionState) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001397 switch (curToken.getKind()) {
1398 default:
Chris Lattner3a467cc2018-07-01 20:28:00 -07001399 return (emitError("expected terminator at end of basic block"), nullptr);
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001400
1401 case Token::kw_return:
1402 consumeToken(Token::kw_return);
Chris Lattner3a467cc2018-07-01 20:28:00 -07001403 return new ReturnInst();
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001404
1405 case Token::kw_br: {
1406 consumeToken(Token::kw_br);
1407 auto destBB = functionState.getBlockNamed(curToken.getSpelling(),
1408 curToken.getLoc());
1409 if (!consumeIf(Token::bare_identifier))
Chris Lattner3a467cc2018-07-01 20:28:00 -07001410 return (emitError("expected basic block name"), nullptr);
1411 return new BranchInst(destBB);
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001412 }
Chris Lattner78276e32018-07-07 15:48:26 -07001413 // TODO: cond_br.
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001414 }
1415}
1416
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001417/// ML function declarations.
1418///
1419/// ml-func ::= `mlfunc` ml-func-signature `{` ml-stmt* ml-return-stmt `}`
1420///
1421ParseResult Parser::parseMLFunc() {
1422 consumeToken(Token::kw_mlfunc);
1423
1424 StringRef name;
1425 FunctionType *type = nullptr;
1426
1427 // FIXME: Parse ML function signature (args + types)
1428 // by passing pointer to SmallVector<identifier> into parseFunctionSignature
1429 if (parseFunctionSignature(name, type))
1430 return ParseFailure;
1431
1432 if (!consumeIf(Token::l_brace))
1433 return emitError("expected '{' in ML function");
1434
1435 // Okay, the ML function signature was parsed correctly, create the function.
1436 auto function = new MLFunction(name, type);
1437
1438 // Make sure we have at least one statement.
1439 if (curToken.is(Token::r_brace))
1440 return emitError("ML function must end with return statement");
1441
1442 // Parse the list of instructions.
1443 while (!consumeIf(Token::kw_return)) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001444 auto *stmt = parseStatement(function);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001445 if (!stmt)
1446 return ParseFailure;
1447 function->stmtList.push_back(stmt);
1448 }
1449
1450 // TODO: parse return statement operands
1451 if (!consumeIf(Token::r_brace))
1452 emitError("expected '}' in ML function");
1453
1454 module->functionList.push_back(function);
1455
1456 return ParseSuccess;
1457}
1458
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001459/// Statement.
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001460///
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001461/// ml-stmt ::= instruction | ml-for-stmt | ml-if-stmt
1462/// TODO: fix terminology in MLSpec document. ML functions
1463/// contain operation statements, not instructions.
1464///
1465Statement * Parser::parseStatement(ParentType parent) {
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001466 switch (curToken.getKind()) {
1467 default:
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001468 //TODO: parse OperationStmt
1469 return (emitError("expected statement"), nullptr);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001470
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001471 case Token::kw_for:
1472 return parseForStmt(parent);
1473
1474 case Token::kw_if:
1475 return parseIfStmt(parent);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001476 }
1477}
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001478
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001479/// For statement.
1480///
1481/// ml-for-stmt ::= `for` ssa-id `=` lower-bound `to` upper-bound
1482/// (`step` integer-literal)? `{` ml-stmt* `}`
1483///
1484ForStmt * Parser::parseForStmt(ParentType parent) {
1485 consumeToken(Token::kw_for);
1486
1487 //TODO: parse loop header
1488 ForStmt *stmt = new ForStmt(parent);
1489 if (parseNestedStatements(stmt)) {
1490 delete stmt;
1491 return nullptr;
1492 }
1493 return stmt;
1494}
1495
1496/// If statement.
1497///
1498/// ml-if-head ::= `if` ml-if-cond `{` ml-stmt* `}`
1499/// | ml-if-head `else` `if` ml-if-cond `{` ml-stmt* `}`
1500/// ml-if-stmt ::= ml-if-head
1501/// | ml-if-head `else` `{` ml-stmt* `}`
1502///
1503IfStmt * Parser::parseIfStmt(PointerUnion<MLFunction *, NodeStmt *> parent) {
1504 consumeToken(Token::kw_if);
1505
1506 //TODO: parse condition
1507 IfStmt *stmt = new IfStmt(parent);
1508 if (parseNestedStatements(stmt)) {
1509 delete stmt;
1510 return nullptr;
1511 }
1512
1513 int clauseNum = 0;
1514 while (consumeIf(Token::kw_else)) {
1515 if (consumeIf(Token::kw_if)) {
1516 //TODO: parse condition
1517 }
1518 ElseClause * clause = new ElseClause(stmt, clauseNum);
1519 ++clauseNum;
1520 if (parseNestedStatements(clause)) {
1521 delete clause;
1522 return nullptr;
1523 }
1524 }
1525
1526 return stmt;
1527}
1528
1529///
1530/// Parse `{` ml-stmt* `}`
1531///
1532ParseResult Parser::parseNestedStatements(NodeStmt *parent) {
1533 if (!consumeIf(Token::l_brace))
1534 return emitError("expected '{' before statement list");
1535
1536 if (consumeIf(Token::r_brace)) {
1537 // TODO: parse OperationStmt
1538 return ParseSuccess;
1539 }
1540
1541 while (!consumeIf(Token::r_brace)) {
1542 auto *stmt = parseStatement(parent);
1543 if (!stmt)
1544 return ParseFailure;
1545 parent->children.push_back(stmt);
1546 }
1547
1548 return ParseSuccess;
1549}
1550
Chris Lattner4c95a502018-06-23 16:03:42 -07001551//===----------------------------------------------------------------------===//
1552// Top-level entity parsing.
1553//===----------------------------------------------------------------------===//
1554
Chris Lattnere79379a2018-06-22 10:39:19 -07001555/// This is the top-level module parser.
1556Module *Parser::parseModule() {
1557 while (1) {
1558 switch (curToken.getKind()) {
1559 default:
1560 emitError("expected a top level entity");
1561 return nullptr;
1562
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001563 // If we got to the end of the file, then we're done.
Chris Lattnere79379a2018-06-22 10:39:19 -07001564 case Token::eof:
1565 return module.release();
1566
1567 // If we got an error token, then the lexer already emitted an error, just
1568 // stop. Someday we could introduce error recovery if there was demand for
1569 // it.
1570 case Token::error:
1571 return nullptr;
1572
1573 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -07001574 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -07001575 break;
1576
Chris Lattner4c95a502018-06-23 16:03:42 -07001577 case Token::kw_cfgfunc:
1578 if (parseCFGFunc()) return nullptr;
1579 break;
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001580
Chris Lattner78276e32018-07-07 15:48:26 -07001581 case Token::hash_identifier:
MLIR Teamf85a6262018-06-27 11:03:08 -07001582 if (parseAffineMapDef()) return nullptr;
1583 break;
Chris Lattner4c95a502018-06-23 16:03:42 -07001584
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001585 case Token::kw_mlfunc:
1586 if (parseMLFunc()) return nullptr;
1587 break;
1588
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001589 // TODO: affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -07001590 }
1591 }
1592}
1593
1594//===----------------------------------------------------------------------===//
1595
Jacques Pienaar7b829702018-07-03 13:24:09 -07001596void mlir::defaultErrorReporter(const llvm::SMDiagnostic &error) {
1597 const auto &sourceMgr = *error.getSourceMgr();
1598 sourceMgr.PrintMessage(error.getLoc(), error.getKind(), error.getMessage());
1599}
1600
Chris Lattnere79379a2018-06-22 10:39:19 -07001601/// This parses the file specified by the indicated SourceMgr and returns an
1602/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Jacques Pienaar9c411be2018-06-24 19:17:35 -07001603Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context,
Jacques Pienaar7b829702018-07-03 13:24:09 -07001604 SMDiagnosticHandlerTy errorReporter) {
Chris Lattner21e67f62018-07-06 10:46:19 -07001605 auto *result =
1606 Parser(sourceMgr, context,
1607 errorReporter ? std::move(errorReporter) : defaultErrorReporter)
1608 .parseModule();
1609
1610 // Make sure the parse module has no other structural problems detected by the
1611 // verifier.
1612 if (result)
1613 result->verify();
1614 return result;
Chris Lattnere79379a2018-06-22 10:39:19 -07001615}