blob: b2fb4d67e012d418f201a8e7020688df2e43fed1 [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 Lattner158e0a3e2018-07-08 20:51:38 -070027#include "mlir/IR/Builders.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)
Chris Lattner158e0a3e2018-07-08 20:51:38 -070073 : builder(context), lex(sourceMgr, errorReporter),
Jacques Pienaar7b829702018-07-03 13:24:09 -070074 curToken(lex.lexToken()), errorReporter(std::move(errorReporter)) {
Chris Lattner158e0a3e2018-07-08 20:51:38 -070075 module.reset(new Module(context));
Chris Lattnere79379a2018-06-22 10:39:19 -070076 }
77
78 Module *parseModule();
79private:
80 // State.
Chris Lattner158e0a3e2018-07-08 20:51:38 -070081 Builder builder;
Chris Lattnerf7e22732018-06-22 22:03:48 -070082
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
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700173 AffineBinaryOpExpr *getBinaryAffineOpExpr(AffineHighPrecOp op,
174 AffineExpr *lhs, AffineExpr *rhs);
175 AffineBinaryOpExpr *getBinaryAffineOpExpr(AffineLowPrecOp op, AffineExpr *lhs,
176 AffineExpr *rhs);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700177 ParseResult parseAffineOperandExpr(const AffineMapParserState &state,
178 AffineExpr *&result);
179 ParseResult parseAffineLowPrecOpExpr(AffineExpr *llhs, AffineLowPrecOp llhsOp,
180 const AffineMapParserState &state,
181 AffineExpr *&result);
182 ParseResult parseAffineHighPrecOpExpr(AffineExpr *llhs,
183 AffineHighPrecOp llhsOp,
184 const AffineMapParserState &state,
185 AffineExpr *&result);
MLIR Teamf85a6262018-06-27 11:03:08 -0700186
Chris Lattner78276e32018-07-07 15:48:26 -0700187 // SSA
188 ParseResult parseSSAUse();
189 ParseResult parseOptionalSSAUseList(Token::Kind endToken);
190 ParseResult parseSSAUseAndType();
191 ParseResult parseOptionalSSAUseAndTypeList(Token::Kind endToken);
192
Chris Lattner4c95a502018-06-23 16:03:42 -0700193 // Functions.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700194 ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
Chris Lattnere79379a2018-06-22 10:39:19 -0700195 ParseResult parseExtFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700196 ParseResult parseCFGFunc();
197 ParseResult parseBasicBlock(CFGFunctionParserState &functionState);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700198 Statement *parseStatement(ParentType parent);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700199
Chris Lattner3a467cc2018-07-01 20:28:00 -0700200 OperationInst *parseCFGOperation(CFGFunctionParserState &functionState);
201 TerminatorInst *parseTerminator(CFGFunctionParserState &functionState);
Chris Lattnered65a732018-06-28 20:45:33 -0700202
Chris Lattner78276e32018-07-07 15:48:26 -0700203 ParseResult parseMLFunc();
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700204 ForStmt *parseForStmt(ParentType parent);
205 IfStmt *parseIfStmt(ParentType parent);
206 ParseResult parseNestedStatements(NodeStmt *parent);
Chris Lattnere79379a2018-06-22 10:39:19 -0700207};
208} // end anonymous namespace
209
210//===----------------------------------------------------------------------===//
211// Helper methods.
212//===----------------------------------------------------------------------===//
213
Chris Lattner4c95a502018-06-23 16:03:42 -0700214ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700215 // If we hit a parse error in response to a lexer error, then the lexer
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700216 // already reported the error.
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700217 if (curToken.is(Token::error))
218 return ParseFailure;
219
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700220 errorReporter(
221 lex.getSourceMgr().GetMessage(loc, SourceMgr::DK_Error, message));
Chris Lattnere79379a2018-06-22 10:39:19 -0700222 return ParseFailure;
223}
224
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700225/// Parse a comma-separated list of elements, terminated with an arbitrary
226/// token. This allows empty lists if allowEmptyList is true.
227///
228/// abstract-list ::= rightToken // if allowEmptyList == true
229/// abstract-list ::= element (',' element)* rightToken
230///
231ParseResult Parser::
Chris Lattner8da0c282018-06-29 11:15:56 -0700232parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700233 const std::function<ParseResult()> &parseElement,
234 bool allowEmptyList) {
235 // Handle the empty case.
236 if (curToken.is(rightToken)) {
237 if (!allowEmptyList)
238 return emitError("expected list element");
239 consumeToken(rightToken);
240 return ParseSuccess;
241 }
242
243 // Non-empty case starts with an element.
244 if (parseElement())
245 return ParseFailure;
246
247 // Otherwise we have a list of comma separated elements.
248 while (consumeIf(Token::comma)) {
249 if (parseElement())
250 return ParseFailure;
251 }
252
253 // Consume the end character.
254 if (!consumeIf(rightToken))
Chris Lattner8da0c282018-06-29 11:15:56 -0700255 return emitError("expected ',' or '" + Token::getTokenSpelling(rightToken) +
256 "'");
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700257
258 return ParseSuccess;
259}
Chris Lattnere79379a2018-06-22 10:39:19 -0700260
261//===----------------------------------------------------------------------===//
262// Type Parsing
263//===----------------------------------------------------------------------===//
264
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700265/// Parse the low-level fixed dtypes in the system.
266///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700267/// primitive-type ::= `f16` | `bf16` | `f32` | `f64`
268/// primitive-type ::= integer-type
269/// primitive-type ::= `affineint`
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700270///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700271Type *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700272 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700273 default:
274 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700275 case Token::kw_bf16:
276 consumeToken(Token::kw_bf16);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700277 return builder.getBF16Type();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700278 case Token::kw_f16:
279 consumeToken(Token::kw_f16);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700280 return builder.getF16Type();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700281 case Token::kw_f32:
282 consumeToken(Token::kw_f32);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700283 return builder.getF32Type();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700284 case Token::kw_f64:
285 consumeToken(Token::kw_f64);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700286 return builder.getF64Type();
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700287 case Token::kw_affineint:
288 consumeToken(Token::kw_affineint);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700289 return builder.getAffineIntType();
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700290 case Token::inttype: {
291 auto width = curToken.getIntTypeBitwidth();
292 if (!width.hasValue())
293 return (emitError("invalid integer width"), nullptr);
294 consumeToken(Token::inttype);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700295 return builder.getIntegerType(width.getValue());
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700296 }
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700297 }
298}
299
300/// Parse the element type of a tensor or memref type.
301///
302/// element-type ::= primitive-type | vector-type
303///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700304Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700305 if (curToken.is(Token::kw_vector))
306 return parseVectorType();
307
308 return parsePrimitiveType();
309}
310
311/// Parse a vector type.
312///
313/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
314/// const-dimension-list ::= (integer-literal `x`)+
315///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700316VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700317 consumeToken(Token::kw_vector);
318
319 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700320 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700321
322 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700323 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700324
325 SmallVector<unsigned, 4> dimensions;
326 while (curToken.is(Token::integer)) {
327 // Make sure this integer value is in bound and valid.
328 auto dimension = curToken.getUnsignedIntegerValue();
329 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700330 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700331 dimensions.push_back(dimension.getValue());
332
333 consumeToken(Token::integer);
334
335 // Make sure we have an 'x' or something like 'xbf32'.
336 if (curToken.isNot(Token::bare_identifier) ||
337 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700338 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700339
340 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
341 if (curToken.getSpelling().size() != 1)
342 lex.resetPointer(curToken.getSpelling().data()+1);
343
344 // Consume the 'x'.
345 consumeToken(Token::bare_identifier);
346 }
347
348 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700349 auto *elementType = parsePrimitiveType();
350 if (!elementType)
351 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700352
353 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700354 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700355
Chris Lattnerf7e22732018-06-22 22:03:48 -0700356 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700357}
358
359/// Parse a dimension list of a tensor or memref type. This populates the
360/// dimension list, returning -1 for the '?' dimensions.
361///
362/// dimension-list-ranked ::= (dimension `x`)*
363/// dimension ::= `?` | integer-literal
364///
365ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
366 while (curToken.isAny(Token::integer, Token::question)) {
367 if (consumeIf(Token::question)) {
368 dimensions.push_back(-1);
369 } else {
370 // Make sure this integer value is in bound and valid.
371 auto dimension = curToken.getUnsignedIntegerValue();
372 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
373 return emitError("invalid dimension");
374 dimensions.push_back((int)dimension.getValue());
375 consumeToken(Token::integer);
376 }
377
378 // Make sure we have an 'x' or something like 'xbf32'.
379 if (curToken.isNot(Token::bare_identifier) ||
380 curToken.getSpelling()[0] != 'x')
381 return emitError("expected 'x' in dimension list");
382
383 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
384 if (curToken.getSpelling().size() != 1)
385 lex.resetPointer(curToken.getSpelling().data()+1);
386
387 // Consume the 'x'.
388 consumeToken(Token::bare_identifier);
389 }
390
391 return ParseSuccess;
392}
393
394/// Parse a tensor type.
395///
396/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
397/// dimension-list ::= dimension-list-ranked | `??`
398///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700399Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700400 consumeToken(Token::kw_tensor);
401
402 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700403 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700404
405 bool isUnranked;
406 SmallVector<int, 4> dimensions;
407
408 if (consumeIf(Token::questionquestion)) {
409 isUnranked = true;
410 } else {
411 isUnranked = false;
412 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700413 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700414 }
415
416 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700417 auto elementType = parseElementType();
418 if (!elementType)
419 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700420
421 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700422 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700423
MLIR Team355ec862018-06-23 18:09:09 -0700424 if (isUnranked)
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700425 return builder.getTensorType(elementType);
426 return builder.getTensorType(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700427}
428
429/// Parse a memref type.
430///
431/// memref-type ::= `memref` `<` dimension-list-ranked element-type
432/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
433///
434/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
435/// memory-space ::= integer-literal /* | TODO: address-space-id */
436///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700437Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700438 consumeToken(Token::kw_memref);
439
440 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700441 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700442
443 SmallVector<int, 4> dimensions;
444 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700445 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700446
447 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700448 auto elementType = parseElementType();
449 if (!elementType)
450 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700451
452 // TODO: Parse semi-affine-map-composition.
453 // TODO: Parse memory-space.
454
455 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700456 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700457
Chris Lattnerf7e22732018-06-22 22:03:48 -0700458 // FIXME: Add an IR representation for memref types.
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700459 return builder.getIntegerType(1);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700460}
461
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700462/// Parse a function type.
463///
464/// function-type ::= type-list-parens `->` type-list
465///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700466Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700467 assert(curToken.is(Token::l_paren));
468
Chris Lattnerf7e22732018-06-22 22:03:48 -0700469 SmallVector<Type*, 4> arguments;
470 if (parseTypeList(arguments))
471 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700472
473 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700474 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700475
Chris Lattnerf7e22732018-06-22 22:03:48 -0700476 SmallVector<Type*, 4> results;
477 if (parseTypeList(results))
478 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700479
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700480 return builder.getFunctionType(arguments, results);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700481}
482
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700483/// Parse an arbitrary type.
484///
485/// type ::= primitive-type
486/// | vector-type
487/// | tensor-type
488/// | memref-type
489/// | function-type
490/// element-type ::= primitive-type | vector-type
491///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700492Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700493 switch (curToken.getKind()) {
494 case Token::kw_memref: return parseMemRefType();
495 case Token::kw_tensor: return parseTensorType();
496 case Token::kw_vector: return parseVectorType();
497 case Token::l_paren: return parseFunctionType();
498 default:
499 return parsePrimitiveType();
500 }
501}
502
503/// Parse a "type list", which is a singular type, or a parenthesized list of
504/// types.
505///
506/// type-list ::= type-list-parens | type
507/// type-list-parens ::= `(` `)`
508/// | `(` type (`,` type)* `)`
509///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700510ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
511 auto parseElt = [&]() -> ParseResult {
512 auto elt = parseType();
513 elements.push_back(elt);
514 return elt ? ParseSuccess : ParseFailure;
515 };
516
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700517 // If there is no parens, then it must be a singular type.
518 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700519 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700520
Chris Lattnerf7e22732018-06-22 22:03:48 -0700521 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700522 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700523
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700524 return ParseSuccess;
525}
526
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700527namespace {
528/// This class represents the transient parser state while parsing an affine
529/// expression.
530class AffineMapParserState {
531 public:
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700532 explicit AffineMapParserState() {}
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700533
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700534 void addDim(StringRef sRef) { dims.insert({sRef, dims.size()}); }
535 void addSymbol(StringRef sRef) { symbols.insert({sRef, symbols.size()}); }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700536
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700537 unsigned getNumDims() const { return dims.size(); }
538 unsigned getNumSymbols() const { return symbols.size(); }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700539
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700540 // TODO(bondhugula): could just use an vector/ArrayRef and scan the numbers.
541 const llvm::StringMap<unsigned> &getDims() const { return dims; }
542 const llvm::StringMap<unsigned> &getSymbols() const { return symbols; }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700543
544 private:
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700545 llvm::StringMap<unsigned> dims;
546 llvm::StringMap<unsigned> symbols;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700547};
548} // end anonymous namespace
549
Chris Lattner4c95a502018-06-23 16:03:42 -0700550//===----------------------------------------------------------------------===//
Chris Lattner7121b802018-07-04 20:45:39 -0700551// Attribute parsing.
552//===----------------------------------------------------------------------===//
553
554
555/// Attribute parsing.
556///
557/// attribute-value ::= bool-literal
558/// | integer-literal
559/// | float-literal
560/// | string-literal
561/// | `[` (attribute-value (`,` attribute-value)*)? `]`
562///
563Attribute *Parser::parseAttribute() {
564 switch (curToken.getKind()) {
565 case Token::kw_true:
566 consumeToken(Token::kw_true);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700567 return BoolAttr::get(true, builder.getContext());
Chris Lattner7121b802018-07-04 20:45:39 -0700568 case Token::kw_false:
569 consumeToken(Token::kw_false);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700570 return BoolAttr::get(false, builder.getContext());
Chris Lattner7121b802018-07-04 20:45:39 -0700571
572 case Token::integer: {
573 auto val = curToken.getUInt64IntegerValue();
574 if (!val.hasValue() || (int64_t)val.getValue() < 0)
575 return (emitError("integer too large for attribute"), nullptr);
576 consumeToken(Token::integer);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700577 return IntegerAttr::get((int64_t)val.getValue(), builder.getContext());
Chris Lattner7121b802018-07-04 20:45:39 -0700578 }
579
580 case Token::minus: {
581 consumeToken(Token::minus);
582 if (curToken.is(Token::integer)) {
583 auto val = curToken.getUInt64IntegerValue();
584 if (!val.hasValue() || (int64_t)-val.getValue() >= 0)
585 return (emitError("integer too large for attribute"), nullptr);
586 consumeToken(Token::integer);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700587 return IntegerAttr::get((int64_t)-val.getValue(), builder.getContext());
Chris Lattner7121b802018-07-04 20:45:39 -0700588 }
589
590 return (emitError("expected constant integer or floating point value"),
591 nullptr);
592 }
593
594 case Token::string: {
595 auto val = curToken.getStringValue();
596 consumeToken(Token::string);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700597 return StringAttr::get(val, builder.getContext());
Chris Lattner7121b802018-07-04 20:45:39 -0700598 }
599
600 case Token::l_bracket: {
601 consumeToken(Token::l_bracket);
602 SmallVector<Attribute*, 4> elements;
603
604 auto parseElt = [&]() -> ParseResult {
605 elements.push_back(parseAttribute());
606 return elements.back() ? ParseSuccess : ParseFailure;
607 };
608
609 if (parseCommaSeparatedList(Token::r_bracket, parseElt))
610 return nullptr;
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700611 return ArrayAttr::get(elements, builder.getContext());
Chris Lattner7121b802018-07-04 20:45:39 -0700612 }
613 default:
614 // TODO: Handle floating point.
615 return (emitError("expected constant attribute value"), nullptr);
616 }
617}
618
619
620/// Attribute dictionary.
621///
622/// attribute-dict ::= `{` `}`
623/// | `{` attribute-entry (`,` attribute-entry)* `}`
624/// attribute-entry ::= bare-id `:` attribute-value
625///
626ParseResult Parser::parseAttributeDict(
627 SmallVectorImpl<NamedAttribute> &attributes) {
628 consumeToken(Token::l_brace);
629
630 auto parseElt = [&]() -> ParseResult {
631 // We allow keywords as attribute names.
632 if (curToken.isNot(Token::bare_identifier, Token::inttype) &&
633 !curToken.isKeyword())
634 return emitError("expected attribute name");
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700635 auto nameId = Identifier::get(curToken.getSpelling(), builder.getContext());
Chris Lattner7121b802018-07-04 20:45:39 -0700636 consumeToken();
637
638 if (!consumeIf(Token::colon))
639 return emitError("expected ':' in attribute list");
640
641 auto attr = parseAttribute();
642 if (!attr) return ParseFailure;
643
644 attributes.push_back({nameId, attr});
645 return ParseSuccess;
646 };
647
648 if (parseCommaSeparatedList(Token::r_brace, parseElt))
649 return ParseFailure;
650
651 return ParseSuccess;
652}
653
654//===----------------------------------------------------------------------===//
MLIR Teamf85a6262018-06-27 11:03:08 -0700655// Polyhedral structures.
656//===----------------------------------------------------------------------===//
657
658/// Affine map declaration.
659///
660/// affine-map-def ::= affine-map-id `=` affine-map-inline
MLIR Teamf85a6262018-06-27 11:03:08 -0700661///
662ParseResult Parser::parseAffineMapDef() {
Chris Lattner78276e32018-07-07 15:48:26 -0700663 assert(curToken.is(Token::hash_identifier));
MLIR Teamf85a6262018-06-27 11:03:08 -0700664
665 StringRef affineMapId = curToken.getSpelling().drop_front();
Chris Lattner7121b802018-07-04 20:45:39 -0700666
667 // Check for redefinitions.
668 auto *&entry = affineMapDefinitions[affineMapId];
669 if (entry)
670 return emitError("redefinition of affine map id '" + affineMapId + "'");
671
Chris Lattner78276e32018-07-07 15:48:26 -0700672 consumeToken(Token::hash_identifier);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700673
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700674 // Parse the '='
675 if (!consumeIf(Token::equal))
676 return emitError("expected '=' in affine map outlined definition");
MLIR Teamf85a6262018-06-27 11:03:08 -0700677
Chris Lattner7121b802018-07-04 20:45:39 -0700678 entry = parseAffineMapInline(affineMapId);
679 if (!entry)
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700680 return ParseFailure;
MLIR Teamf85a6262018-06-27 11:03:08 -0700681
Chris Lattner7121b802018-07-04 20:45:39 -0700682 module->affineMapList.push_back(entry);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700683 return ParseSuccess;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700684}
685
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700686/// Create an affine op expression
687AffineBinaryOpExpr *Parser::getBinaryAffineOpExpr(AffineHighPrecOp op,
688 AffineExpr *lhs,
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700689 AffineExpr *rhs) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700690 switch (op) {
691 case Mul:
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700692 return AffineMulExpr::get(lhs, rhs, builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700693 case FloorDiv:
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700694 return AffineFloorDivExpr::get(lhs, rhs, builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700695 case CeilDiv:
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700696 return AffineCeilDivExpr::get(lhs, rhs, builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700697 case Mod:
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700698 return AffineModExpr::get(lhs, rhs, builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700699 case HNoOp:
700 llvm_unreachable("can't create affine expression for null high prec op");
701 return nullptr;
702 }
703}
704
705AffineBinaryOpExpr *Parser::getBinaryAffineOpExpr(AffineLowPrecOp op,
706 AffineExpr *lhs,
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700707 AffineExpr *rhs) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700708 switch (op) {
709 case AffineLowPrecOp::Add:
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700710 return AffineAddExpr::get(lhs, rhs, builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700711 case AffineLowPrecOp::Sub:
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700712 return AffineSubExpr::get(lhs, rhs, builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700713 case AffineLowPrecOp::LNoOp:
714 llvm_unreachable("can't create affine expression for null low prec op");
715 return nullptr;
716 }
717}
718
719/// Parses an expression that can be a valid operand of an affine expression
720/// (where associativity may not have been specified through parentheses).
721// Eg: for an expression without parentheses (like i + j + k + l), each
722// of the four identifiers is an operand. For: i + j*k + l, j*k is not an
723// operand expression, it's an op expression and will be parsed via
724// parseAffineLowPrecOpExpression().
725ParseResult Parser::parseAffineOperandExpr(const AffineMapParserState &state,
726 AffineExpr *&result) {
727 result = parseParentheticalExpr(state);
728 if (!result)
729 result = parseBareIdExpr(state);
730 if (!result)
731 result = parseIntegerExpr(state);
732 return result ? ParseSuccess : ParseFailure;
733}
734
735/// Parse a high precedence op expression list: mul, div, and mod are high
736/// precedence binary ops, i.e., parse a
737/// expr_1 op_1 expr_2 op_2 ... expr_n
738/// where op_1, op_2 are all a AffineHighPrecOp (mul, div, mod).
739/// All affine binary ops are left associative.
740/// Given llhs, returns (llhs * lhs) * rhs, or (lhs * rhs) if llhs is null. If
741/// no rhs can be found, returns (llhs * lhs) or lhs if llhs is null.
742// TODO(bondhugula): check whether mul is w.r.t. a constant - otherwise, the
743/// map is semi-affine.
744ParseResult Parser::parseAffineHighPrecOpExpr(AffineExpr *llhs,
745 AffineHighPrecOp llhsOp,
746 const AffineMapParserState &state,
747 AffineExpr *&result) {
748 // FIXME: Assume for now that llhsOp is mul.
749 AffineExpr *lhs = nullptr;
750 if (parseAffineOperandExpr(state, lhs)) {
751 return ParseFailure;
752 }
753 AffineHighPrecOp op = HNoOp;
754 // Found an LHS. Parse the remaining expression.
755 if ((op = consumeIfHighPrecOp())) {
756 if (llhs) {
757 // TODO(bondhugula): check whether 'lhs' here is a constant (for affine
758 // maps); semi-affine maps allow symbols.
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700759 AffineExpr *expr = getBinaryAffineOpExpr(llhsOp, llhs, lhs);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700760 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.
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700790 result = getBinaryAffineOpExpr(llhsOp, llhs, lhs);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700791 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) {
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700870 AffineExpr *sum = getBinaryAffineOpExpr(llhsOp, llhs, lhs);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700871 AffineExpr *recSum = nullptr;
872 parseAffineLowPrecOpExpr(sum, lOp, state, recSum);
873 result = recSum ? recSum : sum;
874 return ParseSuccess;
875 }
876 // No LLHS, get RHS and form the expression.
877 if (parseAffineLowPrecOpExpr(lhs, lOp, state, result)) {
878 if (!result)
879 emitError("missing right operand of add op");
880 return ParseFailure;
881 }
882 return ParseSuccess;
883 } else if ((rOp = consumeIfHighPrecOp())) {
884 // We have a higher precedence op here. Get the rhs operand for the llhs
885 // through parseAffineHighPrecOpExpr.
886 AffineExpr *highRes = nullptr;
887 if (parseAffineHighPrecOpExpr(lhs, rOp, state, highRes)) {
888 // 'product' needs to be checked to prevent duplicate errors messages as
889 // the call stack unwinds. All of this due to left associativity.
890 if (!highRes)
891 emitError("missing right operand of binary op");
892 return ParseFailure;
893 }
894 // If llhs is null, the product forms the first operand of the yet to be
895 // found expression. If non-null, assume for now that the op to associate
896 // with llhs is add.
897 AffineExpr *expr =
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700898 llhs ? getBinaryAffineOpExpr(llhsOp, llhs, highRes) : highRes;
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700899 // Recurse for subsequent add's after the affine mul expression
900 AffineLowPrecOp nextOp = consumeIfLowPrecOp();
901 if (nextOp) {
902 AffineExpr *sumProd = nullptr;
903 parseAffineLowPrecOpExpr(expr, nextOp, state, sumProd);
904 result = sumProd ? sumProd : expr;
905 } else {
906 result = expr;
907 }
908 return ParseSuccess;
909 } else {
910 // Last operand in the expression list.
911 if (llhs) {
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700912 result = getBinaryAffineOpExpr(llhsOp, llhs, lhs);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700913 return ParseSuccess;
914 }
915 // No llhs, 'lhs' itself is the expression.
916 result = lhs;
917 return ParseSuccess;
918 }
919}
920
921/// Parse an affine expression inside parentheses.
922/// affine-expr ::= `(` affine-expr `)`
923AffineExpr *Parser::parseParentheticalExpr(const AffineMapParserState &state) {
924 if (!consumeIf(Token::l_paren)) {
925 return nullptr;
926 }
927 auto *expr = parseAffineExpr(state);
928 if (!consumeIf(Token::r_paren)) {
929 emitError("expected ')'");
930 return nullptr;
931 }
932 if (!expr)
933 emitError("no expression inside parentheses");
934 return expr;
935}
936
937/// Parse a bare id that may appear in an affine expression.
938/// affine-expr ::= bare-id
939AffineExpr *Parser::parseBareIdExpr(const AffineMapParserState &state) {
940 if (curToken.is(Token::bare_identifier)) {
941 StringRef sRef = curToken.getSpelling();
942 const auto &dims = state.getDims();
943 const auto &symbols = state.getSymbols();
944 if (dims.count(sRef)) {
945 consumeToken(Token::bare_identifier);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700946 return AffineDimExpr::get(dims.lookup(sRef), builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700947 }
948 if (symbols.count(sRef)) {
949 consumeToken(Token::bare_identifier);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700950 return AffineSymbolExpr::get(symbols.lookup(sRef), builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700951 }
952 return emitError("identifier is neither dimensional nor symbolic"), nullptr;
953 }
954 return nullptr;
955}
956
957/// Parse an integral constant appearing in an affine expression.
958/// affine-expr ::= `-`? integer-literal
959/// TODO(bondhugula): handle negative numbers.
960AffineExpr *Parser::parseIntegerExpr(const AffineMapParserState &state) {
961 if (curToken.is(Token::integer)) {
962 auto *expr = AffineConstantExpr::get(
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700963 curToken.getUnsignedIntegerValue().getValue(), builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700964 consumeToken(Token::integer);
965 return expr;
966 }
967 return nullptr;
968}
969
970/// Parse an affine expression.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700971/// affine-expr ::= `(` affine-expr `)`
972/// | affine-expr `+` affine-expr
973/// | affine-expr `-` affine-expr
974/// | `-`? integer-literal `*` affine-expr
975/// | `ceildiv` `(` affine-expr `,` integer-literal `)`
976/// | `floordiv` `(` affine-expr `,` integer-literal `)`
977/// | affine-expr `mod` integer-literal
978/// | bare-id
979/// | `-`? integer-literal
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700980/// Use 'state' to check if valid identifiers appear.
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700981// TODO(bondhugula): check if mul, mod, div take integral constants
982AffineExpr *Parser::parseAffineExpr(const AffineMapParserState &state) {
983 switch (curToken.getKind()) {
984 case Token::l_paren:
985 case Token::kw_ceildiv:
986 case Token::kw_floordiv:
987 case Token::bare_identifier:
988 case Token::integer: {
989 AffineExpr *result = nullptr;
990 parseAffineLowPrecOpExpr(nullptr, AffineLowPrecOp::LNoOp, state, result);
991 return result;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700992 }
993
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700994 case Token::plus:
995 case Token::minus:
996 case Token::star:
997 emitError("left operand of binary op missing");
998 return nullptr;
999
1000 default:
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001001 return nullptr;
1002 }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001003}
1004
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001005/// Parse a dim or symbol from the lists appearing before the actual expressions
1006/// of the affine map. Update state to store the dimensional/symbolic
1007/// identifier. 'dim': whether it's the dim list or symbol list that is being
1008/// parsed.
1009ParseResult Parser::parseDimOrSymbolId(AffineMapParserState &state, bool dim) {
1010 if (curToken.isNot(Token::bare_identifier))
1011 return emitError("expected bare identifier");
1012 auto sRef = curToken.getSpelling();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001013 consumeToken(Token::bare_identifier);
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001014 if (state.getDims().count(sRef) == 1)
1015 return emitError("dimensional identifier name reused");
1016 if (state.getSymbols().count(sRef) == 1)
1017 return emitError("symbolic identifier name reused");
1018 if (dim)
1019 state.addDim(sRef);
1020 else
1021 state.addSymbol(sRef);
1022 return ParseSuccess;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001023}
1024
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001025/// Parse the list of symbolic identifiers to an affine map.
1026ParseResult Parser::parseSymbolIdList(AffineMapParserState &state) {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001027 if (!consumeIf(Token::l_bracket)) return emitError("expected '['");
1028
1029 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001030 return parseDimOrSymbolId(state, false);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001031 };
1032 return parseCommaSeparatedList(Token::r_bracket, parseElt);
1033}
1034
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001035/// Parse the list of dimensional identifiers to an affine map.
1036ParseResult Parser::parseDimIdList(AffineMapParserState &state) {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001037 if (!consumeIf(Token::l_paren))
1038 return emitError("expected '(' at start of dimensional identifiers list");
1039
1040 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001041 return parseDimOrSymbolId(state, true);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001042 };
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001043 return parseCommaSeparatedList(Token::r_paren, parseElt);
1044}
1045
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001046/// Parse an affine map definition.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001047///
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001048/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001049/// ( `size` `(` dim-size (`,` dim-size)* `)` )?
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001050/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001051///
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001052/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
Chris Lattner7121b802018-07-04 20:45:39 -07001053AffineMap *Parser::parseAffineMapInline(StringRef mapId) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001054 AffineMapParserState state;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001055
1056 // List of dimensional identifiers.
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001057 if (parseDimIdList(state))
Chris Lattner7121b802018-07-04 20:45:39 -07001058 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001059
1060 // Symbols are optional.
1061 if (curToken.is(Token::l_bracket)) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001062 if (parseSymbolIdList(state))
Chris Lattner7121b802018-07-04 20:45:39 -07001063 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001064 }
1065 if (!consumeIf(Token::arrow)) {
Chris Lattner7121b802018-07-04 20:45:39 -07001066 return (emitError("expected '->' or '['"), nullptr);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001067 }
1068 if (!consumeIf(Token::l_paren)) {
1069 emitError("expected '(' at start of affine map range");
Chris Lattner7121b802018-07-04 20:45:39 -07001070 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001071 }
1072
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001073 SmallVector<AffineExpr *, 4> exprs;
1074 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001075 auto *elt = parseAffineExpr(state);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001076 ParseResult res = elt ? ParseSuccess : ParseFailure;
1077 exprs.push_back(elt);
1078 return res;
1079 };
1080
1081 // Parse a multi-dimensional affine expression (a comma-separated list of 1-d
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001082 // affine expressions); the list cannot be empty.
1083 // Grammar: multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
1084 if (parseCommaSeparatedList(Token::r_paren, parseElt, false))
Chris Lattner7121b802018-07-04 20:45:39 -07001085 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001086
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001087 // Parsed a valid affine map.
Chris Lattner7121b802018-07-04 20:45:39 -07001088 return AffineMap::get(state.getNumDims(), state.getNumSymbols(), exprs,
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001089 builder.getContext());
MLIR Teamf85a6262018-06-27 11:03:08 -07001090}
1091
1092//===----------------------------------------------------------------------===//
Chris Lattner78276e32018-07-07 15:48:26 -07001093// SSA
Chris Lattner4c95a502018-06-23 16:03:42 -07001094//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -07001095
Chris Lattner78276e32018-07-07 15:48:26 -07001096/// Parse a SSA operand for an instruction or statement.
1097///
1098/// ssa-use ::= ssa-id | ssa-constant
1099///
1100ParseResult Parser::parseSSAUse() {
1101 if (curToken.is(Token::percent_identifier)) {
1102 StringRef name = curToken.getSpelling().drop_front();
1103 consumeToken(Token::percent_identifier);
1104 // TODO: Return this use.
1105 (void)name;
1106 return ParseSuccess;
1107 }
1108
1109 // TODO: Parse SSA constants.
1110
1111 return emitError("expected SSA operand");
1112}
1113
1114/// Parse a (possibly empty) list of SSA operands.
1115///
1116/// ssa-use-list ::= ssa-use (`,` ssa-use)*
1117/// ssa-use-list-opt ::= ssa-use-list?
1118///
1119ParseResult Parser::parseOptionalSSAUseList(Token::Kind endToken) {
1120 // TODO: Build and return this.
1121 return parseCommaSeparatedList(
1122 endToken, [&]() -> ParseResult { return parseSSAUse(); });
1123}
1124
1125/// Parse an SSA use with an associated type.
1126///
1127/// ssa-use-and-type ::= ssa-use `:` type
1128ParseResult Parser::parseSSAUseAndType() {
1129 if (parseSSAUse())
1130 return ParseFailure;
1131
1132 if (!consumeIf(Token::colon))
1133 return emitError("expected ':' and type for SSA operand");
1134
1135 if (!parseType())
1136 return ParseFailure;
1137
1138 return ParseSuccess;
1139}
1140
1141/// Parse a (possibly empty) list of SSA operands with types.
1142///
1143/// ssa-use-and-type-list ::= ssa-use-and-type (`,` ssa-use-and-type)*
1144///
1145ParseResult Parser::parseOptionalSSAUseAndTypeList(Token::Kind endToken) {
1146 // TODO: Build and return this.
1147 return parseCommaSeparatedList(
1148 endToken, [&]() -> ParseResult { return parseSSAUseAndType(); });
1149}
1150
1151//===----------------------------------------------------------------------===//
1152// Functions
1153//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -07001154
1155/// Parse a function signature, starting with a name and including the parameter
1156/// list.
1157///
1158/// argument-list ::= type (`,` type)* | /*empty*/
1159/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
1160///
Chris Lattnerf7e22732018-06-22 22:03:48 -07001161ParseResult Parser::parseFunctionSignature(StringRef &name,
1162 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -07001163 if (curToken.isNot(Token::at_identifier))
1164 return emitError("expected a function identifier like '@foo'");
1165
1166 name = curToken.getSpelling().drop_front();
1167 consumeToken(Token::at_identifier);
1168
1169 if (curToken.isNot(Token::l_paren))
1170 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -07001171
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001172 SmallVector<Type*, 4> arguments;
1173 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001174 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -07001175
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001176 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -07001177 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001178 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -07001179 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001180 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001181 }
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001182 type = builder.getFunctionType(arguments, results);
Chris Lattnere79379a2018-06-22 10:39:19 -07001183 return ParseSuccess;
1184}
1185
Chris Lattnere79379a2018-06-22 10:39:19 -07001186/// External function declarations.
1187///
1188/// ext-func ::= `extfunc` function-signature
1189///
1190ParseResult Parser::parseExtFunc() {
1191 consumeToken(Token::kw_extfunc);
1192
1193 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -07001194 FunctionType *type = nullptr;
1195 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -07001196 return ParseFailure;
1197
Chris Lattnere79379a2018-06-22 10:39:19 -07001198 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -07001199 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -07001200 return ParseSuccess;
1201}
1202
1203
Chris Lattner4c95a502018-06-23 16:03:42 -07001204namespace {
1205/// This class represents the transient parser state for the internals of a
1206/// function as we are parsing it, e.g. the names for basic blocks. It handles
1207/// forward references.
1208class CFGFunctionParserState {
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001209public:
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001210 CFGFunction *function;
1211 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001212 CFGFuncBuilder builder;
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001213
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001214 CFGFunctionParserState(CFGFunction *function)
1215 : function(function), builder(function) {}
Chris Lattner4c95a502018-06-23 16:03:42 -07001216
1217 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001218 /// already exist. The location specified is the point of use, which allows
1219 /// us to diagnose references to blocks that are not defined precisely.
1220 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
1221 auto &blockAndLoc = blocksByName[name];
1222 if (!blockAndLoc.first) {
Chris Lattner3a467cc2018-07-01 20:28:00 -07001223 blockAndLoc.first = new BasicBlock();
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001224 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -07001225 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001226 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -07001227 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001228};
1229} // end anonymous namespace
1230
1231
1232/// CFG function declarations.
1233///
1234/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
1235///
1236ParseResult Parser::parseCFGFunc() {
1237 consumeToken(Token::kw_cfgfunc);
1238
1239 StringRef name;
1240 FunctionType *type = nullptr;
1241 if (parseFunctionSignature(name, type))
1242 return ParseFailure;
1243
1244 if (!consumeIf(Token::l_brace))
1245 return emitError("expected '{' in CFG function");
1246
1247 // Okay, the CFG function signature was parsed correctly, create the function.
1248 auto function = new CFGFunction(name, type);
1249
1250 // Make sure we have at least one block.
1251 if (curToken.is(Token::r_brace))
1252 return emitError("CFG functions must have at least one basic block");
1253
1254 CFGFunctionParserState functionState(function);
1255
1256 // Parse the list of blocks.
1257 while (!consumeIf(Token::r_brace))
1258 if (parseBasicBlock(functionState))
1259 return ParseFailure;
1260
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001261 // Verify that all referenced blocks were defined. Iteration over a
1262 // StringMap isn't determinstic, but this is good enough for our purposes.
1263 for (auto &elt : functionState.blocksByName) {
1264 auto *bb = elt.second.first;
Chris Lattner3a467cc2018-07-01 20:28:00 -07001265 if (!bb->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001266 return emitError(elt.second.second,
1267 "reference to an undefined basic block '" +
1268 elt.first() + "'");
1269 }
1270
Chris Lattner4c95a502018-06-23 16:03:42 -07001271 module->functionList.push_back(function);
1272 return ParseSuccess;
1273}
1274
1275/// Basic block declaration.
1276///
1277/// basic-block ::= bb-label instruction* terminator-stmt
1278/// bb-label ::= bb-id bb-arg-list? `:`
1279/// bb-id ::= bare-id
1280/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
1281///
1282ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
1283 SMLoc nameLoc = curToken.getLoc();
1284 auto name = curToken.getSpelling();
1285 if (!consumeIf(Token::bare_identifier))
1286 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001287
1288 auto block = functionState.getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -07001289
1290 // If this block has already been parsed, then this is a redefinition with the
1291 // same block name.
Chris Lattner3a467cc2018-07-01 20:28:00 -07001292 if (block->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001293 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
1294
Chris Lattner3a467cc2018-07-01 20:28:00 -07001295 // Add the block to the function.
1296 functionState.function->push_back(block);
Chris Lattner4c95a502018-06-23 16:03:42 -07001297
Chris Lattner78276e32018-07-07 15:48:26 -07001298 // If an argument list is present, parse it.
1299 if (consumeIf(Token::l_paren)) {
1300 if (parseOptionalSSAUseAndTypeList(Token::r_paren))
1301 return ParseFailure;
1302
1303 // TODO: attach it.
1304 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001305
1306 if (!consumeIf(Token::colon))
1307 return emitError("expected ':' after basic block name");
1308
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001309 // Set the insertion point to the block we want to insert new operations into.
1310 functionState.builder.setInsertionPoint(block);
1311
Chris Lattnered65a732018-06-28 20:45:33 -07001312 // Parse the list of operations that make up the body of the block.
1313 while (curToken.isNot(Token::kw_return, Token::kw_br)) {
Chris Lattner21e67f62018-07-06 10:46:19 -07001314 auto loc = curToken.getLoc();
Chris Lattner3a467cc2018-07-01 20:28:00 -07001315 auto *inst = parseCFGOperation(functionState);
1316 if (!inst)
Chris Lattnered65a732018-06-28 20:45:33 -07001317 return ParseFailure;
Chris Lattner3a467cc2018-07-01 20:28:00 -07001318
Chris Lattner21e67f62018-07-06 10:46:19 -07001319 // We just parsed an operation. If it is a recognized one, verify that it
1320 // is structurally as we expect. If not, produce an error with a reasonable
1321 // source location.
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001322 if (auto *opInfo = inst->getAbstractOperation(builder.getContext()))
Chris Lattner21e67f62018-07-06 10:46:19 -07001323 if (auto error = opInfo->verifyInvariants(inst))
1324 return emitError(loc, error);
Chris Lattnered65a732018-06-28 20:45:33 -07001325 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001326
Chris Lattner3a467cc2018-07-01 20:28:00 -07001327 auto *term = parseTerminator(functionState);
1328 if (!term)
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001329 return ParseFailure;
Chris Lattner4c95a502018-06-23 16:03:42 -07001330
1331 return ParseSuccess;
1332}
1333
1334
Chris Lattnered65a732018-06-28 20:45:33 -07001335/// Parse the CFG operation.
1336///
1337/// TODO(clattner): This is a change from the MLIR spec as written, it is an
1338/// experiment that will eliminate "builtin" instructions as a thing.
1339///
1340/// cfg-operation ::=
1341/// (ssa-id `=`)? string '(' ssa-use-list? ')' attribute-dict?
1342/// `:` function-type
1343///
Chris Lattner3a467cc2018-07-01 20:28:00 -07001344OperationInst *Parser::
1345parseCFGOperation(CFGFunctionParserState &functionState) {
Chris Lattnered65a732018-06-28 20:45:33 -07001346
Chris Lattner78276e32018-07-07 15:48:26 -07001347 StringRef resultID;
1348 if (curToken.is(Token::percent_identifier)) {
1349 resultID = curToken.getSpelling().drop_front();
1350 consumeToken();
1351 if (!consumeIf(Token::equal))
1352 return (emitError("expected '=' after SSA name"), nullptr);
1353 }
Chris Lattnered65a732018-06-28 20:45:33 -07001354
1355 if (curToken.isNot(Token::string))
Chris Lattner3a467cc2018-07-01 20:28:00 -07001356 return (emitError("expected operation name in quotes"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001357
1358 auto name = curToken.getStringValue();
1359 if (name.empty())
Chris Lattner3a467cc2018-07-01 20:28:00 -07001360 return (emitError("empty operation name is invalid"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001361
1362 consumeToken(Token::string);
1363
1364 if (!consumeIf(Token::l_paren))
Chris Lattner7121b802018-07-04 20:45:39 -07001365 return (emitError("expected '(' to start operand list"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001366
Chris Lattner78276e32018-07-07 15:48:26 -07001367 // Parse the operand list.
1368 parseOptionalSSAUseList(Token::r_paren);
Chris Lattner7121b802018-07-04 20:45:39 -07001369
1370 SmallVector<NamedAttribute, 4> attributes;
1371 if (curToken.is(Token::l_brace)) {
1372 if (parseAttributeDict(attributes))
1373 return nullptr;
1374 }
Chris Lattnered65a732018-06-28 20:45:33 -07001375
Chris Lattner78276e32018-07-07 15:48:26 -07001376 // TODO: Don't drop result name and operand names on the floor.
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001377 auto nameId = Identifier::get(name, builder.getContext());
1378 return functionState.builder.createOperation(nameId, attributes);
Chris Lattnered65a732018-06-28 20:45:33 -07001379}
1380
1381
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001382/// Parse the terminator instruction for a basic block.
1383///
1384/// terminator-stmt ::= `br` bb-id branch-use-list?
1385/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
1386/// terminator-stmt ::=
1387/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
1388/// terminator-stmt ::= `return` ssa-use-and-type-list?
1389///
Chris Lattner3a467cc2018-07-01 20:28:00 -07001390TerminatorInst *Parser::parseTerminator(CFGFunctionParserState &functionState) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001391 switch (curToken.getKind()) {
1392 default:
Chris Lattner3a467cc2018-07-01 20:28:00 -07001393 return (emitError("expected terminator at end of basic block"), nullptr);
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001394
1395 case Token::kw_return:
1396 consumeToken(Token::kw_return);
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001397 return functionState.builder.createReturnInst();
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001398
1399 case Token::kw_br: {
1400 consumeToken(Token::kw_br);
1401 auto destBB = functionState.getBlockNamed(curToken.getSpelling(),
1402 curToken.getLoc());
1403 if (!consumeIf(Token::bare_identifier))
Chris Lattner3a467cc2018-07-01 20:28:00 -07001404 return (emitError("expected basic block name"), nullptr);
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001405 return functionState.builder.createBranchInst(destBB);
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001406 }
Chris Lattner78276e32018-07-07 15:48:26 -07001407 // TODO: cond_br.
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001408 }
1409}
1410
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001411/// ML function declarations.
1412///
1413/// ml-func ::= `mlfunc` ml-func-signature `{` ml-stmt* ml-return-stmt `}`
1414///
1415ParseResult Parser::parseMLFunc() {
1416 consumeToken(Token::kw_mlfunc);
1417
1418 StringRef name;
1419 FunctionType *type = nullptr;
1420
1421 // FIXME: Parse ML function signature (args + types)
1422 // by passing pointer to SmallVector<identifier> into parseFunctionSignature
1423 if (parseFunctionSignature(name, type))
1424 return ParseFailure;
1425
1426 if (!consumeIf(Token::l_brace))
1427 return emitError("expected '{' in ML function");
1428
1429 // Okay, the ML function signature was parsed correctly, create the function.
1430 auto function = new MLFunction(name, type);
1431
1432 // Make sure we have at least one statement.
1433 if (curToken.is(Token::r_brace))
1434 return emitError("ML function must end with return statement");
1435
1436 // Parse the list of instructions.
1437 while (!consumeIf(Token::kw_return)) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001438 auto *stmt = parseStatement(function);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001439 if (!stmt)
1440 return ParseFailure;
1441 function->stmtList.push_back(stmt);
1442 }
1443
1444 // TODO: parse return statement operands
1445 if (!consumeIf(Token::r_brace))
1446 emitError("expected '}' in ML function");
1447
1448 module->functionList.push_back(function);
1449
1450 return ParseSuccess;
1451}
1452
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001453/// Statement.
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001454///
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001455/// ml-stmt ::= instruction | ml-for-stmt | ml-if-stmt
1456/// TODO: fix terminology in MLSpec document. ML functions
1457/// contain operation statements, not instructions.
1458///
1459Statement * Parser::parseStatement(ParentType parent) {
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001460 switch (curToken.getKind()) {
1461 default:
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001462 //TODO: parse OperationStmt
1463 return (emitError("expected statement"), nullptr);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001464
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001465 case Token::kw_for:
1466 return parseForStmt(parent);
1467
1468 case Token::kw_if:
1469 return parseIfStmt(parent);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001470 }
1471}
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001472
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001473/// For statement.
1474///
1475/// ml-for-stmt ::= `for` ssa-id `=` lower-bound `to` upper-bound
1476/// (`step` integer-literal)? `{` ml-stmt* `}`
1477///
1478ForStmt * Parser::parseForStmt(ParentType parent) {
1479 consumeToken(Token::kw_for);
1480
1481 //TODO: parse loop header
1482 ForStmt *stmt = new ForStmt(parent);
1483 if (parseNestedStatements(stmt)) {
1484 delete stmt;
1485 return nullptr;
1486 }
1487 return stmt;
1488}
1489
1490/// If statement.
1491///
1492/// ml-if-head ::= `if` ml-if-cond `{` ml-stmt* `}`
1493/// | ml-if-head `else` `if` ml-if-cond `{` ml-stmt* `}`
1494/// ml-if-stmt ::= ml-if-head
1495/// | ml-if-head `else` `{` ml-stmt* `}`
1496///
1497IfStmt * Parser::parseIfStmt(PointerUnion<MLFunction *, NodeStmt *> parent) {
1498 consumeToken(Token::kw_if);
1499
1500 //TODO: parse condition
1501 IfStmt *stmt = new IfStmt(parent);
1502 if (parseNestedStatements(stmt)) {
1503 delete stmt;
1504 return nullptr;
1505 }
1506
1507 int clauseNum = 0;
1508 while (consumeIf(Token::kw_else)) {
1509 if (consumeIf(Token::kw_if)) {
1510 //TODO: parse condition
1511 }
1512 ElseClause * clause = new ElseClause(stmt, clauseNum);
1513 ++clauseNum;
1514 if (parseNestedStatements(clause)) {
1515 delete clause;
1516 return nullptr;
1517 }
1518 }
1519
1520 return stmt;
1521}
1522
1523///
1524/// Parse `{` ml-stmt* `}`
1525///
1526ParseResult Parser::parseNestedStatements(NodeStmt *parent) {
1527 if (!consumeIf(Token::l_brace))
1528 return emitError("expected '{' before statement list");
1529
1530 if (consumeIf(Token::r_brace)) {
1531 // TODO: parse OperationStmt
1532 return ParseSuccess;
1533 }
1534
1535 while (!consumeIf(Token::r_brace)) {
1536 auto *stmt = parseStatement(parent);
1537 if (!stmt)
1538 return ParseFailure;
1539 parent->children.push_back(stmt);
1540 }
1541
1542 return ParseSuccess;
1543}
1544
Chris Lattner4c95a502018-06-23 16:03:42 -07001545//===----------------------------------------------------------------------===//
1546// Top-level entity parsing.
1547//===----------------------------------------------------------------------===//
1548
Chris Lattnere79379a2018-06-22 10:39:19 -07001549/// This is the top-level module parser.
1550Module *Parser::parseModule() {
1551 while (1) {
1552 switch (curToken.getKind()) {
1553 default:
1554 emitError("expected a top level entity");
1555 return nullptr;
1556
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001557 // If we got to the end of the file, then we're done.
Chris Lattnere79379a2018-06-22 10:39:19 -07001558 case Token::eof:
1559 return module.release();
1560
1561 // If we got an error token, then the lexer already emitted an error, just
1562 // stop. Someday we could introduce error recovery if there was demand for
1563 // it.
1564 case Token::error:
1565 return nullptr;
1566
1567 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -07001568 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -07001569 break;
1570
Chris Lattner4c95a502018-06-23 16:03:42 -07001571 case Token::kw_cfgfunc:
1572 if (parseCFGFunc()) return nullptr;
1573 break;
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001574
Chris Lattner78276e32018-07-07 15:48:26 -07001575 case Token::hash_identifier:
MLIR Teamf85a6262018-06-27 11:03:08 -07001576 if (parseAffineMapDef()) return nullptr;
1577 break;
Chris Lattner4c95a502018-06-23 16:03:42 -07001578
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001579 case Token::kw_mlfunc:
1580 if (parseMLFunc()) return nullptr;
1581 break;
1582
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001583 // TODO: affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -07001584 }
1585 }
1586}
1587
1588//===----------------------------------------------------------------------===//
1589
Jacques Pienaar7b829702018-07-03 13:24:09 -07001590void mlir::defaultErrorReporter(const llvm::SMDiagnostic &error) {
1591 const auto &sourceMgr = *error.getSourceMgr();
1592 sourceMgr.PrintMessage(error.getLoc(), error.getKind(), error.getMessage());
1593}
1594
Chris Lattnere79379a2018-06-22 10:39:19 -07001595/// This parses the file specified by the indicated SourceMgr and returns an
1596/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Jacques Pienaar9c411be2018-06-24 19:17:35 -07001597Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context,
Jacques Pienaar7b829702018-07-03 13:24:09 -07001598 SMDiagnosticHandlerTy errorReporter) {
Chris Lattner21e67f62018-07-06 10:46:19 -07001599 auto *result =
1600 Parser(sourceMgr, context,
1601 errorReporter ? std::move(errorReporter) : defaultErrorReporter)
1602 .parseModule();
1603
1604 // Make sure the parse module has no other structural problems detected by the
1605 // verifier.
1606 if (result)
1607 result->verify();
1608 return result;
Chris Lattnere79379a2018-06-22 10:39:19 -07001609}