blob: dd0112e7320cf955f992b05f268caa0fb9f5bbfc [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//===----------------------------------------------------------------------===//
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070021#include <stack>
Chris Lattnere79379a2018-06-22 10:39:19 -070022
23#include "mlir/Parser.h"
24#include "Lexer.h"
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070025#include "mlir/IR/AffineExpr.h"
MLIR Teamf85a6262018-06-27 11:03:08 -070026#include "mlir/IR/AffineMap.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070027#include "mlir/IR/CFGFunction.h"
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070028#include "mlir/IR/Module.h"
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -070029#include "mlir/IR/MLFunction.h"
Chris Lattnerf7e22732018-06-22 22:03:48 -070030#include "mlir/IR/Types.h"
Chris Lattnere79379a2018-06-22 10:39:19 -070031#include "llvm/Support/SourceMgr.h"
32using namespace mlir;
33using llvm::SourceMgr;
Chris Lattner4c95a502018-06-23 16:03:42 -070034using llvm::SMLoc;
Chris Lattnere79379a2018-06-22 10:39:19 -070035
36namespace {
Chris Lattner4c95a502018-06-23 16:03:42 -070037class CFGFunctionParserState;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070038class AffineMapParserState;
Chris Lattner4c95a502018-06-23 16:03:42 -070039
Chris Lattnerf7e22732018-06-22 22:03:48 -070040/// Simple enum to make code read better in cases that would otherwise return a
41/// bool value. Failure is "true" in a boolean context.
Chris Lattnere79379a2018-06-22 10:39:19 -070042enum ParseResult {
43 ParseSuccess,
44 ParseFailure
45};
46
47/// Main parser implementation.
48class Parser {
Chris Lattnered65a732018-06-28 20:45:33 -070049public:
Jacques Pienaar9c411be2018-06-24 19:17:35 -070050 Parser(llvm::SourceMgr &sourceMgr, MLIRContext *context,
Jacques Pienaar7b829702018-07-03 13:24:09 -070051 SMDiagnosticHandlerTy errorReporter)
52 : context(context), lex(sourceMgr, errorReporter),
53 curToken(lex.lexToken()), errorReporter(std::move(errorReporter)) {
Chris Lattnere79379a2018-06-22 10:39:19 -070054 module.reset(new Module());
55 }
56
57 Module *parseModule();
58private:
59 // State.
Chris Lattnerf7e22732018-06-22 22:03:48 -070060 MLIRContext *const context;
61
62 // The lexer for the source file we're parsing.
Chris Lattnere79379a2018-06-22 10:39:19 -070063 Lexer lex;
64
65 // This is the next token that hasn't been consumed yet.
66 Token curToken;
67
Jacques Pienaar9c411be2018-06-24 19:17:35 -070068 // The diagnostic error reporter.
Jacques Pienaar7b829702018-07-03 13:24:09 -070069 SMDiagnosticHandlerTy errorReporter;
Jacques Pienaar9c411be2018-06-24 19:17:35 -070070
Chris Lattnere79379a2018-06-22 10:39:19 -070071 // This is the result module we are parsing into.
72 std::unique_ptr<Module> module;
73
MLIR Teamf85a6262018-06-27 11:03:08 -070074 // A map from affine map identifier to AffineMap.
75 // TODO(andydavis) Remove use of unique_ptr when AffineMaps are bump pointer
76 // allocated.
77 llvm::StringMap<std::unique_ptr<AffineMap>> affineMaps;
78
Chris Lattnere79379a2018-06-22 10:39:19 -070079private:
80 // Helper methods.
81
82 /// Emit an error and return failure.
Chris Lattner4c95a502018-06-23 16:03:42 -070083 ParseResult emitError(const Twine &message) {
84 return emitError(curToken.getLoc(), message);
85 }
86 ParseResult emitError(SMLoc loc, const Twine &message);
Chris Lattnere79379a2018-06-22 10:39:19 -070087
88 /// Advance the current lexer onto the next token.
89 void consumeToken() {
90 assert(curToken.isNot(Token::eof, Token::error) &&
91 "shouldn't advance past EOF or errors");
92 curToken = lex.lexToken();
93 }
94
95 /// Advance the current lexer onto the next token, asserting what the expected
96 /// current token is. This is preferred to the above method because it leads
97 /// to more self-documenting code with better checking.
Chris Lattner8da0c282018-06-29 11:15:56 -070098 void consumeToken(Token::Kind kind) {
Chris Lattnere79379a2018-06-22 10:39:19 -070099 assert(curToken.is(kind) && "consumed an unexpected token");
100 consumeToken();
101 }
102
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700103 /// If the current token has the specified kind, consume it and return true.
104 /// If not, return false.
Chris Lattner8da0c282018-06-29 11:15:56 -0700105 bool consumeIf(Token::Kind kind) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700106 if (curToken.isNot(kind))
107 return false;
108 consumeToken(kind);
109 return true;
110 }
111
Chris Lattner8da0c282018-06-29 11:15:56 -0700112 ParseResult parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700113 const std::function<ParseResult()> &parseElement,
114 bool allowEmptyList = true);
115
Chris Lattnerf7e22732018-06-22 22:03:48 -0700116 // We have two forms of parsing methods - those that return a non-null
117 // pointer on success, and those that return a ParseResult to indicate whether
118 // they returned a failure. The second class fills in by-reference arguments
119 // as the results of their action.
120
Chris Lattnere79379a2018-06-22 10:39:19 -0700121 // Type parsing.
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700122 Type *parsePrimitiveType();
Chris Lattnerf7e22732018-06-22 22:03:48 -0700123 Type *parseElementType();
124 VectorType *parseVectorType();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700125 ParseResult parseDimensionListRanked(SmallVectorImpl<int> &dimensions);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700126 Type *parseTensorType();
127 Type *parseMemRefType();
128 Type *parseFunctionType();
129 Type *parseType();
130 ParseResult parseTypeList(SmallVectorImpl<Type*> &elements);
Chris Lattnere79379a2018-06-22 10:39:19 -0700131
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700132 // Identifiers
133 ParseResult parseDimIdList(SmallVectorImpl<StringRef> &dims,
134 SmallVectorImpl<StringRef> &symbols);
135 ParseResult parseSymbolIdList(SmallVectorImpl<StringRef> &dims,
136 SmallVectorImpl<StringRef> &symbols);
137 StringRef parseDimOrSymbolId(SmallVectorImpl<StringRef> &dims,
138 SmallVectorImpl<StringRef> &symbols,
139 bool symbol);
140
MLIR Teamf85a6262018-06-27 11:03:08 -0700141 // Polyhedral structures
142 ParseResult parseAffineMapDef();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700143 AffineMap *parseAffineMapInline(StringRef mapId);
144 AffineExpr *parseAffineExpr(AffineMapParserState &state);
MLIR Teamf85a6262018-06-27 11:03:08 -0700145
Chris Lattner4c95a502018-06-23 16:03:42 -0700146 // Functions.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700147 ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
Chris Lattnere79379a2018-06-22 10:39:19 -0700148 ParseResult parseExtFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700149 ParseResult parseCFGFunc();
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700150 ParseResult parseMLFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700151 ParseResult parseBasicBlock(CFGFunctionParserState &functionState);
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700152 Statement *parseStatement(ParentType parent);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700153
Chris Lattner3a467cc2018-07-01 20:28:00 -0700154 OperationInst *parseCFGOperation(CFGFunctionParserState &functionState);
155 TerminatorInst *parseTerminator(CFGFunctionParserState &functionState);
Chris Lattnered65a732018-06-28 20:45:33 -0700156
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700157 ForStmt *parseForStmt(ParentType parent);
158 IfStmt *parseIfStmt(ParentType parent);
159 ParseResult parseNestedStatements(NodeStmt *parent);
Chris Lattnere79379a2018-06-22 10:39:19 -0700160};
161} // end anonymous namespace
162
163//===----------------------------------------------------------------------===//
164// Helper methods.
165//===----------------------------------------------------------------------===//
166
Chris Lattner4c95a502018-06-23 16:03:42 -0700167ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700168 // If we hit a parse error in response to a lexer error, then the lexer
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700169 // already reported the error.
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700170 if (curToken.is(Token::error))
171 return ParseFailure;
172
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700173 errorReporter(
174 lex.getSourceMgr().GetMessage(loc, SourceMgr::DK_Error, message));
Chris Lattnere79379a2018-06-22 10:39:19 -0700175 return ParseFailure;
176}
177
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700178/// Parse a comma-separated list of elements, terminated with an arbitrary
179/// token. This allows empty lists if allowEmptyList is true.
180///
181/// abstract-list ::= rightToken // if allowEmptyList == true
182/// abstract-list ::= element (',' element)* rightToken
183///
184ParseResult Parser::
Chris Lattner8da0c282018-06-29 11:15:56 -0700185parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700186 const std::function<ParseResult()> &parseElement,
187 bool allowEmptyList) {
188 // Handle the empty case.
189 if (curToken.is(rightToken)) {
190 if (!allowEmptyList)
191 return emitError("expected list element");
192 consumeToken(rightToken);
193 return ParseSuccess;
194 }
195
196 // Non-empty case starts with an element.
197 if (parseElement())
198 return ParseFailure;
199
200 // Otherwise we have a list of comma separated elements.
201 while (consumeIf(Token::comma)) {
202 if (parseElement())
203 return ParseFailure;
204 }
205
206 // Consume the end character.
207 if (!consumeIf(rightToken))
Chris Lattner8da0c282018-06-29 11:15:56 -0700208 return emitError("expected ',' or '" + Token::getTokenSpelling(rightToken) +
209 "'");
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700210
211 return ParseSuccess;
212}
Chris Lattnere79379a2018-06-22 10:39:19 -0700213
214//===----------------------------------------------------------------------===//
215// Type Parsing
216//===----------------------------------------------------------------------===//
217
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700218/// Parse the low-level fixed dtypes in the system.
219///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700220/// primitive-type ::= `f16` | `bf16` | `f32` | `f64`
221/// primitive-type ::= integer-type
222/// primitive-type ::= `affineint`
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700223///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700224Type *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700225 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700226 default:
227 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700228 case Token::kw_bf16:
229 consumeToken(Token::kw_bf16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700230 return Type::getBF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700231 case Token::kw_f16:
232 consumeToken(Token::kw_f16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700233 return Type::getF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700234 case Token::kw_f32:
235 consumeToken(Token::kw_f32);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700236 return Type::getF32(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700237 case Token::kw_f64:
238 consumeToken(Token::kw_f64);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700239 return Type::getF64(context);
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700240 case Token::kw_affineint:
241 consumeToken(Token::kw_affineint);
242 return Type::getAffineInt(context);
243 case Token::inttype: {
244 auto width = curToken.getIntTypeBitwidth();
245 if (!width.hasValue())
246 return (emitError("invalid integer width"), nullptr);
247 consumeToken(Token::inttype);
248 return Type::getInt(width.getValue(), context);
249 }
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700250 }
251}
252
253/// Parse the element type of a tensor or memref type.
254///
255/// element-type ::= primitive-type | vector-type
256///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700257Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700258 if (curToken.is(Token::kw_vector))
259 return parseVectorType();
260
261 return parsePrimitiveType();
262}
263
264/// Parse a vector type.
265///
266/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
267/// const-dimension-list ::= (integer-literal `x`)+
268///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700269VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700270 consumeToken(Token::kw_vector);
271
272 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700273 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700274
275 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700276 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700277
278 SmallVector<unsigned, 4> dimensions;
279 while (curToken.is(Token::integer)) {
280 // Make sure this integer value is in bound and valid.
281 auto dimension = curToken.getUnsignedIntegerValue();
282 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700283 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700284 dimensions.push_back(dimension.getValue());
285
286 consumeToken(Token::integer);
287
288 // Make sure we have an 'x' or something like 'xbf32'.
289 if (curToken.isNot(Token::bare_identifier) ||
290 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700291 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700292
293 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
294 if (curToken.getSpelling().size() != 1)
295 lex.resetPointer(curToken.getSpelling().data()+1);
296
297 // Consume the 'x'.
298 consumeToken(Token::bare_identifier);
299 }
300
301 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700302 auto *elementType = parsePrimitiveType();
303 if (!elementType)
304 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700305
306 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700307 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700308
Chris Lattnerf7e22732018-06-22 22:03:48 -0700309 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700310}
311
312/// Parse a dimension list of a tensor or memref type. This populates the
313/// dimension list, returning -1 for the '?' dimensions.
314///
315/// dimension-list-ranked ::= (dimension `x`)*
316/// dimension ::= `?` | integer-literal
317///
318ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
319 while (curToken.isAny(Token::integer, Token::question)) {
320 if (consumeIf(Token::question)) {
321 dimensions.push_back(-1);
322 } else {
323 // Make sure this integer value is in bound and valid.
324 auto dimension = curToken.getUnsignedIntegerValue();
325 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
326 return emitError("invalid dimension");
327 dimensions.push_back((int)dimension.getValue());
328 consumeToken(Token::integer);
329 }
330
331 // Make sure we have an 'x' or something like 'xbf32'.
332 if (curToken.isNot(Token::bare_identifier) ||
333 curToken.getSpelling()[0] != 'x')
334 return emitError("expected 'x' in dimension list");
335
336 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
337 if (curToken.getSpelling().size() != 1)
338 lex.resetPointer(curToken.getSpelling().data()+1);
339
340 // Consume the 'x'.
341 consumeToken(Token::bare_identifier);
342 }
343
344 return ParseSuccess;
345}
346
347/// Parse a tensor type.
348///
349/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
350/// dimension-list ::= dimension-list-ranked | `??`
351///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700352Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700353 consumeToken(Token::kw_tensor);
354
355 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700356 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700357
358 bool isUnranked;
359 SmallVector<int, 4> dimensions;
360
361 if (consumeIf(Token::questionquestion)) {
362 isUnranked = true;
363 } else {
364 isUnranked = false;
365 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700366 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700367 }
368
369 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700370 auto elementType = parseElementType();
371 if (!elementType)
372 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700373
374 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700375 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700376
MLIR Team355ec862018-06-23 18:09:09 -0700377 if (isUnranked)
378 return UnrankedTensorType::get(elementType);
379 return RankedTensorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700380}
381
382/// Parse a memref type.
383///
384/// memref-type ::= `memref` `<` dimension-list-ranked element-type
385/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
386///
387/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
388/// memory-space ::= integer-literal /* | TODO: address-space-id */
389///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700390Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700391 consumeToken(Token::kw_memref);
392
393 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700394 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700395
396 SmallVector<int, 4> dimensions;
397 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700398 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700399
400 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700401 auto elementType = parseElementType();
402 if (!elementType)
403 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700404
405 // TODO: Parse semi-affine-map-composition.
406 // TODO: Parse memory-space.
407
408 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700409 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700410
Chris Lattnerf7e22732018-06-22 22:03:48 -0700411 // FIXME: Add an IR representation for memref types.
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700412 return Type::getInt(1, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700413}
414
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700415/// Parse a function type.
416///
417/// function-type ::= type-list-parens `->` type-list
418///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700419Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700420 assert(curToken.is(Token::l_paren));
421
Chris Lattnerf7e22732018-06-22 22:03:48 -0700422 SmallVector<Type*, 4> arguments;
423 if (parseTypeList(arguments))
424 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700425
426 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700427 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700428
Chris Lattnerf7e22732018-06-22 22:03:48 -0700429 SmallVector<Type*, 4> results;
430 if (parseTypeList(results))
431 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700432
Chris Lattnerf7e22732018-06-22 22:03:48 -0700433 return FunctionType::get(arguments, results, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700434}
435
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700436/// Parse an arbitrary type.
437///
438/// type ::= primitive-type
439/// | vector-type
440/// | tensor-type
441/// | memref-type
442/// | function-type
443/// element-type ::= primitive-type | vector-type
444///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700445Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700446 switch (curToken.getKind()) {
447 case Token::kw_memref: return parseMemRefType();
448 case Token::kw_tensor: return parseTensorType();
449 case Token::kw_vector: return parseVectorType();
450 case Token::l_paren: return parseFunctionType();
451 default:
452 return parsePrimitiveType();
453 }
454}
455
456/// Parse a "type list", which is a singular type, or a parenthesized list of
457/// types.
458///
459/// type-list ::= type-list-parens | type
460/// type-list-parens ::= `(` `)`
461/// | `(` type (`,` type)* `)`
462///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700463ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
464 auto parseElt = [&]() -> ParseResult {
465 auto elt = parseType();
466 elements.push_back(elt);
467 return elt ? ParseSuccess : ParseFailure;
468 };
469
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700470 // If there is no parens, then it must be a singular type.
471 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700472 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700473
Chris Lattnerf7e22732018-06-22 22:03:48 -0700474 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700475 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700476
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700477 return ParseSuccess;
478}
479
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700480namespace {
481/// This class represents the transient parser state while parsing an affine
482/// expression.
483class AffineMapParserState {
484 public:
485 explicit AffineMapParserState(ArrayRef<StringRef> dims,
486 ArrayRef<StringRef> symbols) :
487 dims_(dims), symbols_(symbols) {}
488
489 unsigned dimCount() const { return dims_.size(); }
490 unsigned symbolCount() const { return symbols_.size(); }
491
492 // Stack operations for affine expression parsing
493 // TODO(bondhugula): all of this will be improved/made more principled
494 void pushAffineExpr(AffineExpr *expr) { exprStack.push(expr); }
495 AffineExpr *popAffineExpr() {
496 auto *t = exprStack.top();
497 exprStack.pop();
498 return t;
499 }
500 AffineExpr *topAffineExpr() { return exprStack.top(); }
501
502 ArrayRef<StringRef> getDims() const { return dims_; }
503 ArrayRef<StringRef> getSymbols() const { return symbols_; }
504
505 private:
506 const ArrayRef<StringRef> dims_;
507 const ArrayRef<StringRef> symbols_;
508
509 // TEMP: stack to hold affine expressions
510 std::stack<AffineExpr *> exprStack;
511};
512} // end anonymous namespace
513
Chris Lattner4c95a502018-06-23 16:03:42 -0700514//===----------------------------------------------------------------------===//
MLIR Teamf85a6262018-06-27 11:03:08 -0700515// Polyhedral structures.
516//===----------------------------------------------------------------------===//
517
518/// Affine map declaration.
519///
520/// affine-map-def ::= affine-map-id `=` affine-map-inline
MLIR Teamf85a6262018-06-27 11:03:08 -0700521///
522ParseResult Parser::parseAffineMapDef() {
Chris Lattner8da0c282018-06-29 11:15:56 -0700523 assert(curToken.is(Token::affine_map_identifier));
MLIR Teamf85a6262018-06-27 11:03:08 -0700524
525 StringRef affineMapId = curToken.getSpelling().drop_front();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700526 consumeToken(Token::affine_map_identifier);
527
MLIR Teamf85a6262018-06-27 11:03:08 -0700528 // Check that 'affineMapId' is unique.
529 // TODO(andydavis) Add a unit test for this case.
530 if (affineMaps.count(affineMapId) > 0)
Chris Lattnered65a732018-06-28 20:45:33 -0700531 return emitError("redefinition of affine map id '" + affineMapId + "'");
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700532 // Parse the '='
533 if (!consumeIf(Token::equal))
534 return emitError("expected '=' in affine map outlined definition");
MLIR Teamf85a6262018-06-27 11:03:08 -0700535
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700536 auto *affineMap = parseAffineMapInline(affineMapId);
537 affineMaps[affineMapId].reset(affineMap);
538 if (!affineMap) return ParseFailure;
MLIR Teamf85a6262018-06-27 11:03:08 -0700539
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700540 module->affineMapList.push_back(affineMap);
541 return affineMap ? ParseSuccess : ParseFailure;
542}
543
544///
545/// Parse a multi-dimensional affine expression
546/// affine-expr ::= `(` affine-expr `)`
547/// | affine-expr `+` affine-expr
548/// | affine-expr `-` affine-expr
549/// | `-`? integer-literal `*` affine-expr
550/// | `ceildiv` `(` affine-expr `,` integer-literal `)`
551/// | `floordiv` `(` affine-expr `,` integer-literal `)`
552/// | affine-expr `mod` integer-literal
553/// | bare-id
554/// | `-`? integer-literal
555/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
556///
557/// Use 'state' to check if valid identifiers appear.
558///
559AffineExpr *Parser::parseAffineExpr(AffineMapParserState &state) {
560 // TODO(bondhugula): complete support for this
561 // The code below is all placeholder / it is wrong / not complete
562 // Operator precedence not considered; pure left to right associativity
563 if (curToken.is(Token::comma)) {
564 emitError("expecting affine expression");
565 return nullptr;
566 }
567
568 while (curToken.isNot(Token::comma, Token::r_paren,
569 Token::eof, Token::error)) {
570 switch (curToken.getKind()) {
571 case Token::bare_identifier: {
572 // TODO(bondhugula): look up state to see if it's a symbol or dim_id and
573 // get its position
574 AffineExpr *expr = AffineDimExpr::get(0, context);
575 state.pushAffineExpr(expr);
576 consumeToken(Token::bare_identifier);
577 break;
578 }
579 case Token::plus: {
580 consumeToken(Token::plus);
581 if (state.topAffineExpr()) {
582 auto lChild = state.popAffineExpr();
583 auto rChild = parseAffineExpr(state);
584 if (rChild) {
585 auto binaryOpExpr = AffineAddExpr::get(lChild, rChild, context);
586 state.popAffineExpr();
587 state.pushAffineExpr(binaryOpExpr);
588 } else {
589 emitError("right operand of + missing");
590 }
591 } else {
592 emitError("left operand of + missing");
593 }
594 break;
595 }
596 case Token::integer: {
597 AffineExpr *expr = AffineConstantExpr::get(
598 curToken.getUnsignedIntegerValue().getValue(), context);
599 state.pushAffineExpr(expr);
600 consumeToken(Token::integer);
601 break;
602 }
603 case Token::l_paren: {
604 consumeToken(Token::l_paren);
605 break;
606 }
607 case Token::r_paren: {
608 consumeToken(Token::r_paren);
609 break;
610 }
611 default: {
612 emitError("affine map expr parse impl incomplete/unexpected token");
613 return nullptr;
614 }
615 }
616 }
617 if (!state.topAffineExpr()) {
618 // An error will be emitted by parse comma separated list on an empty list
619 return nullptr;
620 }
621 return state.topAffineExpr();
622}
623
624// Return empty string if no bare id was found
625StringRef Parser::parseDimOrSymbolId(SmallVectorImpl<StringRef> &dims,
626 SmallVectorImpl<StringRef> &symbols,
627 bool symbol = false) {
628 if (curToken.isNot(Token::bare_identifier)) {
629 emitError("expected bare identifier");
630 return StringRef();
631 }
632 // TODO(bondhugula): check whether the id already exists in either
633 // state.symbols or state.dims; report error if it does; otherwise create a
634 // new one.
635 StringRef ref = curToken.getSpelling();
636 consumeToken(Token::bare_identifier);
637 return ref;
638}
639
640ParseResult Parser::parseSymbolIdList(SmallVectorImpl<StringRef> &dims,
641 SmallVectorImpl<StringRef> &symbols) {
642 if (!consumeIf(Token::l_bracket)) return emitError("expected '['");
643
644 auto parseElt = [&]() -> ParseResult {
645 auto elt = parseDimOrSymbolId(dims, symbols, true);
646 // FIXME(bondhugula): assuming dim arg for now
647 if (!elt.empty()) {
648 symbols.push_back(elt);
649 return ParseSuccess;
650 }
651 return ParseFailure;
652 };
653 return parseCommaSeparatedList(Token::r_bracket, parseElt);
654}
655
656// TODO(andy,bondhugula)
657ParseResult Parser::parseDimIdList(SmallVectorImpl<StringRef> &dims,
658 SmallVectorImpl<StringRef> &symbols) {
659 if (!consumeIf(Token::l_paren))
660 return emitError("expected '(' at start of dimensional identifiers list");
661
662 auto parseElt = [&]() -> ParseResult {
663 auto elt = parseDimOrSymbolId(dims, symbols, false);
664 if (!elt.empty()) {
665 dims.push_back(elt);
666 return ParseSuccess;
667 }
668 return ParseFailure;
669 };
670
671 return parseCommaSeparatedList(Token::r_paren, parseElt);
672}
673
674/// Affine map definition.
675///
676/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
677/// ( `size` `(` dim-size (`,` dim-size)* `)` )?
678/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
679///
680AffineMap *Parser::parseAffineMapInline(StringRef mapId) {
681 SmallVector<StringRef, 4> dims;
682 SmallVector<StringRef, 4> symbols;
683
684 // List of dimensional identifiers.
685 if (parseDimIdList(dims, symbols)) return nullptr;
686
687 // Symbols are optional.
688 if (curToken.is(Token::l_bracket)) {
689 if (parseSymbolIdList(dims, symbols)) return nullptr;
690 }
691 if (!consumeIf(Token::arrow)) {
692 emitError("expected '->' or '['");
693 return nullptr;
694 }
695 if (!consumeIf(Token::l_paren)) {
696 emitError("expected '(' at start of affine map range");
697 return nullptr;
698 }
699
700 AffineMapParserState affState(dims, symbols);
701
702 SmallVector<AffineExpr *, 4> exprs;
703 auto parseElt = [&]() -> ParseResult {
704 auto elt = parseAffineExpr(affState);
705 ParseResult res = elt ? ParseSuccess : ParseFailure;
706 exprs.push_back(elt);
707 return res;
708 };
709
710 // Parse a multi-dimensional affine expression (a comma-separated list of 1-d
711 // affine expressions)
712 if (parseCommaSeparatedList(Token::r_paren, parseElt, false)) return nullptr;
713
714 // Parsed a valid affine map
715 auto *affineMap =
716 AffineMap::get(affState.dimCount(), affState.symbolCount(), exprs,
717 context);
718
719 return affineMap;
MLIR Teamf85a6262018-06-27 11:03:08 -0700720}
721
722//===----------------------------------------------------------------------===//
Chris Lattner4c95a502018-06-23 16:03:42 -0700723// Functions
724//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -0700725
Chris Lattnere79379a2018-06-22 10:39:19 -0700726
727/// Parse a function signature, starting with a name and including the parameter
728/// list.
729///
730/// argument-list ::= type (`,` type)* | /*empty*/
731/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
732///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700733ParseResult Parser::parseFunctionSignature(StringRef &name,
734 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700735 if (curToken.isNot(Token::at_identifier))
736 return emitError("expected a function identifier like '@foo'");
737
738 name = curToken.getSpelling().drop_front();
739 consumeToken(Token::at_identifier);
740
741 if (curToken.isNot(Token::l_paren))
742 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -0700743
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700744 SmallVector<Type*, 4> arguments;
745 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700746 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -0700747
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700748 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700749 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700750 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700751 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700752 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700753 }
Chris Lattnerf7e22732018-06-22 22:03:48 -0700754 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -0700755 return ParseSuccess;
756}
757
Chris Lattnere79379a2018-06-22 10:39:19 -0700758/// External function declarations.
759///
760/// ext-func ::= `extfunc` function-signature
761///
762ParseResult Parser::parseExtFunc() {
763 consumeToken(Token::kw_extfunc);
764
765 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700766 FunctionType *type = nullptr;
767 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -0700768 return ParseFailure;
769
770
771 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -0700772 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -0700773 return ParseSuccess;
774}
775
776
Chris Lattner4c95a502018-06-23 16:03:42 -0700777namespace {
778/// This class represents the transient parser state for the internals of a
779/// function as we are parsing it, e.g. the names for basic blocks. It handles
780/// forward references.
781class CFGFunctionParserState {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700782 public:
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700783 CFGFunction *function;
784 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
785
Chris Lattner4c95a502018-06-23 16:03:42 -0700786 CFGFunctionParserState(CFGFunction *function) : function(function) {}
787
788 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700789 /// already exist. The location specified is the point of use, which allows
790 /// us to diagnose references to blocks that are not defined precisely.
791 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
792 auto &blockAndLoc = blocksByName[name];
793 if (!blockAndLoc.first) {
Chris Lattner3a467cc2018-07-01 20:28:00 -0700794 blockAndLoc.first = new BasicBlock();
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700795 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -0700796 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700797 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -0700798 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700799};
800} // end anonymous namespace
801
802
803/// CFG function declarations.
804///
805/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
806///
807ParseResult Parser::parseCFGFunc() {
808 consumeToken(Token::kw_cfgfunc);
809
810 StringRef name;
811 FunctionType *type = nullptr;
812 if (parseFunctionSignature(name, type))
813 return ParseFailure;
814
815 if (!consumeIf(Token::l_brace))
816 return emitError("expected '{' in CFG function");
817
818 // Okay, the CFG function signature was parsed correctly, create the function.
819 auto function = new CFGFunction(name, type);
820
821 // Make sure we have at least one block.
822 if (curToken.is(Token::r_brace))
823 return emitError("CFG functions must have at least one basic block");
824
825 CFGFunctionParserState functionState(function);
826
827 // Parse the list of blocks.
828 while (!consumeIf(Token::r_brace))
829 if (parseBasicBlock(functionState))
830 return ParseFailure;
831
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700832 // Verify that all referenced blocks were defined. Iteration over a
833 // StringMap isn't determinstic, but this is good enough for our purposes.
834 for (auto &elt : functionState.blocksByName) {
835 auto *bb = elt.second.first;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700836 if (!bb->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700837 return emitError(elt.second.second,
838 "reference to an undefined basic block '" +
839 elt.first() + "'");
840 }
841
Chris Lattner4c95a502018-06-23 16:03:42 -0700842 module->functionList.push_back(function);
843 return ParseSuccess;
844}
845
846/// Basic block declaration.
847///
848/// basic-block ::= bb-label instruction* terminator-stmt
849/// bb-label ::= bb-id bb-arg-list? `:`
850/// bb-id ::= bare-id
851/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
852///
853ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
854 SMLoc nameLoc = curToken.getLoc();
855 auto name = curToken.getSpelling();
856 if (!consumeIf(Token::bare_identifier))
857 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700858
859 auto block = functionState.getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -0700860
861 // If this block has already been parsed, then this is a redefinition with the
862 // same block name.
Chris Lattner3a467cc2018-07-01 20:28:00 -0700863 if (block->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700864 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
865
Chris Lattner3a467cc2018-07-01 20:28:00 -0700866 // Add the block to the function.
867 functionState.function->push_back(block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700868
869 // TODO: parse bb argument list.
870
871 if (!consumeIf(Token::colon))
872 return emitError("expected ':' after basic block name");
873
Chris Lattnered65a732018-06-28 20:45:33 -0700874 // Parse the list of operations that make up the body of the block.
875 while (curToken.isNot(Token::kw_return, Token::kw_br)) {
Chris Lattner3a467cc2018-07-01 20:28:00 -0700876 auto *inst = parseCFGOperation(functionState);
877 if (!inst)
Chris Lattnered65a732018-06-28 20:45:33 -0700878 return ParseFailure;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700879
880 block->getOperations().push_back(inst);
Chris Lattnered65a732018-06-28 20:45:33 -0700881 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700882
Chris Lattner3a467cc2018-07-01 20:28:00 -0700883 auto *term = parseTerminator(functionState);
884 if (!term)
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700885 return ParseFailure;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700886 block->setTerminator(term);
Chris Lattner4c95a502018-06-23 16:03:42 -0700887
888 return ParseSuccess;
889}
890
891
Chris Lattnered65a732018-06-28 20:45:33 -0700892/// Parse the CFG operation.
893///
894/// TODO(clattner): This is a change from the MLIR spec as written, it is an
895/// experiment that will eliminate "builtin" instructions as a thing.
896///
897/// cfg-operation ::=
898/// (ssa-id `=`)? string '(' ssa-use-list? ')' attribute-dict?
899/// `:` function-type
900///
Chris Lattner3a467cc2018-07-01 20:28:00 -0700901OperationInst *Parser::
902parseCFGOperation(CFGFunctionParserState &functionState) {
Chris Lattnered65a732018-06-28 20:45:33 -0700903
904 // TODO: parse ssa-id.
905
906 if (curToken.isNot(Token::string))
Chris Lattner3a467cc2018-07-01 20:28:00 -0700907 return (emitError("expected operation name in quotes"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -0700908
909 auto name = curToken.getStringValue();
910 if (name.empty())
Chris Lattner3a467cc2018-07-01 20:28:00 -0700911 return (emitError("empty operation name is invalid"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -0700912
913 consumeToken(Token::string);
914
915 if (!consumeIf(Token::l_paren))
Chris Lattner3a467cc2018-07-01 20:28:00 -0700916 return (emitError("expected '(' in operation"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -0700917
918 // TODO: Parse operands.
919 if (!consumeIf(Token::r_paren))
Chris Lattner3a467cc2018-07-01 20:28:00 -0700920 return (emitError("expected '(' in operation"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -0700921
922 auto nameId = Identifier::get(name, context);
Chris Lattner3a467cc2018-07-01 20:28:00 -0700923 return new OperationInst(nameId);
Chris Lattnered65a732018-06-28 20:45:33 -0700924}
925
926
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700927/// Parse the terminator instruction for a basic block.
928///
929/// terminator-stmt ::= `br` bb-id branch-use-list?
930/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
931/// terminator-stmt ::=
932/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
933/// terminator-stmt ::= `return` ssa-use-and-type-list?
934///
Chris Lattner3a467cc2018-07-01 20:28:00 -0700935TerminatorInst *Parser::parseTerminator(CFGFunctionParserState &functionState) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700936 switch (curToken.getKind()) {
937 default:
Chris Lattner3a467cc2018-07-01 20:28:00 -0700938 return (emitError("expected terminator at end of basic block"), nullptr);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700939
940 case Token::kw_return:
941 consumeToken(Token::kw_return);
Chris Lattner3a467cc2018-07-01 20:28:00 -0700942 return new ReturnInst();
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700943
944 case Token::kw_br: {
945 consumeToken(Token::kw_br);
946 auto destBB = functionState.getBlockNamed(curToken.getSpelling(),
947 curToken.getLoc());
948 if (!consumeIf(Token::bare_identifier))
Chris Lattner3a467cc2018-07-01 20:28:00 -0700949 return (emitError("expected basic block name"), nullptr);
950 return new BranchInst(destBB);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700951 }
952 }
953}
954
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700955/// ML function declarations.
956///
957/// ml-func ::= `mlfunc` ml-func-signature `{` ml-stmt* ml-return-stmt `}`
958///
959ParseResult Parser::parseMLFunc() {
960 consumeToken(Token::kw_mlfunc);
961
962 StringRef name;
963 FunctionType *type = nullptr;
964
965 // FIXME: Parse ML function signature (args + types)
966 // by passing pointer to SmallVector<identifier> into parseFunctionSignature
967 if (parseFunctionSignature(name, type))
968 return ParseFailure;
969
970 if (!consumeIf(Token::l_brace))
971 return emitError("expected '{' in ML function");
972
973 // Okay, the ML function signature was parsed correctly, create the function.
974 auto function = new MLFunction(name, type);
975
976 // Make sure we have at least one statement.
977 if (curToken.is(Token::r_brace))
978 return emitError("ML function must end with return statement");
979
980 // Parse the list of instructions.
981 while (!consumeIf(Token::kw_return)) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700982 auto *stmt = parseStatement(function);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700983 if (!stmt)
984 return ParseFailure;
985 function->stmtList.push_back(stmt);
986 }
987
988 // TODO: parse return statement operands
989 if (!consumeIf(Token::r_brace))
990 emitError("expected '}' in ML function");
991
992 module->functionList.push_back(function);
993
994 return ParseSuccess;
995}
996
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700997/// Statement.
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700998///
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -0700999/// ml-stmt ::= instruction | ml-for-stmt | ml-if-stmt
1000/// TODO: fix terminology in MLSpec document. ML functions
1001/// contain operation statements, not instructions.
1002///
1003Statement * Parser::parseStatement(ParentType parent) {
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001004 switch (curToken.getKind()) {
1005 default:
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001006 //TODO: parse OperationStmt
1007 return (emitError("expected statement"), nullptr);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001008
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001009 case Token::kw_for:
1010 return parseForStmt(parent);
1011
1012 case Token::kw_if:
1013 return parseIfStmt(parent);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001014 }
1015}
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001016
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001017/// For statement.
1018///
1019/// ml-for-stmt ::= `for` ssa-id `=` lower-bound `to` upper-bound
1020/// (`step` integer-literal)? `{` ml-stmt* `}`
1021///
1022ForStmt * Parser::parseForStmt(ParentType parent) {
1023 consumeToken(Token::kw_for);
1024
1025 //TODO: parse loop header
1026 ForStmt *stmt = new ForStmt(parent);
1027 if (parseNestedStatements(stmt)) {
1028 delete stmt;
1029 return nullptr;
1030 }
1031 return stmt;
1032}
1033
1034/// If statement.
1035///
1036/// ml-if-head ::= `if` ml-if-cond `{` ml-stmt* `}`
1037/// | ml-if-head `else` `if` ml-if-cond `{` ml-stmt* `}`
1038/// ml-if-stmt ::= ml-if-head
1039/// | ml-if-head `else` `{` ml-stmt* `}`
1040///
1041IfStmt * Parser::parseIfStmt(PointerUnion<MLFunction *, NodeStmt *> parent) {
1042 consumeToken(Token::kw_if);
1043
1044 //TODO: parse condition
1045 IfStmt *stmt = new IfStmt(parent);
1046 if (parseNestedStatements(stmt)) {
1047 delete stmt;
1048 return nullptr;
1049 }
1050
1051 int clauseNum = 0;
1052 while (consumeIf(Token::kw_else)) {
1053 if (consumeIf(Token::kw_if)) {
1054 //TODO: parse condition
1055 }
1056 ElseClause * clause = new ElseClause(stmt, clauseNum);
1057 ++clauseNum;
1058 if (parseNestedStatements(clause)) {
1059 delete clause;
1060 return nullptr;
1061 }
1062 }
1063
1064 return stmt;
1065}
1066
1067///
1068/// Parse `{` ml-stmt* `}`
1069///
1070ParseResult Parser::parseNestedStatements(NodeStmt *parent) {
1071 if (!consumeIf(Token::l_brace))
1072 return emitError("expected '{' before statement list");
1073
1074 if (consumeIf(Token::r_brace)) {
1075 // TODO: parse OperationStmt
1076 return ParseSuccess;
1077 }
1078
1079 while (!consumeIf(Token::r_brace)) {
1080 auto *stmt = parseStatement(parent);
1081 if (!stmt)
1082 return ParseFailure;
1083 parent->children.push_back(stmt);
1084 }
1085
1086 return ParseSuccess;
1087}
1088
Chris Lattner4c95a502018-06-23 16:03:42 -07001089//===----------------------------------------------------------------------===//
1090// Top-level entity parsing.
1091//===----------------------------------------------------------------------===//
1092
Chris Lattnere79379a2018-06-22 10:39:19 -07001093/// This is the top-level module parser.
1094Module *Parser::parseModule() {
1095 while (1) {
1096 switch (curToken.getKind()) {
1097 default:
1098 emitError("expected a top level entity");
1099 return nullptr;
1100
1101 // If we got to the end of the file, then we're done.
1102 case Token::eof:
1103 return module.release();
1104
1105 // If we got an error token, then the lexer already emitted an error, just
1106 // stop. Someday we could introduce error recovery if there was demand for
1107 // it.
1108 case Token::error:
1109 return nullptr;
1110
1111 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -07001112 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -07001113 break;
1114
Chris Lattner4c95a502018-06-23 16:03:42 -07001115 case Token::kw_cfgfunc:
1116 if (parseCFGFunc()) return nullptr;
1117 break;
Chris Lattner8da0c282018-06-29 11:15:56 -07001118 case Token::affine_map_identifier:
MLIR Teamf85a6262018-06-27 11:03:08 -07001119 if (parseAffineMapDef()) return nullptr;
1120 break;
Chris Lattner4c95a502018-06-23 16:03:42 -07001121
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001122 case Token::kw_mlfunc:
1123 if (parseMLFunc()) return nullptr;
1124 break;
1125
1126 // TODO: affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -07001127 }
1128 }
1129}
1130
1131//===----------------------------------------------------------------------===//
1132
Jacques Pienaar7b829702018-07-03 13:24:09 -07001133void mlir::defaultErrorReporter(const llvm::SMDiagnostic &error) {
1134 const auto &sourceMgr = *error.getSourceMgr();
1135 sourceMgr.PrintMessage(error.getLoc(), error.getKind(), error.getMessage());
1136}
1137
Chris Lattnere79379a2018-06-22 10:39:19 -07001138/// This parses the file specified by the indicated SourceMgr and returns an
1139/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Jacques Pienaar9c411be2018-06-24 19:17:35 -07001140Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context,
Jacques Pienaar7b829702018-07-03 13:24:09 -07001141 SMDiagnosticHandlerTy errorReporter) {
1142 return Parser(sourceMgr, context,
1143 errorReporter ? std::move(errorReporter) : defaultErrorReporter)
1144 .parseModule();
Chris Lattnere79379a2018-06-22 10:39:19 -07001145}