blob: aabefbf2c8acd6bf9bcf2ca810a9ed2cae7a0f84 [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"
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -070031#include "mlir/IR/Statements.h"
Chris Lattnerf7e22732018-06-22 22:03:48 -070032#include "mlir/IR/Types.h"
Chris Lattnere79379a2018-06-22 10:39:19 -070033#include "llvm/Support/SourceMgr.h"
34using namespace mlir;
35using llvm::SourceMgr;
Chris Lattner4c95a502018-06-23 16:03:42 -070036using llvm::SMLoc;
Chris Lattnere79379a2018-06-22 10:39:19 -070037
Chris Lattnerf7e22732018-06-22 22:03:48 -070038/// Simple enum to make code read better in cases that would otherwise return a
39/// bool value. Failure is "true" in a boolean context.
Chris Lattnere79379a2018-06-22 10:39:19 -070040enum ParseResult {
41 ParseSuccess,
42 ParseFailure
43};
44
Chris Lattner48af7d12018-07-09 19:05:38 -070045namespace {
46class Parser;
47
48/// This class refers to all of the state maintained globally by the parser,
49/// such as the current lexer position etc. The Parser base class provides
50/// methods to access this.
51class ParserState {
Chris Lattnered65a732018-06-28 20:45:33 -070052public:
Chris Lattner2e595eb2018-07-10 10:08:27 -070053 ParserState(llvm::SourceMgr &sourceMgr, Module *module,
Chris Lattner48af7d12018-07-09 19:05:38 -070054 SMDiagnosticHandlerTy errorReporter)
Chris Lattner2e595eb2018-07-10 10:08:27 -070055 : context(module->getContext()), module(module),
56 lex(sourceMgr, errorReporter), curToken(lex.lexToken()),
Jacques Pienaard4c784e2018-07-11 00:07:36 -070057 errorReporter(errorReporter) {}
Chris Lattner2e595eb2018-07-10 10:08:27 -070058
59 // A map from affine map identifier to AffineMap.
60 llvm::StringMap<AffineMap *> affineMapDefinitions;
Chris Lattnere79379a2018-06-22 10:39:19 -070061
Chris Lattnere79379a2018-06-22 10:39:19 -070062private:
Chris Lattner48af7d12018-07-09 19:05:38 -070063 ParserState(const ParserState &) = delete;
64 void operator=(const ParserState &) = delete;
65
66 friend class Parser;
67
68 // The context we're parsing into.
Chris Lattner2e595eb2018-07-10 10:08:27 -070069 MLIRContext *const context;
70
71 // This is the module we are parsing into.
72 Module *const module;
Chris Lattnerf7e22732018-06-22 22:03:48 -070073
74 // The lexer for the source file we're parsing.
Chris Lattnere79379a2018-06-22 10:39:19 -070075 Lexer lex;
76
77 // This is the next token that hasn't been consumed yet.
78 Token curToken;
79
Jacques Pienaar9c411be2018-06-24 19:17:35 -070080 // The diagnostic error reporter.
Chris Lattner2e595eb2018-07-10 10:08:27 -070081 SMDiagnosticHandlerTy const errorReporter;
Chris Lattner48af7d12018-07-09 19:05:38 -070082};
83} // end anonymous namespace
MLIR Teamf85a6262018-06-27 11:03:08 -070084
Chris Lattner48af7d12018-07-09 19:05:38 -070085namespace {
86
Tatiana Shpeisman565b9642018-07-16 11:47:09 -070087typedef std::function<Operation *(Identifier, ArrayRef<NamedAttribute>)>
88 CreateOperationFunction;
89
Chris Lattner48af7d12018-07-09 19:05:38 -070090/// This class implement support for parsing global entities like types and
91/// shared entities like SSA names. It is intended to be subclassed by
92/// specialized subparsers that include state, e.g. when a local symbol table.
93class Parser {
94public:
Chris Lattner2e595eb2018-07-10 10:08:27 -070095 Builder builder;
Chris Lattner48af7d12018-07-09 19:05:38 -070096
Chris Lattner2e595eb2018-07-10 10:08:27 -070097 Parser(ParserState &state) : builder(state.context), state(state) {}
98
99 // Helper methods to get stuff from the parser-global state.
100 ParserState &getState() const { return state; }
Chris Lattner48af7d12018-07-09 19:05:38 -0700101 MLIRContext *getContext() const { return state.context; }
Chris Lattner2e595eb2018-07-10 10:08:27 -0700102 Module *getModule() { return state.module; }
Chris Lattner48af7d12018-07-09 19:05:38 -0700103
104 /// Return the current token the parser is inspecting.
105 const Token &getToken() const { return state.curToken; }
106 StringRef getTokenSpelling() const { return state.curToken.getSpelling(); }
Chris Lattnere79379a2018-06-22 10:39:19 -0700107
108 /// Emit an error and return failure.
Chris Lattner4c95a502018-06-23 16:03:42 -0700109 ParseResult emitError(const Twine &message) {
Chris Lattner48af7d12018-07-09 19:05:38 -0700110 return emitError(state.curToken.getLoc(), message);
Chris Lattner4c95a502018-06-23 16:03:42 -0700111 }
112 ParseResult emitError(SMLoc loc, const Twine &message);
Chris Lattnere79379a2018-06-22 10:39:19 -0700113
114 /// Advance the current lexer onto the next token.
115 void consumeToken() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700116 assert(state.curToken.isNot(Token::eof, Token::error) &&
Chris Lattnere79379a2018-06-22 10:39:19 -0700117 "shouldn't advance past EOF or errors");
Chris Lattner48af7d12018-07-09 19:05:38 -0700118 state.curToken = state.lex.lexToken();
Chris Lattnere79379a2018-06-22 10:39:19 -0700119 }
120
121 /// Advance the current lexer onto the next token, asserting what the expected
122 /// current token is. This is preferred to the above method because it leads
123 /// to more self-documenting code with better checking.
Chris Lattner8da0c282018-06-29 11:15:56 -0700124 void consumeToken(Token::Kind kind) {
Chris Lattner48af7d12018-07-09 19:05:38 -0700125 assert(state.curToken.is(kind) && "consumed an unexpected token");
Chris Lattnere79379a2018-06-22 10:39:19 -0700126 consumeToken();
127 }
128
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700129 /// If the current token has the specified kind, consume it and return true.
130 /// If not, return false.
Chris Lattner8da0c282018-06-29 11:15:56 -0700131 bool consumeIf(Token::Kind kind) {
Chris Lattner48af7d12018-07-09 19:05:38 -0700132 if (state.curToken.isNot(kind))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700133 return false;
134 consumeToken(kind);
135 return true;
136 }
137
MLIR Team718c82f2018-07-16 09:45:22 -0700138 ParseResult parseCommaSeparatedList(
139 Token::Kind rightToken,
140 const std::function<ParseResult()> &parseElement,
141 bool allowEmptyList = true);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700142
Chris Lattnerf7e22732018-06-22 22:03:48 -0700143 // We have two forms of parsing methods - those that return a non-null
144 // pointer on success, and those that return a ParseResult to indicate whether
145 // they returned a failure. The second class fills in by-reference arguments
146 // as the results of their action.
147
Chris Lattnere79379a2018-06-22 10:39:19 -0700148 // Type parsing.
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700149 Type *parsePrimitiveType();
Chris Lattnerf7e22732018-06-22 22:03:48 -0700150 Type *parseElementType();
151 VectorType *parseVectorType();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700152 ParseResult parseDimensionListRanked(SmallVectorImpl<int> &dimensions);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700153 Type *parseTensorType();
154 Type *parseMemRefType();
155 Type *parseFunctionType();
156 Type *parseType();
157 ParseResult parseTypeList(SmallVectorImpl<Type*> &elements);
Chris Lattnere79379a2018-06-22 10:39:19 -0700158
Chris Lattner7121b802018-07-04 20:45:39 -0700159 // Attribute parsing.
160 Attribute *parseAttribute();
161 ParseResult parseAttributeDict(SmallVectorImpl<NamedAttribute> &attributes);
162
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700163 // Polyhedral structures.
Chris Lattner2e595eb2018-07-10 10:08:27 -0700164 AffineMap *parseAffineMapInline();
MLIR Team718c82f2018-07-16 09:45:22 -0700165 AffineMap *parseAffineMapReference();
MLIR Teamf85a6262018-06-27 11:03:08 -0700166
Chris Lattner78276e32018-07-07 15:48:26 -0700167 // SSA
168 ParseResult parseSSAUse();
169 ParseResult parseOptionalSSAUseList(Token::Kind endToken);
170 ParseResult parseSSAUseAndType();
171 ParseResult parseOptionalSSAUseAndTypeList(Token::Kind endToken);
172
Tatiana Shpeisman565b9642018-07-16 11:47:09 -0700173 // Operations
174 ParseResult parseOperation(const CreateOperationFunction &createOpFunc);
175
Chris Lattner48af7d12018-07-09 19:05:38 -0700176private:
177 // The Parser is subclassed and reinstantiated. Do not add additional
178 // non-trivial state here, add it to the ParserState class.
179 ParserState &state;
Chris Lattnere79379a2018-06-22 10:39:19 -0700180};
181} // end anonymous namespace
182
183//===----------------------------------------------------------------------===//
184// Helper methods.
185//===----------------------------------------------------------------------===//
186
Chris Lattner4c95a502018-06-23 16:03:42 -0700187ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700188 // If we hit a parse error in response to a lexer error, then the lexer
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700189 // already reported the error.
Chris Lattner48af7d12018-07-09 19:05:38 -0700190 if (getToken().is(Token::error))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700191 return ParseFailure;
192
Chris Lattner48af7d12018-07-09 19:05:38 -0700193 auto &sourceMgr = state.lex.getSourceMgr();
194 state.errorReporter(sourceMgr.GetMessage(loc, SourceMgr::DK_Error, message));
Chris Lattnere79379a2018-06-22 10:39:19 -0700195 return ParseFailure;
196}
197
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700198/// Parse a comma-separated list of elements, terminated with an arbitrary
199/// token. This allows empty lists if allowEmptyList is true.
200///
201/// abstract-list ::= rightToken // if allowEmptyList == true
202/// abstract-list ::= element (',' element)* rightToken
203///
204ParseResult Parser::
Chris Lattner8da0c282018-06-29 11:15:56 -0700205parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700206 const std::function<ParseResult()> &parseElement,
207 bool allowEmptyList) {
208 // Handle the empty case.
Chris Lattner48af7d12018-07-09 19:05:38 -0700209 if (getToken().is(rightToken)) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700210 if (!allowEmptyList)
211 return emitError("expected list element");
212 consumeToken(rightToken);
213 return ParseSuccess;
214 }
215
216 // Non-empty case starts with an element.
217 if (parseElement())
218 return ParseFailure;
219
220 // Otherwise we have a list of comma separated elements.
221 while (consumeIf(Token::comma)) {
222 if (parseElement())
223 return ParseFailure;
224 }
225
226 // Consume the end character.
227 if (!consumeIf(rightToken))
Chris Lattner8da0c282018-06-29 11:15:56 -0700228 return emitError("expected ',' or '" + Token::getTokenSpelling(rightToken) +
229 "'");
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700230
231 return ParseSuccess;
232}
Chris Lattnere79379a2018-06-22 10:39:19 -0700233
234//===----------------------------------------------------------------------===//
235// Type Parsing
236//===----------------------------------------------------------------------===//
237
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700238/// Parse the low-level fixed dtypes in the system.
239///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700240/// primitive-type ::= `f16` | `bf16` | `f32` | `f64`
241/// primitive-type ::= integer-type
242/// primitive-type ::= `affineint`
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700243///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700244Type *Parser::parsePrimitiveType() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700245 switch (getToken().getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700246 default:
247 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700248 case Token::kw_bf16:
249 consumeToken(Token::kw_bf16);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700250 return builder.getBF16Type();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700251 case Token::kw_f16:
252 consumeToken(Token::kw_f16);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700253 return builder.getF16Type();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700254 case Token::kw_f32:
255 consumeToken(Token::kw_f32);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700256 return builder.getF32Type();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700257 case Token::kw_f64:
258 consumeToken(Token::kw_f64);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700259 return builder.getF64Type();
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700260 case Token::kw_affineint:
261 consumeToken(Token::kw_affineint);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700262 return builder.getAffineIntType();
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700263 case Token::inttype: {
Chris Lattner48af7d12018-07-09 19:05:38 -0700264 auto width = getToken().getIntTypeBitwidth();
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700265 if (!width.hasValue())
266 return (emitError("invalid integer width"), nullptr);
267 consumeToken(Token::inttype);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700268 return builder.getIntegerType(width.getValue());
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700269 }
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700270 }
271}
272
273/// Parse the element type of a tensor or memref type.
274///
275/// element-type ::= primitive-type | vector-type
276///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700277Type *Parser::parseElementType() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700278 if (getToken().is(Token::kw_vector))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700279 return parseVectorType();
280
281 return parsePrimitiveType();
282}
283
284/// Parse a vector type.
285///
286/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
287/// const-dimension-list ::= (integer-literal `x`)+
288///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700289VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700290 consumeToken(Token::kw_vector);
291
292 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700293 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700294
Chris Lattner48af7d12018-07-09 19:05:38 -0700295 if (getToken().isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700296 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700297
298 SmallVector<unsigned, 4> dimensions;
Chris Lattner48af7d12018-07-09 19:05:38 -0700299 while (getToken().is(Token::integer)) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700300 // Make sure this integer value is in bound and valid.
Chris Lattner48af7d12018-07-09 19:05:38 -0700301 auto dimension = getToken().getUnsignedIntegerValue();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700302 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700303 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700304 dimensions.push_back(dimension.getValue());
305
306 consumeToken(Token::integer);
307
308 // Make sure we have an 'x' or something like 'xbf32'.
Chris Lattner48af7d12018-07-09 19:05:38 -0700309 if (getToken().isNot(Token::bare_identifier) ||
310 getTokenSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700311 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700312
313 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
Chris Lattner48af7d12018-07-09 19:05:38 -0700314 if (getTokenSpelling().size() != 1)
315 state.lex.resetPointer(getTokenSpelling().data() + 1);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700316
317 // Consume the 'x'.
318 consumeToken(Token::bare_identifier);
319 }
320
321 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700322 auto *elementType = parsePrimitiveType();
323 if (!elementType)
324 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700325
326 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700327 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700328
Chris Lattnerf7e22732018-06-22 22:03:48 -0700329 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700330}
331
332/// Parse a dimension list of a tensor or memref type. This populates the
333/// dimension list, returning -1 for the '?' dimensions.
334///
335/// dimension-list-ranked ::= (dimension `x`)*
336/// dimension ::= `?` | integer-literal
337///
338ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
Chris Lattner48af7d12018-07-09 19:05:38 -0700339 while (getToken().isAny(Token::integer, Token::question)) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700340 if (consumeIf(Token::question)) {
341 dimensions.push_back(-1);
342 } else {
343 // Make sure this integer value is in bound and valid.
Chris Lattner48af7d12018-07-09 19:05:38 -0700344 auto dimension = getToken().getUnsignedIntegerValue();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700345 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
346 return emitError("invalid dimension");
347 dimensions.push_back((int)dimension.getValue());
348 consumeToken(Token::integer);
349 }
350
351 // Make sure we have an 'x' or something like 'xbf32'.
Chris Lattner48af7d12018-07-09 19:05:38 -0700352 if (getToken().isNot(Token::bare_identifier) ||
353 getTokenSpelling()[0] != 'x')
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700354 return emitError("expected 'x' in dimension list");
355
356 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
Chris Lattner48af7d12018-07-09 19:05:38 -0700357 if (getTokenSpelling().size() != 1)
358 state.lex.resetPointer(getTokenSpelling().data() + 1);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700359
360 // Consume the 'x'.
361 consumeToken(Token::bare_identifier);
362 }
363
364 return ParseSuccess;
365}
366
367/// Parse a tensor type.
368///
369/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
370/// dimension-list ::= dimension-list-ranked | `??`
371///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700372Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700373 consumeToken(Token::kw_tensor);
374
375 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700376 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700377
378 bool isUnranked;
379 SmallVector<int, 4> dimensions;
380
381 if (consumeIf(Token::questionquestion)) {
382 isUnranked = true;
383 } else {
384 isUnranked = false;
385 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700386 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700387 }
388
389 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700390 auto elementType = parseElementType();
391 if (!elementType)
392 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700393
394 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700395 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700396
MLIR Team355ec862018-06-23 18:09:09 -0700397 if (isUnranked)
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700398 return builder.getTensorType(elementType);
399 return builder.getTensorType(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700400}
401
402/// Parse a memref type.
403///
404/// memref-type ::= `memref` `<` dimension-list-ranked element-type
405/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
406///
407/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
408/// memory-space ::= integer-literal /* | TODO: address-space-id */
409///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700410Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700411 consumeToken(Token::kw_memref);
412
413 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700414 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700415
416 SmallVector<int, 4> dimensions;
417 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700418 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700419
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
MLIR Team718c82f2018-07-16 09:45:22 -0700425 if (!consumeIf(Token::comma))
426 return (emitError("expected ',' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700427
MLIR Team718c82f2018-07-16 09:45:22 -0700428 // Parse semi-affine-map-composition.
429 SmallVector<AffineMap*, 2> affineMapComposition;
430 unsigned memorySpace;
431 bool parsedMemorySpace = false;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700432
MLIR Team718c82f2018-07-16 09:45:22 -0700433 auto parseElt = [&]() -> ParseResult {
434 if (getToken().is(Token::integer)) {
435 // Parse memory space.
436 if (parsedMemorySpace)
437 return emitError("multiple memory spaces specified in memref type");
438 auto v = getToken().getUnsignedIntegerValue();
439 if (!v.hasValue())
440 return emitError("invalid memory space in memref type");
441 memorySpace = v.getValue();
442 consumeToken(Token::integer);
443 parsedMemorySpace = true;
444 } else {
445 // Parse affine map.
446 if (parsedMemorySpace)
447 return emitError("affine map after memory space in memref type");
448 auto* affineMap = parseAffineMapReference();
449 if (affineMap == nullptr)
450 return ParseFailure;
451 affineMapComposition.push_back(affineMap);
452 }
453 return ParseSuccess;
454 };
455
456 // Parse comma separated list of affine maps, followed by memory space.
457 if (parseCommaSeparatedList(Token::greater, parseElt,
458 /*allowEmptyList=*/false)) {
459 return nullptr;
460 }
461 // Check that MemRef type specifies at least one affine map in composition.
462 if (affineMapComposition.empty())
463 return (emitError("expected semi-affine-map in memref type"), nullptr);
464 if (!parsedMemorySpace)
465 return (emitError("expected memory space in memref type"), nullptr);
466
467 return MemRefType::get(dimensions, elementType, affineMapComposition,
468 memorySpace);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700469}
470
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700471/// Parse a function type.
472///
473/// function-type ::= type-list-parens `->` type-list
474///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700475Type *Parser::parseFunctionType() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700476 assert(getToken().is(Token::l_paren));
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700477
Chris Lattnerf7e22732018-06-22 22:03:48 -0700478 SmallVector<Type*, 4> arguments;
479 if (parseTypeList(arguments))
480 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700481
482 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700483 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700484
Chris Lattnerf7e22732018-06-22 22:03:48 -0700485 SmallVector<Type*, 4> results;
486 if (parseTypeList(results))
487 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700488
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700489 return builder.getFunctionType(arguments, results);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700490}
491
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700492/// Parse an arbitrary type.
493///
494/// type ::= primitive-type
495/// | vector-type
496/// | tensor-type
497/// | memref-type
498/// | function-type
499/// element-type ::= primitive-type | vector-type
500///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700501Type *Parser::parseType() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700502 switch (getToken().getKind()) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700503 case Token::kw_memref: return parseMemRefType();
504 case Token::kw_tensor: return parseTensorType();
505 case Token::kw_vector: return parseVectorType();
506 case Token::l_paren: return parseFunctionType();
507 default:
508 return parsePrimitiveType();
509 }
510}
511
512/// Parse a "type list", which is a singular type, or a parenthesized list of
513/// types.
514///
515/// type-list ::= type-list-parens | type
516/// type-list-parens ::= `(` `)`
517/// | `(` type (`,` type)* `)`
518///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700519ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
520 auto parseElt = [&]() -> ParseResult {
521 auto elt = parseType();
522 elements.push_back(elt);
523 return elt ? ParseSuccess : ParseFailure;
524 };
525
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700526 // If there is no parens, then it must be a singular type.
527 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700528 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700529
Chris Lattnerf7e22732018-06-22 22:03:48 -0700530 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700531 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700532
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700533 return ParseSuccess;
534}
535
Chris Lattner4c95a502018-06-23 16:03:42 -0700536//===----------------------------------------------------------------------===//
Chris Lattner7121b802018-07-04 20:45:39 -0700537// Attribute parsing.
538//===----------------------------------------------------------------------===//
539
540
541/// Attribute parsing.
542///
543/// attribute-value ::= bool-literal
544/// | integer-literal
545/// | float-literal
546/// | string-literal
547/// | `[` (attribute-value (`,` attribute-value)*)? `]`
548///
549Attribute *Parser::parseAttribute() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700550 switch (getToken().getKind()) {
Chris Lattner7121b802018-07-04 20:45:39 -0700551 case Token::kw_true:
552 consumeToken(Token::kw_true);
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700553 return builder.getBoolAttr(true);
Chris Lattner7121b802018-07-04 20:45:39 -0700554 case Token::kw_false:
555 consumeToken(Token::kw_false);
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700556 return builder.getBoolAttr(false);
Chris Lattner7121b802018-07-04 20:45:39 -0700557
558 case Token::integer: {
Chris Lattner48af7d12018-07-09 19:05:38 -0700559 auto val = getToken().getUInt64IntegerValue();
Chris Lattner7121b802018-07-04 20:45:39 -0700560 if (!val.hasValue() || (int64_t)val.getValue() < 0)
561 return (emitError("integer too large for attribute"), nullptr);
562 consumeToken(Token::integer);
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700563 return builder.getIntegerAttr((int64_t)val.getValue());
Chris Lattner7121b802018-07-04 20:45:39 -0700564 }
565
566 case Token::minus: {
567 consumeToken(Token::minus);
Chris Lattner48af7d12018-07-09 19:05:38 -0700568 if (getToken().is(Token::integer)) {
569 auto val = getToken().getUInt64IntegerValue();
Chris Lattner7121b802018-07-04 20:45:39 -0700570 if (!val.hasValue() || (int64_t)-val.getValue() >= 0)
571 return (emitError("integer too large for attribute"), nullptr);
572 consumeToken(Token::integer);
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700573 return builder.getIntegerAttr((int64_t)-val.getValue());
Chris Lattner7121b802018-07-04 20:45:39 -0700574 }
575
576 return (emitError("expected constant integer or floating point value"),
577 nullptr);
578 }
579
580 case Token::string: {
Chris Lattner48af7d12018-07-09 19:05:38 -0700581 auto val = getToken().getStringValue();
Chris Lattner7121b802018-07-04 20:45:39 -0700582 consumeToken(Token::string);
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700583 return builder.getStringAttr(val);
Chris Lattner7121b802018-07-04 20:45:39 -0700584 }
585
586 case Token::l_bracket: {
587 consumeToken(Token::l_bracket);
588 SmallVector<Attribute*, 4> elements;
589
590 auto parseElt = [&]() -> ParseResult {
591 elements.push_back(parseAttribute());
592 return elements.back() ? ParseSuccess : ParseFailure;
593 };
594
595 if (parseCommaSeparatedList(Token::r_bracket, parseElt))
596 return nullptr;
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700597 return builder.getArrayAttr(elements);
Chris Lattner7121b802018-07-04 20:45:39 -0700598 }
599 default:
600 // TODO: Handle floating point.
601 return (emitError("expected constant attribute value"), nullptr);
602 }
603}
604
Chris Lattner7121b802018-07-04 20:45:39 -0700605/// Attribute dictionary.
606///
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700607/// attribute-dict ::= `{` `}`
608/// | `{` attribute-entry (`,` attribute-entry)* `}`
609/// attribute-entry ::= bare-id `:` attribute-value
Chris Lattner7121b802018-07-04 20:45:39 -0700610///
611ParseResult Parser::parseAttributeDict(
612 SmallVectorImpl<NamedAttribute> &attributes) {
613 consumeToken(Token::l_brace);
614
615 auto parseElt = [&]() -> ParseResult {
616 // We allow keywords as attribute names.
Chris Lattner48af7d12018-07-09 19:05:38 -0700617 if (getToken().isNot(Token::bare_identifier, Token::inttype) &&
618 !getToken().isKeyword())
Chris Lattner7121b802018-07-04 20:45:39 -0700619 return emitError("expected attribute name");
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700620 auto nameId = builder.getIdentifier(getTokenSpelling());
Chris Lattner7121b802018-07-04 20:45:39 -0700621 consumeToken();
622
623 if (!consumeIf(Token::colon))
624 return emitError("expected ':' in attribute list");
625
626 auto attr = parseAttribute();
627 if (!attr) return ParseFailure;
628
629 attributes.push_back({nameId, attr});
630 return ParseSuccess;
631 };
632
633 if (parseCommaSeparatedList(Token::r_brace, parseElt))
634 return ParseFailure;
635
636 return ParseSuccess;
637}
638
639//===----------------------------------------------------------------------===//
MLIR Teamf85a6262018-06-27 11:03:08 -0700640// Polyhedral structures.
641//===----------------------------------------------------------------------===//
642
Chris Lattner2e595eb2018-07-10 10:08:27 -0700643/// Lower precedence ops (all at the same precedence level). LNoOp is false in
644/// the boolean sense.
645enum AffineLowPrecOp {
646 /// Null value.
647 LNoOp,
648 Add,
649 Sub
650};
MLIR Teamf85a6262018-06-27 11:03:08 -0700651
Chris Lattner2e595eb2018-07-10 10:08:27 -0700652/// Higher precedence ops - all at the same precedence level. HNoOp is false in
653/// the boolean sense.
654enum AffineHighPrecOp {
655 /// Null value.
656 HNoOp,
657 Mul,
658 FloorDiv,
659 CeilDiv,
660 Mod
661};
Chris Lattner7121b802018-07-04 20:45:39 -0700662
Chris Lattner2e595eb2018-07-10 10:08:27 -0700663namespace {
664/// This is a specialized parser for AffineMap's, maintaining the state
665/// transient to their bodies.
666class AffineMapParser : public Parser {
667public:
668 explicit AffineMapParser(ParserState &state) : Parser(state) {}
Chris Lattner7121b802018-07-04 20:45:39 -0700669
Chris Lattner2e595eb2018-07-10 10:08:27 -0700670 AffineMap *parseAffineMapInline();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700671
Chris Lattner2e595eb2018-07-10 10:08:27 -0700672private:
673 unsigned getNumDims() const { return dims.size(); }
674 unsigned getNumSymbols() const { return symbols.size(); }
MLIR Teamf85a6262018-06-27 11:03:08 -0700675
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700676 /// Returns true if the only identifiers the parser accepts in affine
677 /// expressions are symbolic identifiers.
678 bool isPureSymbolic() const { return pureSymbolic; }
679 void setSymbolicParsing(bool val) { pureSymbolic = val; }
680
Chris Lattner2e595eb2018-07-10 10:08:27 -0700681 // Binary affine op parsing.
682 AffineLowPrecOp consumeIfLowPrecOp();
683 AffineHighPrecOp consumeIfHighPrecOp();
MLIR Teamf85a6262018-06-27 11:03:08 -0700684
Chris Lattner2e595eb2018-07-10 10:08:27 -0700685 // Identifier lists for polyhedral structures.
686 ParseResult parseDimIdList();
687 ParseResult parseSymbolIdList();
688 ParseResult parseDimOrSymbolId(bool isDim);
689
690 AffineExpr *parseAffineExpr();
691 AffineExpr *parseParentheticalExpr();
692 AffineExpr *parseNegateExpression(AffineExpr *lhs);
693 AffineExpr *parseIntegerExpr();
694 AffineExpr *parseBareIdExpr();
695
696 AffineExpr *getBinaryAffineOpExpr(AffineHighPrecOp op, AffineExpr *lhs,
697 AffineExpr *rhs);
698 AffineExpr *getBinaryAffineOpExpr(AffineLowPrecOp op, AffineExpr *lhs,
699 AffineExpr *rhs);
700 AffineExpr *parseAffineOperandExpr(AffineExpr *lhs);
701 AffineExpr *parseAffineLowPrecOpExpr(AffineExpr *llhs,
702 AffineLowPrecOp llhsOp);
703 AffineExpr *parseAffineHighPrecOpExpr(AffineExpr *llhs,
704 AffineHighPrecOp llhsOp);
705
706private:
707 // TODO(bondhugula): could just use an vector/ArrayRef and scan the numbers.
708 llvm::StringMap<unsigned> dims;
709 llvm::StringMap<unsigned> symbols;
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700710 /// True if the parser should allow only symbolic identifiers in affine
711 /// expressions.
712 bool pureSymbolic = false;
Chris Lattner2e595eb2018-07-10 10:08:27 -0700713};
714} // end anonymous namespace
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700715
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700716/// Create an affine binary high precedence op expression (mul's, div's, mod)
Chris Lattner2e595eb2018-07-10 10:08:27 -0700717AffineExpr *AffineMapParser::getBinaryAffineOpExpr(AffineHighPrecOp op,
718 AffineExpr *lhs,
719 AffineExpr *rhs) {
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700720 // TODO: make the error location info accurate.
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700721 switch (op) {
722 case Mul:
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700723 if (!lhs->isSymbolic() && !rhs->isSymbolic()) {
724 emitError("non-affine expression: at least one of the multiply "
725 "operands has to be either a constant or symbolic");
726 return nullptr;
727 }
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700728 return builder.getMulExpr(lhs, rhs);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700729 case FloorDiv:
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700730 if (!rhs->isSymbolic()) {
731 emitError("non-affine expression: right operand of floordiv "
732 "has to be either a constant or symbolic");
733 return nullptr;
734 }
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700735 return builder.getFloorDivExpr(lhs, rhs);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700736 case CeilDiv:
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700737 if (!rhs->isSymbolic()) {
738 emitError("non-affine expression: right operand of ceildiv "
739 "has to be either a constant or symbolic");
740 return nullptr;
741 }
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700742 return builder.getCeilDivExpr(lhs, rhs);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700743 case Mod:
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700744 if (!rhs->isSymbolic()) {
745 emitError("non-affine expression: right operand of mod "
746 "has to be either a constant or symbolic");
747 return nullptr;
748 }
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700749 return builder.getModExpr(lhs, rhs);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700750 case HNoOp:
751 llvm_unreachable("can't create affine expression for null high prec op");
752 return nullptr;
753 }
754}
755
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700756/// Create an affine binary low precedence op expression (add, sub).
Chris Lattner2e595eb2018-07-10 10:08:27 -0700757AffineExpr *AffineMapParser::getBinaryAffineOpExpr(AffineLowPrecOp op,
758 AffineExpr *lhs,
759 AffineExpr *rhs) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700760 switch (op) {
761 case AffineLowPrecOp::Add:
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700762 return builder.getAddExpr(lhs, rhs);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700763 case AffineLowPrecOp::Sub:
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700764 return builder.getSubExpr(lhs, rhs);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700765 case AffineLowPrecOp::LNoOp:
766 llvm_unreachable("can't create affine expression for null low prec op");
767 return nullptr;
768 }
769}
770
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700771/// Consume this token if it is a lower precedence affine op (there are only two
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700772/// precedence levels).
Chris Lattner2e595eb2018-07-10 10:08:27 -0700773AffineLowPrecOp AffineMapParser::consumeIfLowPrecOp() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700774 switch (getToken().getKind()) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700775 case Token::plus:
776 consumeToken(Token::plus);
777 return AffineLowPrecOp::Add;
778 case Token::minus:
779 consumeToken(Token::minus);
780 return AffineLowPrecOp::Sub;
781 default:
782 return AffineLowPrecOp::LNoOp;
783 }
784}
785
786/// Consume this token if it is a higher precedence affine op (there are only
787/// two precedence levels)
Chris Lattner2e595eb2018-07-10 10:08:27 -0700788AffineHighPrecOp AffineMapParser::consumeIfHighPrecOp() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700789 switch (getToken().getKind()) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700790 case Token::star:
791 consumeToken(Token::star);
792 return Mul;
793 case Token::kw_floordiv:
794 consumeToken(Token::kw_floordiv);
795 return FloorDiv;
796 case Token::kw_ceildiv:
797 consumeToken(Token::kw_ceildiv);
798 return CeilDiv;
799 case Token::kw_mod:
800 consumeToken(Token::kw_mod);
801 return Mod;
802 default:
803 return HNoOp;
804 }
805}
806
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700807/// Parse a high precedence op expression list: mul, div, and mod are high
808/// precedence binary ops, i.e., parse a
809/// expr_1 op_1 expr_2 op_2 ... expr_n
810/// where op_1, op_2 are all a AffineHighPrecOp (mul, div, mod).
811/// All affine binary ops are left associative.
812/// Given llhs, returns (llhs llhsOp lhs) op rhs, or (lhs op rhs) if llhs is
813/// null. If no rhs can be found, returns (llhs llhsOp lhs) or lhs if llhs is
814/// null.
815AffineExpr *
Chris Lattner2e595eb2018-07-10 10:08:27 -0700816AffineMapParser::parseAffineHighPrecOpExpr(AffineExpr *llhs,
817 AffineHighPrecOp llhsOp) {
818 AffineExpr *lhs = parseAffineOperandExpr(llhs);
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700819 if (!lhs)
820 return nullptr;
821
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700822 // Found an LHS. Parse the remaining expression.
Chris Lattner2e595eb2018-07-10 10:08:27 -0700823 if (AffineHighPrecOp op = consumeIfHighPrecOp()) {
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700824 if (llhs) {
825 AffineExpr *expr = getBinaryAffineOpExpr(llhsOp, llhs, lhs);
826 if (!expr)
827 return nullptr;
Chris Lattner2e595eb2018-07-10 10:08:27 -0700828 return parseAffineHighPrecOpExpr(expr, op);
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700829 }
830 // No LLHS, get RHS
Chris Lattner2e595eb2018-07-10 10:08:27 -0700831 return parseAffineHighPrecOpExpr(lhs, op);
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700832 }
833
834 // This is the last operand in this expression.
835 if (llhs)
836 return getBinaryAffineOpExpr(llhsOp, llhs, lhs);
837
838 // No llhs, 'lhs' itself is the expression.
839 return lhs;
840}
841
842/// Parse an affine expression inside parentheses.
843///
844/// affine-expr ::= `(` affine-expr `)`
Chris Lattner2e595eb2018-07-10 10:08:27 -0700845AffineExpr *AffineMapParser::parseParentheticalExpr() {
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700846 if (!consumeIf(Token::l_paren))
847 return (emitError("expected '('"), nullptr);
Chris Lattner48af7d12018-07-09 19:05:38 -0700848 if (getToken().is(Token::r_paren))
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700849 return (emitError("no expression inside parentheses"), nullptr);
Chris Lattner2e595eb2018-07-10 10:08:27 -0700850 auto *expr = parseAffineExpr();
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700851 if (!expr)
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700852 return nullptr;
853 if (!consumeIf(Token::r_paren))
854 return (emitError("expected ')'"), nullptr);
855 return expr;
856}
857
858/// Parse the negation expression.
859///
860/// affine-expr ::= `-` affine-expr
Chris Lattner2e595eb2018-07-10 10:08:27 -0700861AffineExpr *AffineMapParser::parseNegateExpression(AffineExpr *lhs) {
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700862 if (!consumeIf(Token::minus))
863 return (emitError("expected '-'"), nullptr);
864
Chris Lattner2e595eb2018-07-10 10:08:27 -0700865 AffineExpr *operand = parseAffineOperandExpr(lhs);
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700866 // Since negation has the highest precedence of all ops (including high
867 // precedence ops) but lower than parentheses, we are only going to use
868 // parseAffineOperandExpr instead of parseAffineExpr here.
869 if (!operand)
870 // Extra error message although parseAffineOperandExpr would have
871 // complained. Leads to a better diagnostic.
872 return (emitError("missing operand of negation"), nullptr);
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700873 auto *minusOne = builder.getConstantExpr(-1);
874 return builder.getMulExpr(minusOne, operand);
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700875}
876
877/// Parse a bare id that may appear in an affine expression.
878///
879/// affine-expr ::= bare-id
Chris Lattner2e595eb2018-07-10 10:08:27 -0700880AffineExpr *AffineMapParser::parseBareIdExpr() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700881 if (getToken().isNot(Token::bare_identifier))
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700882 return (emitError("expected bare identifier"), nullptr);
883
Chris Lattner48af7d12018-07-09 19:05:38 -0700884 StringRef sRef = getTokenSpelling();
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700885 // dims, symbols are all pairwise distinct.
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700886 if (dims.count(sRef)) {
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700887 if (isPureSymbolic())
888 return (emitError("identifier used is not a symbolic identifier"),
889 nullptr);
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700890 consumeToken(Token::bare_identifier);
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700891 return builder.getDimExpr(dims.lookup(sRef));
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700892 }
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700893
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700894 if (symbols.count(sRef)) {
895 consumeToken(Token::bare_identifier);
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700896 return builder.getSymbolExpr(symbols.lookup(sRef));
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700897 }
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700898
899 return (emitError("use of undeclared identifier"), nullptr);
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700900}
901
902/// Parse a positive integral constant appearing in an affine expression.
903///
904/// affine-expr ::= integer-literal
Chris Lattner2e595eb2018-07-10 10:08:27 -0700905AffineExpr *AffineMapParser::parseIntegerExpr() {
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700906 // No need to handle negative numbers separately here. They are naturally
907 // handled via the unary negation operator, although (FIXME) MININT_64 still
908 // not correctly handled.
Chris Lattner48af7d12018-07-09 19:05:38 -0700909 if (getToken().isNot(Token::integer))
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700910 return (emitError("expected integer"), nullptr);
911
Chris Lattner48af7d12018-07-09 19:05:38 -0700912 auto val = getToken().getUInt64IntegerValue();
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700913 if (!val.hasValue() || (int64_t)val.getValue() < 0) {
914 return (emitError("constant too large for affineint"), nullptr);
915 }
916 consumeToken(Token::integer);
Chris Lattner1ac20cb2018-07-10 10:59:53 -0700917 return builder.getConstantExpr((int64_t)val.getValue());
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700918}
919
920/// Parses an expression that can be a valid operand of an affine expression.
Uday Bondhugula76345202018-07-09 13:47:52 -0700921/// lhs: if non-null, lhs is an affine expression that is the lhs of a binary
922/// operator, the rhs of which is being parsed. This is used to determine
923/// whether an error should be emitted for a missing right operand.
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700924// Eg: for an expression without parentheses (like i + j + k + l), each
925// of the four identifiers is an operand. For i + j*k + l, j*k is not an
926// operand expression, it's an op expression and will be parsed via
927// parseAffineHighPrecOpExpression(). However, for i + (j*k) + -l, (j*k) and -l
928// are valid operands that will be parsed by this function.
Chris Lattner2e595eb2018-07-10 10:08:27 -0700929AffineExpr *AffineMapParser::parseAffineOperandExpr(AffineExpr *lhs) {
Chris Lattner48af7d12018-07-09 19:05:38 -0700930 switch (getToken().getKind()) {
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700931 case Token::bare_identifier:
Chris Lattner2e595eb2018-07-10 10:08:27 -0700932 return parseBareIdExpr();
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700933 case Token::integer:
Chris Lattner2e595eb2018-07-10 10:08:27 -0700934 return parseIntegerExpr();
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700935 case Token::l_paren:
Chris Lattner2e595eb2018-07-10 10:08:27 -0700936 return parseParentheticalExpr();
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700937 case Token::minus:
Chris Lattner2e595eb2018-07-10 10:08:27 -0700938 return parseNegateExpression(lhs);
Uday Bondhugula76345202018-07-09 13:47:52 -0700939 case Token::kw_ceildiv:
940 case Token::kw_floordiv:
941 case Token::kw_mod:
942 case Token::plus:
943 case Token::star:
944 if (lhs)
945 emitError("missing right operand of binary operator");
946 else
947 emitError("missing left operand of binary operator");
948 return nullptr;
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700949 default:
950 if (lhs)
Uday Bondhugula76345202018-07-09 13:47:52 -0700951 emitError("missing right operand of binary operator");
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700952 else
953 emitError("expected affine expression");
954 return nullptr;
955 }
956}
957
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700958/// Parse affine expressions that are bare-id's, integer constants,
959/// parenthetical affine expressions, and affine op expressions that are a
960/// composition of those.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700961///
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700962/// All binary op's associate from left to right.
963///
964/// {add, sub} have lower precedence than {mul, div, and mod}.
965///
Uday Bondhugula76345202018-07-09 13:47:52 -0700966/// Add, sub'are themselves at the same precedence level. Mul, floordiv,
967/// ceildiv, and mod are at the same higher precedence level. Negation has
968/// higher precedence than any binary op.
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700969///
970/// llhs: the affine expression appearing on the left of the one being parsed.
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700971/// This function will return ((llhs llhsOp lhs) op rhs) if llhs is non null,
972/// and lhs op rhs otherwise; if there is no rhs, llhs llhsOp lhs is returned if
973/// llhs is non-null; otherwise lhs is returned. This is to deal with left
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700974/// associativity.
975///
976/// Eg: when the expression is e1 + e2*e3 + e4, with e1 as llhs, this function
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700977/// will return the affine expr equivalent of (e1 + (e2*e3)) + e4, where (e2*e3)
978/// will be parsed using parseAffineHighPrecOpExpr().
Chris Lattner2e595eb2018-07-10 10:08:27 -0700979AffineExpr *AffineMapParser::parseAffineLowPrecOpExpr(AffineExpr *llhs,
980 AffineLowPrecOp llhsOp) {
Uday Bondhugula76345202018-07-09 13:47:52 -0700981 AffineExpr *lhs;
Chris Lattner2e595eb2018-07-10 10:08:27 -0700982 if (!(lhs = parseAffineOperandExpr(llhs)))
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700983 return nullptr;
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700984
985 // Found an LHS. Deal with the ops.
Chris Lattner2e595eb2018-07-10 10:08:27 -0700986 if (AffineLowPrecOp lOp = consumeIfLowPrecOp()) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700987 if (llhs) {
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700988 AffineExpr *sum = getBinaryAffineOpExpr(llhsOp, llhs, lhs);
Chris Lattner2e595eb2018-07-10 10:08:27 -0700989 return parseAffineLowPrecOpExpr(sum, lOp);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700990 }
991 // No LLHS, get RHS and form the expression.
Chris Lattner2e595eb2018-07-10 10:08:27 -0700992 return parseAffineLowPrecOpExpr(lhs, lOp);
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700993 }
Chris Lattner2e595eb2018-07-10 10:08:27 -0700994 if (AffineHighPrecOp hOp = consumeIfHighPrecOp()) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700995 // We have a higher precedence op here. Get the rhs operand for the llhs
996 // through parseAffineHighPrecOpExpr.
Chris Lattner2e595eb2018-07-10 10:08:27 -0700997 AffineExpr *highRes = parseAffineHighPrecOpExpr(lhs, hOp);
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700998 if (!highRes)
999 return nullptr;
Chris Lattner2e595eb2018-07-10 10:08:27 -07001000
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001001 // If llhs is null, the product forms the first operand of the yet to be
Uday Bondhugula3934d4d2018-07-09 09:00:25 -07001002 // found expression. If non-null, the op to associate with llhs is llhsOp.
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001003 AffineExpr *expr =
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001004 llhs ? getBinaryAffineOpExpr(llhsOp, llhs, highRes) : highRes;
Chris Lattner2e595eb2018-07-10 10:08:27 -07001005
Uday Bondhugula3934d4d2018-07-09 09:00:25 -07001006 // Recurse for subsequent low prec op's after the affine high prec op
1007 // expression.
Chris Lattner2e595eb2018-07-10 10:08:27 -07001008 if (AffineLowPrecOp nextOp = consumeIfLowPrecOp())
1009 return parseAffineLowPrecOpExpr(expr, nextOp);
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001010 return expr;
1011 }
Uday Bondhugula3934d4d2018-07-09 09:00:25 -07001012 // Last operand in the expression list.
1013 if (llhs)
1014 return getBinaryAffineOpExpr(llhsOp, llhs, lhs);
1015 // No llhs, 'lhs' itself is the expression.
1016 return lhs;
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001017}
1018
1019/// Parse an affine expression.
Uday Bondhugula3934d4d2018-07-09 09:00:25 -07001020/// affine-expr ::= `(` affine-expr `)`
1021/// | `-` affine-expr
1022/// | affine-expr `+` affine-expr
1023/// | affine-expr `-` affine-expr
1024/// | affine-expr `*` affine-expr
1025/// | affine-expr `floordiv` affine-expr
1026/// | affine-expr `ceildiv` affine-expr
1027/// | affine-expr `mod` affine-expr
1028/// | bare-id
1029/// | integer-literal
1030///
1031/// Additional conditions are checked depending on the production. For eg., one
1032/// of the operands for `*` has to be either constant/symbolic; the second
1033/// operand for floordiv, ceildiv, and mod has to be a positive integer.
Chris Lattner2e595eb2018-07-10 10:08:27 -07001034AffineExpr *AffineMapParser::parseAffineExpr() {
1035 return parseAffineLowPrecOpExpr(nullptr, AffineLowPrecOp::LNoOp);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001036}
1037
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001038/// Parse a dim or symbol from the lists appearing before the actual expressions
Chris Lattner2e595eb2018-07-10 10:08:27 -07001039/// of the affine map. Update our state to store the dimensional/symbolic
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001040/// identifier. 'dim': whether it's the dim list or symbol list that is being
1041/// parsed.
Chris Lattner2e595eb2018-07-10 10:08:27 -07001042ParseResult AffineMapParser::parseDimOrSymbolId(bool isDim) {
Chris Lattner48af7d12018-07-09 19:05:38 -07001043 if (getToken().isNot(Token::bare_identifier))
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001044 return emitError("expected bare identifier");
Chris Lattner48af7d12018-07-09 19:05:38 -07001045 auto sRef = getTokenSpelling();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001046 consumeToken(Token::bare_identifier);
Chris Lattner2e595eb2018-07-10 10:08:27 -07001047 if (dims.count(sRef))
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001048 return emitError("dimensional identifier name reused");
Chris Lattner2e595eb2018-07-10 10:08:27 -07001049 if (symbols.count(sRef))
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001050 return emitError("symbolic identifier name reused");
Chris Lattner2e595eb2018-07-10 10:08:27 -07001051 if (isDim)
1052 dims.insert({sRef, dims.size()});
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001053 else
Chris Lattner2e595eb2018-07-10 10:08:27 -07001054 symbols.insert({sRef, symbols.size()});
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001055 return ParseSuccess;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001056}
1057
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001058/// Parse the list of symbolic identifiers to an affine map.
Chris Lattner2e595eb2018-07-10 10:08:27 -07001059ParseResult AffineMapParser::parseSymbolIdList() {
1060 if (!consumeIf(Token::l_bracket))
1061 return emitError("expected '['");
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001062
Chris Lattner2e595eb2018-07-10 10:08:27 -07001063 auto parseElt = [&]() -> ParseResult { return parseDimOrSymbolId(false); };
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001064 return parseCommaSeparatedList(Token::r_bracket, parseElt);
1065}
1066
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001067/// Parse the list of dimensional identifiers to an affine map.
Chris Lattner2e595eb2018-07-10 10:08:27 -07001068ParseResult AffineMapParser::parseDimIdList() {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001069 if (!consumeIf(Token::l_paren))
1070 return emitError("expected '(' at start of dimensional identifiers list");
1071
Chris Lattner2e595eb2018-07-10 10:08:27 -07001072 auto parseElt = [&]() -> ParseResult { return parseDimOrSymbolId(true); };
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001073 return parseCommaSeparatedList(Token::r_paren, parseElt);
1074}
1075
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001076/// Parse an affine map definition.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001077///
Uday Bondhugula3934d4d2018-07-09 09:00:25 -07001078/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
1079/// (`size` `(` dim-size (`,` dim-size)* `)`)?
1080/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001081///
Uday Bondhugula3934d4d2018-07-09 09:00:25 -07001082/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
Chris Lattner2e595eb2018-07-10 10:08:27 -07001083AffineMap *AffineMapParser::parseAffineMapInline() {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001084 // List of dimensional identifiers.
Chris Lattner2e595eb2018-07-10 10:08:27 -07001085 if (parseDimIdList())
Chris Lattner7121b802018-07-04 20:45:39 -07001086 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001087
1088 // Symbols are optional.
Chris Lattner48af7d12018-07-09 19:05:38 -07001089 if (getToken().is(Token::l_bracket)) {
Chris Lattner2e595eb2018-07-10 10:08:27 -07001090 if (parseSymbolIdList())
Chris Lattner7121b802018-07-04 20:45:39 -07001091 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001092 }
1093 if (!consumeIf(Token::arrow)) {
Chris Lattner7121b802018-07-04 20:45:39 -07001094 return (emitError("expected '->' or '['"), nullptr);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001095 }
1096 if (!consumeIf(Token::l_paren)) {
1097 emitError("expected '(' at start of affine map range");
Chris Lattner7121b802018-07-04 20:45:39 -07001098 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001099 }
1100
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001101 SmallVector<AffineExpr *, 4> exprs;
1102 auto parseElt = [&]() -> ParseResult {
Chris Lattner2e595eb2018-07-10 10:08:27 -07001103 auto *elt = parseAffineExpr();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001104 ParseResult res = elt ? ParseSuccess : ParseFailure;
1105 exprs.push_back(elt);
1106 return res;
1107 };
1108
1109 // Parse a multi-dimensional affine expression (a comma-separated list of 1-d
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001110 // affine expressions); the list cannot be empty.
1111 // Grammar: multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
1112 if (parseCommaSeparatedList(Token::r_paren, parseElt, false))
Chris Lattner7121b802018-07-04 20:45:39 -07001113 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001114
Uday Bondhugula0115dbb2018-07-11 21:31:07 -07001115 // Parse optional range sizes.
Uday Bondhugula1e500b42018-07-12 18:04:04 -07001116 // range-sizes ::= (`size` `(` dim-size (`,` dim-size)* `)`)?
1117 // dim-size ::= affine-expr | `min` `(` affine-expr (`,` affine-expr)+ `)`
1118 // TODO(bondhugula): support for min of several affine expressions.
Uday Bondhugula0115dbb2018-07-11 21:31:07 -07001119 // TODO: check if sizes are non-negative whenever they are constant.
1120 SmallVector<AffineExpr *, 4> rangeSizes;
1121 if (consumeIf(Token::kw_size)) {
1122 // Location of the l_paren token (if it exists) for error reporting later.
1123 auto loc = getToken().getLoc();
1124 if (!consumeIf(Token::l_paren))
1125 return (emitError("expected '(' at start of affine map range"), nullptr);
1126
1127 auto parseRangeSize = [&]() -> ParseResult {
1128 auto *elt = parseAffineExpr();
1129 ParseResult res = elt ? ParseSuccess : ParseFailure;
1130 rangeSizes.push_back(elt);
1131 return res;
1132 };
1133
1134 setSymbolicParsing(true);
1135 if (parseCommaSeparatedList(Token::r_paren, parseRangeSize, false))
1136 return nullptr;
1137 if (exprs.size() > rangeSizes.size())
1138 return (emitError(loc, "fewer range sizes than range expressions"),
1139 nullptr);
1140 if (exprs.size() < rangeSizes.size())
1141 return (emitError(loc, "more range sizes than range expressions"),
1142 nullptr);
1143 }
1144
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001145 // Parsed a valid affine map.
Uday Bondhugula0115dbb2018-07-11 21:31:07 -07001146 return builder.getAffineMap(dims.size(), symbols.size(), exprs, rangeSizes);
MLIR Teamf85a6262018-06-27 11:03:08 -07001147}
1148
Chris Lattner2e595eb2018-07-10 10:08:27 -07001149AffineMap *Parser::parseAffineMapInline() {
1150 return AffineMapParser(state).parseAffineMapInline();
1151}
1152
MLIR Team718c82f2018-07-16 09:45:22 -07001153AffineMap *Parser::parseAffineMapReference() {
1154 if (getToken().is(Token::hash_identifier)) {
1155 // Parse affine map identifier and verify that it exists.
1156 StringRef affineMapId = getTokenSpelling().drop_front();
1157 if (getState().affineMapDefinitions.count(affineMapId) == 0)
1158 return (emitError("undefined affine map id '" + affineMapId + "'"),
1159 nullptr);
1160 consumeToken(Token::hash_identifier);
1161 return getState().affineMapDefinitions[affineMapId];
1162 }
1163 // Try to parse inline affine map.
1164 return parseAffineMapInline();
1165}
1166
MLIR Teamf85a6262018-06-27 11:03:08 -07001167//===----------------------------------------------------------------------===//
Chris Lattner78276e32018-07-07 15:48:26 -07001168// SSA
Chris Lattner4c95a502018-06-23 16:03:42 -07001169//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -07001170
Chris Lattner78276e32018-07-07 15:48:26 -07001171/// Parse a SSA operand for an instruction or statement.
1172///
1173/// ssa-use ::= ssa-id | ssa-constant
1174///
1175ParseResult Parser::parseSSAUse() {
Chris Lattner48af7d12018-07-09 19:05:38 -07001176 if (getToken().is(Token::percent_identifier)) {
1177 StringRef name = getTokenSpelling().drop_front();
Chris Lattner78276e32018-07-07 15:48:26 -07001178 consumeToken(Token::percent_identifier);
1179 // TODO: Return this use.
1180 (void)name;
1181 return ParseSuccess;
1182 }
1183
1184 // TODO: Parse SSA constants.
1185
1186 return emitError("expected SSA operand");
1187}
1188
1189/// Parse a (possibly empty) list of SSA operands.
1190///
1191/// ssa-use-list ::= ssa-use (`,` ssa-use)*
1192/// ssa-use-list-opt ::= ssa-use-list?
1193///
1194ParseResult Parser::parseOptionalSSAUseList(Token::Kind endToken) {
1195 // TODO: Build and return this.
1196 return parseCommaSeparatedList(
1197 endToken, [&]() -> ParseResult { return parseSSAUse(); });
1198}
1199
1200/// Parse an SSA use with an associated type.
1201///
1202/// ssa-use-and-type ::= ssa-use `:` type
1203ParseResult Parser::parseSSAUseAndType() {
1204 if (parseSSAUse())
1205 return ParseFailure;
1206
1207 if (!consumeIf(Token::colon))
1208 return emitError("expected ':' and type for SSA operand");
1209
1210 if (!parseType())
1211 return ParseFailure;
1212
1213 return ParseSuccess;
1214}
1215
1216/// Parse a (possibly empty) list of SSA operands with types.
1217///
1218/// ssa-use-and-type-list ::= ssa-use-and-type (`,` ssa-use-and-type)*
1219///
1220ParseResult Parser::parseOptionalSSAUseAndTypeList(Token::Kind endToken) {
1221 // TODO: Build and return this.
1222 return parseCommaSeparatedList(
1223 endToken, [&]() -> ParseResult { return parseSSAUseAndType(); });
1224}
1225
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001226//===----------------------------------------------------------------------===//
1227// Operations
1228//===----------------------------------------------------------------------===//
1229
1230/// Parse the CFG or MLFunc operation.
1231///
1232/// TODO(clattner): This is a change from the MLIR spec as written, it is an
1233/// experiment that will eliminate "builtin" instructions as a thing.
1234///
1235/// operation ::=
1236/// (ssa-id `=`)? string '(' ssa-use-list? ')' attribute-dict?
1237/// `:` function-type
1238///
1239ParseResult
1240Parser::parseOperation(const CreateOperationFunction &createOpFunc) {
1241 auto loc = getToken().getLoc();
1242
1243 StringRef resultID;
1244 if (getToken().is(Token::percent_identifier)) {
1245 resultID = getTokenSpelling().drop_front();
1246 consumeToken(Token::percent_identifier);
1247 if (!consumeIf(Token::equal))
1248 return emitError("expected '=' after SSA name");
1249 }
1250
1251 if (getToken().isNot(Token::string))
1252 return emitError("expected operation name in quotes");
1253
1254 auto name = getToken().getStringValue();
1255 if (name.empty())
1256 return emitError("empty operation name is invalid");
1257
1258 consumeToken(Token::string);
1259
1260 if (!consumeIf(Token::l_paren))
1261 return emitError("expected '(' to start operand list");
1262
1263 // Parse the operand list.
1264 parseOptionalSSAUseList(Token::r_paren);
1265
1266 SmallVector<NamedAttribute, 4> attributes;
1267 if (getToken().is(Token::l_brace)) {
1268 if (parseAttributeDict(attributes))
1269 return ParseFailure;
1270 }
1271
1272 // TODO: Don't drop result name and operand names on the floor.
1273 auto nameId = builder.getIdentifier(name);
1274
1275 auto oper = createOpFunc(nameId, attributes);
1276
1277 if (!oper)
1278 return ParseFailure;
1279
1280 // We just parsed an operation. If it is a recognized one, verify that it
1281 // is structurally as we expect. If not, produce an error with a reasonable
1282 // source location.
1283 if (auto *opInfo = oper->getAbstractOperation(builder.getContext())) {
1284 if (auto error = opInfo->verifyInvariants(oper))
1285 return emitError(loc, error);
1286 }
1287
1288 return ParseSuccess;
1289}
Chris Lattnere79379a2018-06-22 10:39:19 -07001290
Chris Lattner48af7d12018-07-09 19:05:38 -07001291//===----------------------------------------------------------------------===//
1292// CFG Functions
1293//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -07001294
Chris Lattner4c95a502018-06-23 16:03:42 -07001295namespace {
Chris Lattner48af7d12018-07-09 19:05:38 -07001296/// This is a specialized parser for CFGFunction's, maintaining the state
1297/// transient to their bodies.
1298class CFGFunctionParser : public Parser {
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001299public:
Chris Lattner2e595eb2018-07-10 10:08:27 -07001300 CFGFunctionParser(ParserState &state, CFGFunction *function)
1301 : Parser(state), function(function), builder(function) {}
1302
1303 ParseResult parseFunctionBody();
1304
1305private:
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001306 CFGFunction *function;
1307 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
Chris Lattner48af7d12018-07-09 19:05:38 -07001308
1309 /// This builder intentionally shadows the builder in the base class, with a
1310 /// more specific builder type.
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001311 CFGFuncBuilder builder;
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001312
Chris Lattner4c95a502018-06-23 16:03:42 -07001313 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001314 /// already exist. The location specified is the point of use, which allows
1315 /// us to diagnose references to blocks that are not defined precisely.
1316 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
1317 auto &blockAndLoc = blocksByName[name];
1318 if (!blockAndLoc.first) {
Chris Lattner3a467cc2018-07-01 20:28:00 -07001319 blockAndLoc.first = new BasicBlock();
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001320 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -07001321 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001322 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -07001323 }
Chris Lattner48af7d12018-07-09 19:05:38 -07001324
Chris Lattner48af7d12018-07-09 19:05:38 -07001325 ParseResult parseBasicBlock();
1326 OperationInst *parseCFGOperation();
1327 TerminatorInst *parseTerminator();
Chris Lattner4c95a502018-06-23 16:03:42 -07001328};
1329} // end anonymous namespace
1330
Chris Lattner48af7d12018-07-09 19:05:38 -07001331ParseResult CFGFunctionParser::parseFunctionBody() {
1332 if (!consumeIf(Token::l_brace))
1333 return emitError("expected '{' in CFG function");
1334
1335 // Make sure we have at least one block.
1336 if (getToken().is(Token::r_brace))
1337 return emitError("CFG functions must have at least one basic block");
Chris Lattner4c95a502018-06-23 16:03:42 -07001338
1339 // Parse the list of blocks.
1340 while (!consumeIf(Token::r_brace))
Chris Lattner48af7d12018-07-09 19:05:38 -07001341 if (parseBasicBlock())
Chris Lattner4c95a502018-06-23 16:03:42 -07001342 return ParseFailure;
1343
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001344 // Verify that all referenced blocks were defined. Iteration over a
1345 // StringMap isn't determinstic, but this is good enough for our purposes.
Chris Lattner48af7d12018-07-09 19:05:38 -07001346 for (auto &elt : blocksByName) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001347 auto *bb = elt.second.first;
Chris Lattner3a467cc2018-07-01 20:28:00 -07001348 if (!bb->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001349 return emitError(elt.second.second,
1350 "reference to an undefined basic block '" +
1351 elt.first() + "'");
1352 }
1353
Chris Lattner48af7d12018-07-09 19:05:38 -07001354 getModule()->functionList.push_back(function);
Chris Lattner4c95a502018-06-23 16:03:42 -07001355 return ParseSuccess;
1356}
1357
1358/// Basic block declaration.
1359///
1360/// basic-block ::= bb-label instruction* terminator-stmt
1361/// bb-label ::= bb-id bb-arg-list? `:`
1362/// bb-id ::= bare-id
1363/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
1364///
Chris Lattner48af7d12018-07-09 19:05:38 -07001365ParseResult CFGFunctionParser::parseBasicBlock() {
1366 SMLoc nameLoc = getToken().getLoc();
1367 auto name = getTokenSpelling();
Chris Lattner4c95a502018-06-23 16:03:42 -07001368 if (!consumeIf(Token::bare_identifier))
1369 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001370
Chris Lattner48af7d12018-07-09 19:05:38 -07001371 auto *block = getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -07001372
1373 // If this block has already been parsed, then this is a redefinition with the
1374 // same block name.
Chris Lattner3a467cc2018-07-01 20:28:00 -07001375 if (block->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001376 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
1377
Chris Lattner3a467cc2018-07-01 20:28:00 -07001378 // Add the block to the function.
Chris Lattner48af7d12018-07-09 19:05:38 -07001379 function->push_back(block);
Chris Lattner4c95a502018-06-23 16:03:42 -07001380
Chris Lattner78276e32018-07-07 15:48:26 -07001381 // If an argument list is present, parse it.
1382 if (consumeIf(Token::l_paren)) {
1383 if (parseOptionalSSAUseAndTypeList(Token::r_paren))
1384 return ParseFailure;
1385
1386 // TODO: attach it.
1387 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001388
1389 if (!consumeIf(Token::colon))
1390 return emitError("expected ':' after basic block name");
1391
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001392 // Set the insertion point to the block we want to insert new operations into.
Chris Lattner48af7d12018-07-09 19:05:38 -07001393 builder.setInsertionPoint(block);
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001394
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001395 auto createOpFunc = [this](Identifier name,
1396 ArrayRef<NamedAttribute> attrs) -> Operation * {
1397 return builder.createOperation(name, attrs);
1398 };
1399
Chris Lattnered65a732018-06-28 20:45:33 -07001400 // Parse the list of operations that make up the body of the block.
Chris Lattner48af7d12018-07-09 19:05:38 -07001401 while (getToken().isNot(Token::kw_return, Token::kw_br)) {
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001402 if (parseOperation(createOpFunc))
Chris Lattnered65a732018-06-28 20:45:33 -07001403 return ParseFailure;
1404 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001405
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001406 if (!parseTerminator())
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001407 return ParseFailure;
Chris Lattner4c95a502018-06-23 16:03:42 -07001408
1409 return ParseSuccess;
1410}
1411
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001412/// Parse the terminator instruction for a basic block.
1413///
1414/// terminator-stmt ::= `br` bb-id branch-use-list?
1415/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
1416/// terminator-stmt ::=
1417/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
1418/// terminator-stmt ::= `return` ssa-use-and-type-list?
1419///
Chris Lattner48af7d12018-07-09 19:05:38 -07001420TerminatorInst *CFGFunctionParser::parseTerminator() {
1421 switch (getToken().getKind()) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001422 default:
Chris Lattner3a467cc2018-07-01 20:28:00 -07001423 return (emitError("expected terminator at end of basic block"), nullptr);
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001424
1425 case Token::kw_return:
1426 consumeToken(Token::kw_return);
Chris Lattner48af7d12018-07-09 19:05:38 -07001427 return builder.createReturnInst();
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001428
1429 case Token::kw_br: {
1430 consumeToken(Token::kw_br);
Chris Lattner48af7d12018-07-09 19:05:38 -07001431 auto destBB = getBlockNamed(getTokenSpelling(), getToken().getLoc());
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001432 if (!consumeIf(Token::bare_identifier))
Chris Lattner3a467cc2018-07-01 20:28:00 -07001433 return (emitError("expected basic block name"), nullptr);
Chris Lattner48af7d12018-07-09 19:05:38 -07001434 return builder.createBranchInst(destBB);
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001435 }
Chris Lattner78276e32018-07-07 15:48:26 -07001436 // TODO: cond_br.
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001437 }
1438}
1439
Chris Lattner48af7d12018-07-09 19:05:38 -07001440//===----------------------------------------------------------------------===//
1441// ML Functions
1442//===----------------------------------------------------------------------===//
1443
1444namespace {
1445/// Refined parser for MLFunction bodies.
1446class MLFunctionParser : public Parser {
1447public:
Chris Lattner48af7d12018-07-09 19:05:38 -07001448 MLFunctionParser(ParserState &state, MLFunction *function)
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001449 : Parser(state), function(function), builder(function) {}
Chris Lattner48af7d12018-07-09 19:05:38 -07001450
1451 ParseResult parseFunctionBody();
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001452
1453private:
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001454 MLFunction *function;
1455
1456 /// This builder intentionally shadows the builder in the base class, with a
1457 /// more specific builder type.
1458 MLFuncBuilder builder;
1459
1460 ParseResult parseForStmt();
1461 ParseResult parseIfStmt();
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001462 ParseResult parseElseClause(IfClause *elseClause);
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001463 ParseResult parseStatements(StmtBlock *block);
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001464 ParseResult parseStmtBlock(StmtBlock *block);
Chris Lattner48af7d12018-07-09 19:05:38 -07001465};
1466} // end anonymous namespace
1467
Chris Lattner48af7d12018-07-09 19:05:38 -07001468ParseResult MLFunctionParser::parseFunctionBody() {
1469 if (!consumeIf(Token::l_brace))
1470 return emitError("expected '{' in ML function");
1471
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001472 // Parse statements in this function
1473 if (parseStatements(function))
1474 return ParseFailure;
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001475
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001476 if (!consumeIf(Token::kw_return))
1477 emitError("ML function must end with return statement");
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001478 // TODO: parse return statement operands
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001479
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001480 if (!consumeIf(Token::r_brace))
1481 emitError("expected '}' in ML function");
1482
Chris Lattner48af7d12018-07-09 19:05:38 -07001483 getModule()->functionList.push_back(function);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001484
1485 return ParseSuccess;
1486}
1487
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001488/// For statement.
1489///
Chris Lattner48af7d12018-07-09 19:05:38 -07001490/// ml-for-stmt ::= `for` ssa-id `=` lower-bound `to` upper-bound
1491/// (`step` integer-literal)? `{` ml-stmt* `}`
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001492///
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001493ParseResult MLFunctionParser::parseForStmt() {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001494 consumeToken(Token::kw_for);
1495
1496 //TODO: parse loop header
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001497 ForStmt *stmt = builder.createFor();
1498
1499 // If parsing of the for statement body fails
1500 // MLIR contains for statement with successfully parsed nested statements
1501 if (parseStmtBlock(static_cast<StmtBlock *>(stmt)))
1502 return ParseFailure;
1503
1504 return ParseSuccess;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001505}
1506
1507/// If statement.
1508///
Chris Lattner48af7d12018-07-09 19:05:38 -07001509/// ml-if-head ::= `if` ml-if-cond `{` ml-stmt* `}`
1510/// | ml-if-head `else` `if` ml-if-cond `{` ml-stmt* `}`
1511/// ml-if-stmt ::= ml-if-head
1512/// | ml-if-head `else` `{` ml-stmt* `}`
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001513///
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001514ParseResult MLFunctionParser::parseIfStmt() {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001515 consumeToken(Token::kw_if);
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001516 if (!consumeIf(Token::l_paren))
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001517 return emitError("expected (");
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001518
1519 //TODO: parse condition
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001520
1521 if (!consumeIf(Token::r_paren))
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001522 return emitError("expected )");
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001523
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001524 IfStmt *ifStmt = builder.createIf();
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001525 IfClause *thenClause = ifStmt->getThenClause();
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001526
1527 // If parsing of the then or optional else clause fails MLIR contains
1528 // if statement with successfully parsed nested statements.
1529 if (parseStmtBlock(thenClause))
1530 return ParseFailure;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001531
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001532 if (consumeIf(Token::kw_else)) {
1533 IfClause *elseClause = ifStmt->createElseClause();
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001534 if (parseElseClause(elseClause))
1535 return ParseFailure;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001536 }
1537
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001538 return ParseSuccess;
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001539}
1540
1541ParseResult MLFunctionParser::parseElseClause(IfClause *elseClause) {
1542 if (getToken().is(Token::kw_if)) {
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001543 builder.setInsertionPoint(elseClause);
1544 return parseIfStmt();
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001545 }
1546
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001547 return parseStmtBlock(elseClause);
1548}
1549
1550///
1551/// Parse a list of statements ending with `return` or `}`
1552///
1553ParseResult MLFunctionParser::parseStatements(StmtBlock *block) {
1554 auto createOpFunc = [this](Identifier name,
1555 ArrayRef<NamedAttribute> attrs) -> Operation * {
1556 return builder.createOperation(name, attrs);
1557 };
1558
1559 builder.setInsertionPoint(block);
1560
1561 while (getToken().isNot(Token::kw_return, Token::r_brace)) {
1562 switch (getToken().getKind()) {
1563 default:
1564 if (parseOperation(createOpFunc))
1565 return ParseFailure;
1566 break;
1567 case Token::kw_for:
1568 if (parseForStmt())
1569 return ParseFailure;
1570 break;
1571 case Token::kw_if:
1572 if (parseIfStmt())
1573 return ParseFailure;
1574 break;
1575 } // end switch
1576 }
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001577
1578 return ParseSuccess;
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001579}
1580
1581///
1582/// Parse `{` ml-stmt* `}`
1583///
Tatiana Shpeisman1bcfe982018-07-13 13:03:13 -07001584ParseResult MLFunctionParser::parseStmtBlock(StmtBlock *block) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001585 if (!consumeIf(Token::l_brace))
1586 return emitError("expected '{' before statement list");
1587
Tatiana Shpeisman565b9642018-07-16 11:47:09 -07001588 if (parseStatements(block))
1589 return ParseFailure;
1590
1591 if (!consumeIf(Token::r_brace))
1592 return emitError("expected '}' at the end of the statement block");
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001593
1594 return ParseSuccess;
1595}
1596
Chris Lattner4c95a502018-06-23 16:03:42 -07001597//===----------------------------------------------------------------------===//
1598// Top-level entity parsing.
1599//===----------------------------------------------------------------------===//
1600
Chris Lattner2e595eb2018-07-10 10:08:27 -07001601namespace {
1602/// This parser handles entities that are only valid at the top level of the
1603/// file.
1604class ModuleParser : public Parser {
1605public:
1606 explicit ModuleParser(ParserState &state) : Parser(state) {}
1607
1608 ParseResult parseModule();
1609
1610private:
1611 ParseResult parseAffineMapDef();
1612
1613 // Functions.
1614 ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
1615 ParseResult parseExtFunc();
1616 ParseResult parseCFGFunc();
1617 ParseResult parseMLFunc();
1618};
1619} // end anonymous namespace
1620
1621/// Affine map declaration.
1622///
1623/// affine-map-def ::= affine-map-id `=` affine-map-inline
1624///
1625ParseResult ModuleParser::parseAffineMapDef() {
1626 assert(getToken().is(Token::hash_identifier));
1627
1628 StringRef affineMapId = getTokenSpelling().drop_front();
1629
1630 // Check for redefinitions.
1631 auto *&entry = getState().affineMapDefinitions[affineMapId];
1632 if (entry)
1633 return emitError("redefinition of affine map id '" + affineMapId + "'");
1634
1635 consumeToken(Token::hash_identifier);
1636
1637 // Parse the '='
1638 if (!consumeIf(Token::equal))
1639 return emitError("expected '=' in affine map outlined definition");
1640
1641 entry = parseAffineMapInline();
1642 if (!entry)
1643 return ParseFailure;
1644
Chris Lattner2e595eb2018-07-10 10:08:27 -07001645 return ParseSuccess;
1646}
1647
1648/// Parse a function signature, starting with a name and including the parameter
1649/// list.
1650///
1651/// argument-list ::= type (`,` type)* | /*empty*/
1652/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
1653///
1654ParseResult ModuleParser::parseFunctionSignature(StringRef &name,
1655 FunctionType *&type) {
1656 if (getToken().isNot(Token::at_identifier))
1657 return emitError("expected a function identifier like '@foo'");
1658
1659 name = getTokenSpelling().drop_front();
1660 consumeToken(Token::at_identifier);
1661
1662 if (getToken().isNot(Token::l_paren))
1663 return emitError("expected '(' in function signature");
1664
1665 SmallVector<Type *, 4> arguments;
1666 if (parseTypeList(arguments))
1667 return ParseFailure;
1668
1669 // Parse the return type if present.
1670 SmallVector<Type *, 4> results;
1671 if (consumeIf(Token::arrow)) {
1672 if (parseTypeList(results))
1673 return ParseFailure;
1674 }
1675 type = builder.getFunctionType(arguments, results);
1676 return ParseSuccess;
1677}
1678
1679/// External function declarations.
1680///
1681/// ext-func ::= `extfunc` function-signature
1682///
1683ParseResult ModuleParser::parseExtFunc() {
1684 consumeToken(Token::kw_extfunc);
1685
1686 StringRef name;
1687 FunctionType *type = nullptr;
1688 if (parseFunctionSignature(name, type))
1689 return ParseFailure;
1690
1691 // Okay, the external function definition was parsed correctly.
1692 getModule()->functionList.push_back(new ExtFunction(name, type));
1693 return ParseSuccess;
1694}
1695
1696/// CFG function declarations.
1697///
1698/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
1699///
1700ParseResult ModuleParser::parseCFGFunc() {
1701 consumeToken(Token::kw_cfgfunc);
1702
1703 StringRef name;
1704 FunctionType *type = nullptr;
1705 if (parseFunctionSignature(name, type))
1706 return ParseFailure;
1707
1708 // Okay, the CFG function signature was parsed correctly, create the function.
1709 auto function = new CFGFunction(name, type);
1710
1711 return CFGFunctionParser(getState(), function).parseFunctionBody();
1712}
1713
1714/// ML function declarations.
1715///
1716/// ml-func ::= `mlfunc` ml-func-signature `{` ml-stmt* ml-return-stmt `}`
1717///
1718ParseResult ModuleParser::parseMLFunc() {
1719 consumeToken(Token::kw_mlfunc);
1720
1721 StringRef name;
1722 FunctionType *type = nullptr;
1723
1724 // FIXME: Parse ML function signature (args + types)
1725 // by passing pointer to SmallVector<identifier> into parseFunctionSignature
1726 if (parseFunctionSignature(name, type))
1727 return ParseFailure;
1728
1729 // Okay, the ML function signature was parsed correctly, create the function.
1730 auto function = new MLFunction(name, type);
1731
1732 return MLFunctionParser(getState(), function).parseFunctionBody();
1733}
1734
Chris Lattnere79379a2018-06-22 10:39:19 -07001735/// This is the top-level module parser.
Chris Lattner2e595eb2018-07-10 10:08:27 -07001736ParseResult ModuleParser::parseModule() {
Chris Lattnere79379a2018-06-22 10:39:19 -07001737 while (1) {
Chris Lattner48af7d12018-07-09 19:05:38 -07001738 switch (getToken().getKind()) {
Chris Lattnere79379a2018-06-22 10:39:19 -07001739 default:
1740 emitError("expected a top level entity");
Chris Lattner2e595eb2018-07-10 10:08:27 -07001741 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -07001742
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001743 // If we got to the end of the file, then we're done.
Chris Lattnere79379a2018-06-22 10:39:19 -07001744 case Token::eof:
Chris Lattner2e595eb2018-07-10 10:08:27 -07001745 return ParseSuccess;
Chris Lattnere79379a2018-06-22 10:39:19 -07001746
1747 // If we got an error token, then the lexer already emitted an error, just
1748 // stop. Someday we could introduce error recovery if there was demand for
1749 // it.
1750 case Token::error:
Chris Lattner2e595eb2018-07-10 10:08:27 -07001751 return ParseFailure;
1752
1753 case Token::hash_identifier:
1754 if (parseAffineMapDef())
1755 return ParseFailure;
1756 break;
Chris Lattnere79379a2018-06-22 10:39:19 -07001757
1758 case Token::kw_extfunc:
Chris Lattner2e595eb2018-07-10 10:08:27 -07001759 if (parseExtFunc())
1760 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -07001761 break;
1762
Chris Lattner4c95a502018-06-23 16:03:42 -07001763 case Token::kw_cfgfunc:
Chris Lattner2e595eb2018-07-10 10:08:27 -07001764 if (parseCFGFunc())
1765 return ParseFailure;
MLIR Teamf85a6262018-06-27 11:03:08 -07001766 break;
Chris Lattner4c95a502018-06-23 16:03:42 -07001767
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001768 case Token::kw_mlfunc:
Chris Lattner2e595eb2018-07-10 10:08:27 -07001769 if (parseMLFunc())
1770 return ParseFailure;
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001771 break;
1772
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001773 // TODO: affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -07001774 }
1775 }
1776}
1777
1778//===----------------------------------------------------------------------===//
1779
Jacques Pienaar7b829702018-07-03 13:24:09 -07001780void mlir::defaultErrorReporter(const llvm::SMDiagnostic &error) {
1781 const auto &sourceMgr = *error.getSourceMgr();
1782 sourceMgr.PrintMessage(error.getLoc(), error.getKind(), error.getMessage());
1783}
1784
Chris Lattnere79379a2018-06-22 10:39:19 -07001785/// This parses the file specified by the indicated SourceMgr and returns an
1786/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Jacques Pienaar9c411be2018-06-24 19:17:35 -07001787Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context,
Jacques Pienaar7b829702018-07-03 13:24:09 -07001788 SMDiagnosticHandlerTy errorReporter) {
Chris Lattner2e595eb2018-07-10 10:08:27 -07001789 // This is the result module we are parsing into.
1790 std::unique_ptr<Module> module(new Module(context));
1791
1792 ParserState state(sourceMgr, module.get(),
Jacques Pienaar0bffd862018-07-11 13:26:23 -07001793 errorReporter ? errorReporter : defaultErrorReporter);
Chris Lattner2e595eb2018-07-10 10:08:27 -07001794 if (ModuleParser(state).parseModule())
1795 return nullptr;
Chris Lattner21e67f62018-07-06 10:46:19 -07001796
1797 // Make sure the parse module has no other structural problems detected by the
1798 // verifier.
Chris Lattner2e595eb2018-07-10 10:08:27 -07001799 module->verify();
1800 return module.release();
Chris Lattnere79379a2018-06-22 10:39:19 -07001801}