blob: 08157e5fd7c84249572a510372e460da0cdd33ae [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 Shpeismanc96b5872018-06-28 17:02:32 -0700152 MLStatement *parseMLStatement(MLFunction *currentFunction);
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
Chris Lattnere79379a2018-06-22 10:39:19 -0700157};
158} // end anonymous namespace
159
160//===----------------------------------------------------------------------===//
161// Helper methods.
162//===----------------------------------------------------------------------===//
163
Chris Lattner4c95a502018-06-23 16:03:42 -0700164ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700165 // If we hit a parse error in response to a lexer error, then the lexer
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700166 // already reported the error.
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700167 if (curToken.is(Token::error))
168 return ParseFailure;
169
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700170 errorReporter(
171 lex.getSourceMgr().GetMessage(loc, SourceMgr::DK_Error, message));
Chris Lattnere79379a2018-06-22 10:39:19 -0700172 return ParseFailure;
173}
174
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700175/// Parse a comma-separated list of elements, terminated with an arbitrary
176/// token. This allows empty lists if allowEmptyList is true.
177///
178/// abstract-list ::= rightToken // if allowEmptyList == true
179/// abstract-list ::= element (',' element)* rightToken
180///
181ParseResult Parser::
Chris Lattner8da0c282018-06-29 11:15:56 -0700182parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700183 const std::function<ParseResult()> &parseElement,
184 bool allowEmptyList) {
185 // Handle the empty case.
186 if (curToken.is(rightToken)) {
187 if (!allowEmptyList)
188 return emitError("expected list element");
189 consumeToken(rightToken);
190 return ParseSuccess;
191 }
192
193 // Non-empty case starts with an element.
194 if (parseElement())
195 return ParseFailure;
196
197 // Otherwise we have a list of comma separated elements.
198 while (consumeIf(Token::comma)) {
199 if (parseElement())
200 return ParseFailure;
201 }
202
203 // Consume the end character.
204 if (!consumeIf(rightToken))
Chris Lattner8da0c282018-06-29 11:15:56 -0700205 return emitError("expected ',' or '" + Token::getTokenSpelling(rightToken) +
206 "'");
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700207
208 return ParseSuccess;
209}
Chris Lattnere79379a2018-06-22 10:39:19 -0700210
211//===----------------------------------------------------------------------===//
212// Type Parsing
213//===----------------------------------------------------------------------===//
214
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700215/// Parse the low-level fixed dtypes in the system.
216///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700217/// primitive-type ::= `f16` | `bf16` | `f32` | `f64`
218/// primitive-type ::= integer-type
219/// primitive-type ::= `affineint`
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700220///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700221Type *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700222 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700223 default:
224 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700225 case Token::kw_bf16:
226 consumeToken(Token::kw_bf16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700227 return Type::getBF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700228 case Token::kw_f16:
229 consumeToken(Token::kw_f16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700230 return Type::getF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700231 case Token::kw_f32:
232 consumeToken(Token::kw_f32);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700233 return Type::getF32(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700234 case Token::kw_f64:
235 consumeToken(Token::kw_f64);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700236 return Type::getF64(context);
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700237 case Token::kw_affineint:
238 consumeToken(Token::kw_affineint);
239 return Type::getAffineInt(context);
240 case Token::inttype: {
241 auto width = curToken.getIntTypeBitwidth();
242 if (!width.hasValue())
243 return (emitError("invalid integer width"), nullptr);
244 consumeToken(Token::inttype);
245 return Type::getInt(width.getValue(), context);
246 }
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700247 }
248}
249
250/// Parse the element type of a tensor or memref type.
251///
252/// element-type ::= primitive-type | vector-type
253///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700254Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700255 if (curToken.is(Token::kw_vector))
256 return parseVectorType();
257
258 return parsePrimitiveType();
259}
260
261/// Parse a vector type.
262///
263/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
264/// const-dimension-list ::= (integer-literal `x`)+
265///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700266VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700267 consumeToken(Token::kw_vector);
268
269 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700270 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700271
272 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700273 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700274
275 SmallVector<unsigned, 4> dimensions;
276 while (curToken.is(Token::integer)) {
277 // Make sure this integer value is in bound and valid.
278 auto dimension = curToken.getUnsignedIntegerValue();
279 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700280 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700281 dimensions.push_back(dimension.getValue());
282
283 consumeToken(Token::integer);
284
285 // Make sure we have an 'x' or something like 'xbf32'.
286 if (curToken.isNot(Token::bare_identifier) ||
287 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700288 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700289
290 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
291 if (curToken.getSpelling().size() != 1)
292 lex.resetPointer(curToken.getSpelling().data()+1);
293
294 // Consume the 'x'.
295 consumeToken(Token::bare_identifier);
296 }
297
298 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700299 auto *elementType = parsePrimitiveType();
300 if (!elementType)
301 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700302
303 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700304 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700305
Chris Lattnerf7e22732018-06-22 22:03:48 -0700306 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700307}
308
309/// Parse a dimension list of a tensor or memref type. This populates the
310/// dimension list, returning -1 for the '?' dimensions.
311///
312/// dimension-list-ranked ::= (dimension `x`)*
313/// dimension ::= `?` | integer-literal
314///
315ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
316 while (curToken.isAny(Token::integer, Token::question)) {
317 if (consumeIf(Token::question)) {
318 dimensions.push_back(-1);
319 } else {
320 // Make sure this integer value is in bound and valid.
321 auto dimension = curToken.getUnsignedIntegerValue();
322 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
323 return emitError("invalid dimension");
324 dimensions.push_back((int)dimension.getValue());
325 consumeToken(Token::integer);
326 }
327
328 // Make sure we have an 'x' or something like 'xbf32'.
329 if (curToken.isNot(Token::bare_identifier) ||
330 curToken.getSpelling()[0] != 'x')
331 return emitError("expected 'x' in dimension list");
332
333 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
334 if (curToken.getSpelling().size() != 1)
335 lex.resetPointer(curToken.getSpelling().data()+1);
336
337 // Consume the 'x'.
338 consumeToken(Token::bare_identifier);
339 }
340
341 return ParseSuccess;
342}
343
344/// Parse a tensor type.
345///
346/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
347/// dimension-list ::= dimension-list-ranked | `??`
348///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700349Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700350 consumeToken(Token::kw_tensor);
351
352 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700353 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700354
355 bool isUnranked;
356 SmallVector<int, 4> dimensions;
357
358 if (consumeIf(Token::questionquestion)) {
359 isUnranked = true;
360 } else {
361 isUnranked = false;
362 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700363 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700364 }
365
366 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700367 auto elementType = parseElementType();
368 if (!elementType)
369 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700370
371 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700372 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700373
MLIR Team355ec862018-06-23 18:09:09 -0700374 if (isUnranked)
375 return UnrankedTensorType::get(elementType);
376 return RankedTensorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700377}
378
379/// Parse a memref type.
380///
381/// memref-type ::= `memref` `<` dimension-list-ranked element-type
382/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
383///
384/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
385/// memory-space ::= integer-literal /* | TODO: address-space-id */
386///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700387Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700388 consumeToken(Token::kw_memref);
389
390 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700391 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700392
393 SmallVector<int, 4> dimensions;
394 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700395 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700396
397 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700398 auto elementType = parseElementType();
399 if (!elementType)
400 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700401
402 // TODO: Parse semi-affine-map-composition.
403 // TODO: Parse memory-space.
404
405 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700406 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700407
Chris Lattnerf7e22732018-06-22 22:03:48 -0700408 // FIXME: Add an IR representation for memref types.
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700409 return Type::getInt(1, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700410}
411
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700412/// Parse a function type.
413///
414/// function-type ::= type-list-parens `->` type-list
415///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700416Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700417 assert(curToken.is(Token::l_paren));
418
Chris Lattnerf7e22732018-06-22 22:03:48 -0700419 SmallVector<Type*, 4> arguments;
420 if (parseTypeList(arguments))
421 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700422
423 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700424 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700425
Chris Lattnerf7e22732018-06-22 22:03:48 -0700426 SmallVector<Type*, 4> results;
427 if (parseTypeList(results))
428 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700429
Chris Lattnerf7e22732018-06-22 22:03:48 -0700430 return FunctionType::get(arguments, results, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700431}
432
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700433/// Parse an arbitrary type.
434///
435/// type ::= primitive-type
436/// | vector-type
437/// | tensor-type
438/// | memref-type
439/// | function-type
440/// element-type ::= primitive-type | vector-type
441///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700442Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700443 switch (curToken.getKind()) {
444 case Token::kw_memref: return parseMemRefType();
445 case Token::kw_tensor: return parseTensorType();
446 case Token::kw_vector: return parseVectorType();
447 case Token::l_paren: return parseFunctionType();
448 default:
449 return parsePrimitiveType();
450 }
451}
452
453/// Parse a "type list", which is a singular type, or a parenthesized list of
454/// types.
455///
456/// type-list ::= type-list-parens | type
457/// type-list-parens ::= `(` `)`
458/// | `(` type (`,` type)* `)`
459///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700460ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
461 auto parseElt = [&]() -> ParseResult {
462 auto elt = parseType();
463 elements.push_back(elt);
464 return elt ? ParseSuccess : ParseFailure;
465 };
466
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700467 // If there is no parens, then it must be a singular type.
468 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700469 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700470
Chris Lattnerf7e22732018-06-22 22:03:48 -0700471 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700472 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700473
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700474 return ParseSuccess;
475}
476
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700477namespace {
478/// This class represents the transient parser state while parsing an affine
479/// expression.
480class AffineMapParserState {
481 public:
482 explicit AffineMapParserState(ArrayRef<StringRef> dims,
483 ArrayRef<StringRef> symbols) :
484 dims_(dims), symbols_(symbols) {}
485
486 unsigned dimCount() const { return dims_.size(); }
487 unsigned symbolCount() const { return symbols_.size(); }
488
489 // Stack operations for affine expression parsing
490 // TODO(bondhugula): all of this will be improved/made more principled
491 void pushAffineExpr(AffineExpr *expr) { exprStack.push(expr); }
492 AffineExpr *popAffineExpr() {
493 auto *t = exprStack.top();
494 exprStack.pop();
495 return t;
496 }
497 AffineExpr *topAffineExpr() { return exprStack.top(); }
498
499 ArrayRef<StringRef> getDims() const { return dims_; }
500 ArrayRef<StringRef> getSymbols() const { return symbols_; }
501
502 private:
503 const ArrayRef<StringRef> dims_;
504 const ArrayRef<StringRef> symbols_;
505
506 // TEMP: stack to hold affine expressions
507 std::stack<AffineExpr *> exprStack;
508};
509} // end anonymous namespace
510
Chris Lattner4c95a502018-06-23 16:03:42 -0700511//===----------------------------------------------------------------------===//
MLIR Teamf85a6262018-06-27 11:03:08 -0700512// Polyhedral structures.
513//===----------------------------------------------------------------------===//
514
515/// Affine map declaration.
516///
517/// affine-map-def ::= affine-map-id `=` affine-map-inline
MLIR Teamf85a6262018-06-27 11:03:08 -0700518///
519ParseResult Parser::parseAffineMapDef() {
Chris Lattner8da0c282018-06-29 11:15:56 -0700520 assert(curToken.is(Token::affine_map_identifier));
MLIR Teamf85a6262018-06-27 11:03:08 -0700521
522 StringRef affineMapId = curToken.getSpelling().drop_front();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700523 consumeToken(Token::affine_map_identifier);
524
MLIR Teamf85a6262018-06-27 11:03:08 -0700525 // Check that 'affineMapId' is unique.
526 // TODO(andydavis) Add a unit test for this case.
527 if (affineMaps.count(affineMapId) > 0)
Chris Lattnered65a732018-06-28 20:45:33 -0700528 return emitError("redefinition of affine map id '" + affineMapId + "'");
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700529 // Parse the '='
530 if (!consumeIf(Token::equal))
531 return emitError("expected '=' in affine map outlined definition");
MLIR Teamf85a6262018-06-27 11:03:08 -0700532
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700533 auto *affineMap = parseAffineMapInline(affineMapId);
534 affineMaps[affineMapId].reset(affineMap);
535 if (!affineMap) return ParseFailure;
MLIR Teamf85a6262018-06-27 11:03:08 -0700536
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700537 module->affineMapList.push_back(affineMap);
538 return affineMap ? ParseSuccess : ParseFailure;
539}
540
541///
542/// Parse a multi-dimensional affine expression
543/// affine-expr ::= `(` affine-expr `)`
544/// | affine-expr `+` affine-expr
545/// | affine-expr `-` affine-expr
546/// | `-`? integer-literal `*` affine-expr
547/// | `ceildiv` `(` affine-expr `,` integer-literal `)`
548/// | `floordiv` `(` affine-expr `,` integer-literal `)`
549/// | affine-expr `mod` integer-literal
550/// | bare-id
551/// | `-`? integer-literal
552/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
553///
554/// Use 'state' to check if valid identifiers appear.
555///
556AffineExpr *Parser::parseAffineExpr(AffineMapParserState &state) {
557 // TODO(bondhugula): complete support for this
558 // The code below is all placeholder / it is wrong / not complete
559 // Operator precedence not considered; pure left to right associativity
560 if (curToken.is(Token::comma)) {
561 emitError("expecting affine expression");
562 return nullptr;
563 }
564
565 while (curToken.isNot(Token::comma, Token::r_paren,
566 Token::eof, Token::error)) {
567 switch (curToken.getKind()) {
568 case Token::bare_identifier: {
569 // TODO(bondhugula): look up state to see if it's a symbol or dim_id and
570 // get its position
571 AffineExpr *expr = AffineDimExpr::get(0, context);
572 state.pushAffineExpr(expr);
573 consumeToken(Token::bare_identifier);
574 break;
575 }
576 case Token::plus: {
577 consumeToken(Token::plus);
578 if (state.topAffineExpr()) {
579 auto lChild = state.popAffineExpr();
580 auto rChild = parseAffineExpr(state);
581 if (rChild) {
582 auto binaryOpExpr = AffineAddExpr::get(lChild, rChild, context);
583 state.popAffineExpr();
584 state.pushAffineExpr(binaryOpExpr);
585 } else {
586 emitError("right operand of + missing");
587 }
588 } else {
589 emitError("left operand of + missing");
590 }
591 break;
592 }
593 case Token::integer: {
594 AffineExpr *expr = AffineConstantExpr::get(
595 curToken.getUnsignedIntegerValue().getValue(), context);
596 state.pushAffineExpr(expr);
597 consumeToken(Token::integer);
598 break;
599 }
600 case Token::l_paren: {
601 consumeToken(Token::l_paren);
602 break;
603 }
604 case Token::r_paren: {
605 consumeToken(Token::r_paren);
606 break;
607 }
608 default: {
609 emitError("affine map expr parse impl incomplete/unexpected token");
610 return nullptr;
611 }
612 }
613 }
614 if (!state.topAffineExpr()) {
615 // An error will be emitted by parse comma separated list on an empty list
616 return nullptr;
617 }
618 return state.topAffineExpr();
619}
620
621// Return empty string if no bare id was found
622StringRef Parser::parseDimOrSymbolId(SmallVectorImpl<StringRef> &dims,
623 SmallVectorImpl<StringRef> &symbols,
624 bool symbol = false) {
625 if (curToken.isNot(Token::bare_identifier)) {
626 emitError("expected bare identifier");
627 return StringRef();
628 }
629 // TODO(bondhugula): check whether the id already exists in either
630 // state.symbols or state.dims; report error if it does; otherwise create a
631 // new one.
632 StringRef ref = curToken.getSpelling();
633 consumeToken(Token::bare_identifier);
634 return ref;
635}
636
637ParseResult Parser::parseSymbolIdList(SmallVectorImpl<StringRef> &dims,
638 SmallVectorImpl<StringRef> &symbols) {
639 if (!consumeIf(Token::l_bracket)) return emitError("expected '['");
640
641 auto parseElt = [&]() -> ParseResult {
642 auto elt = parseDimOrSymbolId(dims, symbols, true);
643 // FIXME(bondhugula): assuming dim arg for now
644 if (!elt.empty()) {
645 symbols.push_back(elt);
646 return ParseSuccess;
647 }
648 return ParseFailure;
649 };
650 return parseCommaSeparatedList(Token::r_bracket, parseElt);
651}
652
653// TODO(andy,bondhugula)
654ParseResult Parser::parseDimIdList(SmallVectorImpl<StringRef> &dims,
655 SmallVectorImpl<StringRef> &symbols) {
656 if (!consumeIf(Token::l_paren))
657 return emitError("expected '(' at start of dimensional identifiers list");
658
659 auto parseElt = [&]() -> ParseResult {
660 auto elt = parseDimOrSymbolId(dims, symbols, false);
661 if (!elt.empty()) {
662 dims.push_back(elt);
663 return ParseSuccess;
664 }
665 return ParseFailure;
666 };
667
668 return parseCommaSeparatedList(Token::r_paren, parseElt);
669}
670
671/// Affine map definition.
672///
673/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
674/// ( `size` `(` dim-size (`,` dim-size)* `)` )?
675/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
676///
677AffineMap *Parser::parseAffineMapInline(StringRef mapId) {
678 SmallVector<StringRef, 4> dims;
679 SmallVector<StringRef, 4> symbols;
680
681 // List of dimensional identifiers.
682 if (parseDimIdList(dims, symbols)) return nullptr;
683
684 // Symbols are optional.
685 if (curToken.is(Token::l_bracket)) {
686 if (parseSymbolIdList(dims, symbols)) return nullptr;
687 }
688 if (!consumeIf(Token::arrow)) {
689 emitError("expected '->' or '['");
690 return nullptr;
691 }
692 if (!consumeIf(Token::l_paren)) {
693 emitError("expected '(' at start of affine map range");
694 return nullptr;
695 }
696
697 AffineMapParserState affState(dims, symbols);
698
699 SmallVector<AffineExpr *, 4> exprs;
700 auto parseElt = [&]() -> ParseResult {
701 auto elt = parseAffineExpr(affState);
702 ParseResult res = elt ? ParseSuccess : ParseFailure;
703 exprs.push_back(elt);
704 return res;
705 };
706
707 // Parse a multi-dimensional affine expression (a comma-separated list of 1-d
708 // affine expressions)
709 if (parseCommaSeparatedList(Token::r_paren, parseElt, false)) return nullptr;
710
711 // Parsed a valid affine map
712 auto *affineMap =
713 AffineMap::get(affState.dimCount(), affState.symbolCount(), exprs,
714 context);
715
716 return affineMap;
MLIR Teamf85a6262018-06-27 11:03:08 -0700717}
718
719//===----------------------------------------------------------------------===//
Chris Lattner4c95a502018-06-23 16:03:42 -0700720// Functions
721//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -0700722
Chris Lattnere79379a2018-06-22 10:39:19 -0700723
724/// Parse a function signature, starting with a name and including the parameter
725/// list.
726///
727/// argument-list ::= type (`,` type)* | /*empty*/
728/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
729///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700730ParseResult Parser::parseFunctionSignature(StringRef &name,
731 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700732 if (curToken.isNot(Token::at_identifier))
733 return emitError("expected a function identifier like '@foo'");
734
735 name = curToken.getSpelling().drop_front();
736 consumeToken(Token::at_identifier);
737
738 if (curToken.isNot(Token::l_paren))
739 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -0700740
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700741 SmallVector<Type*, 4> arguments;
742 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700743 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -0700744
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700745 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700746 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700747 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700748 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700749 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700750 }
Chris Lattnerf7e22732018-06-22 22:03:48 -0700751 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -0700752 return ParseSuccess;
753}
754
Chris Lattnere79379a2018-06-22 10:39:19 -0700755/// External function declarations.
756///
757/// ext-func ::= `extfunc` function-signature
758///
759ParseResult Parser::parseExtFunc() {
760 consumeToken(Token::kw_extfunc);
761
762 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700763 FunctionType *type = nullptr;
764 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -0700765 return ParseFailure;
766
767
768 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -0700769 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -0700770 return ParseSuccess;
771}
772
773
Chris Lattner4c95a502018-06-23 16:03:42 -0700774namespace {
775/// This class represents the transient parser state for the internals of a
776/// function as we are parsing it, e.g. the names for basic blocks. It handles
777/// forward references.
778class CFGFunctionParserState {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700779 public:
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700780 CFGFunction *function;
781 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
782
Chris Lattner4c95a502018-06-23 16:03:42 -0700783 CFGFunctionParserState(CFGFunction *function) : function(function) {}
784
785 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700786 /// already exist. The location specified is the point of use, which allows
787 /// us to diagnose references to blocks that are not defined precisely.
788 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
789 auto &blockAndLoc = blocksByName[name];
790 if (!blockAndLoc.first) {
Chris Lattner3a467cc2018-07-01 20:28:00 -0700791 blockAndLoc.first = new BasicBlock();
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700792 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -0700793 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700794 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -0700795 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700796};
797} // end anonymous namespace
798
799
800/// CFG function declarations.
801///
802/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
803///
804ParseResult Parser::parseCFGFunc() {
805 consumeToken(Token::kw_cfgfunc);
806
807 StringRef name;
808 FunctionType *type = nullptr;
809 if (parseFunctionSignature(name, type))
810 return ParseFailure;
811
812 if (!consumeIf(Token::l_brace))
813 return emitError("expected '{' in CFG function");
814
815 // Okay, the CFG function signature was parsed correctly, create the function.
816 auto function = new CFGFunction(name, type);
817
818 // Make sure we have at least one block.
819 if (curToken.is(Token::r_brace))
820 return emitError("CFG functions must have at least one basic block");
821
822 CFGFunctionParserState functionState(function);
823
824 // Parse the list of blocks.
825 while (!consumeIf(Token::r_brace))
826 if (parseBasicBlock(functionState))
827 return ParseFailure;
828
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700829 // Verify that all referenced blocks were defined. Iteration over a
830 // StringMap isn't determinstic, but this is good enough for our purposes.
831 for (auto &elt : functionState.blocksByName) {
832 auto *bb = elt.second.first;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700833 if (!bb->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700834 return emitError(elt.second.second,
835 "reference to an undefined basic block '" +
836 elt.first() + "'");
837 }
838
Chris Lattner4c95a502018-06-23 16:03:42 -0700839 module->functionList.push_back(function);
840 return ParseSuccess;
841}
842
843/// Basic block declaration.
844///
845/// basic-block ::= bb-label instruction* terminator-stmt
846/// bb-label ::= bb-id bb-arg-list? `:`
847/// bb-id ::= bare-id
848/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
849///
850ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
851 SMLoc nameLoc = curToken.getLoc();
852 auto name = curToken.getSpelling();
853 if (!consumeIf(Token::bare_identifier))
854 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700855
856 auto block = functionState.getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -0700857
858 // If this block has already been parsed, then this is a redefinition with the
859 // same block name.
Chris Lattner3a467cc2018-07-01 20:28:00 -0700860 if (block->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700861 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
862
Chris Lattner3a467cc2018-07-01 20:28:00 -0700863 // Add the block to the function.
864 functionState.function->push_back(block);
Chris Lattner4c95a502018-06-23 16:03:42 -0700865
866 // TODO: parse bb argument list.
867
868 if (!consumeIf(Token::colon))
869 return emitError("expected ':' after basic block name");
870
Chris Lattnered65a732018-06-28 20:45:33 -0700871 // Parse the list of operations that make up the body of the block.
872 while (curToken.isNot(Token::kw_return, Token::kw_br)) {
Chris Lattner3a467cc2018-07-01 20:28:00 -0700873 auto *inst = parseCFGOperation(functionState);
874 if (!inst)
Chris Lattnered65a732018-06-28 20:45:33 -0700875 return ParseFailure;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700876
877 block->getOperations().push_back(inst);
Chris Lattnered65a732018-06-28 20:45:33 -0700878 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700879
Chris Lattner3a467cc2018-07-01 20:28:00 -0700880 auto *term = parseTerminator(functionState);
881 if (!term)
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700882 return ParseFailure;
Chris Lattner3a467cc2018-07-01 20:28:00 -0700883 block->setTerminator(term);
Chris Lattner4c95a502018-06-23 16:03:42 -0700884
885 return ParseSuccess;
886}
887
888
Chris Lattnered65a732018-06-28 20:45:33 -0700889/// Parse the CFG operation.
890///
891/// TODO(clattner): This is a change from the MLIR spec as written, it is an
892/// experiment that will eliminate "builtin" instructions as a thing.
893///
894/// cfg-operation ::=
895/// (ssa-id `=`)? string '(' ssa-use-list? ')' attribute-dict?
896/// `:` function-type
897///
Chris Lattner3a467cc2018-07-01 20:28:00 -0700898OperationInst *Parser::
899parseCFGOperation(CFGFunctionParserState &functionState) {
Chris Lattnered65a732018-06-28 20:45:33 -0700900
901 // TODO: parse ssa-id.
902
903 if (curToken.isNot(Token::string))
Chris Lattner3a467cc2018-07-01 20:28:00 -0700904 return (emitError("expected operation name in quotes"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -0700905
906 auto name = curToken.getStringValue();
907 if (name.empty())
Chris Lattner3a467cc2018-07-01 20:28:00 -0700908 return (emitError("empty operation name is invalid"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -0700909
910 consumeToken(Token::string);
911
912 if (!consumeIf(Token::l_paren))
Chris Lattner3a467cc2018-07-01 20:28:00 -0700913 return (emitError("expected '(' in operation"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -0700914
915 // TODO: Parse operands.
916 if (!consumeIf(Token::r_paren))
Chris Lattner3a467cc2018-07-01 20:28:00 -0700917 return (emitError("expected '(' in operation"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -0700918
919 auto nameId = Identifier::get(name, context);
Chris Lattner3a467cc2018-07-01 20:28:00 -0700920 return new OperationInst(nameId);
Chris Lattnered65a732018-06-28 20:45:33 -0700921}
922
923
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700924/// Parse the terminator instruction for a basic block.
925///
926/// terminator-stmt ::= `br` bb-id branch-use-list?
927/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
928/// terminator-stmt ::=
929/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
930/// terminator-stmt ::= `return` ssa-use-and-type-list?
931///
Chris Lattner3a467cc2018-07-01 20:28:00 -0700932TerminatorInst *Parser::parseTerminator(CFGFunctionParserState &functionState) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700933 switch (curToken.getKind()) {
934 default:
Chris Lattner3a467cc2018-07-01 20:28:00 -0700935 return (emitError("expected terminator at end of basic block"), nullptr);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700936
937 case Token::kw_return:
938 consumeToken(Token::kw_return);
Chris Lattner3a467cc2018-07-01 20:28:00 -0700939 return new ReturnInst();
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700940
941 case Token::kw_br: {
942 consumeToken(Token::kw_br);
943 auto destBB = functionState.getBlockNamed(curToken.getSpelling(),
944 curToken.getLoc());
945 if (!consumeIf(Token::bare_identifier))
Chris Lattner3a467cc2018-07-01 20:28:00 -0700946 return (emitError("expected basic block name"), nullptr);
947 return new BranchInst(destBB);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700948 }
949 }
950}
951
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700952/// ML function declarations.
953///
954/// ml-func ::= `mlfunc` ml-func-signature `{` ml-stmt* ml-return-stmt `}`
955///
956ParseResult Parser::parseMLFunc() {
957 consumeToken(Token::kw_mlfunc);
958
959 StringRef name;
960 FunctionType *type = nullptr;
961
962 // FIXME: Parse ML function signature (args + types)
963 // by passing pointer to SmallVector<identifier> into parseFunctionSignature
964 if (parseFunctionSignature(name, type))
965 return ParseFailure;
966
967 if (!consumeIf(Token::l_brace))
968 return emitError("expected '{' in ML function");
969
970 // Okay, the ML function signature was parsed correctly, create the function.
971 auto function = new MLFunction(name, type);
972
973 // Make sure we have at least one statement.
974 if (curToken.is(Token::r_brace))
975 return emitError("ML function must end with return statement");
976
977 // Parse the list of instructions.
978 while (!consumeIf(Token::kw_return)) {
979 auto *stmt = parseMLStatement(function);
980 if (!stmt)
981 return ParseFailure;
982 function->stmtList.push_back(stmt);
983 }
984
985 // TODO: parse return statement operands
986 if (!consumeIf(Token::r_brace))
987 emitError("expected '}' in ML function");
988
989 module->functionList.push_back(function);
990
991 return ParseSuccess;
992}
993
994/// Parse an MLStatement
995/// TODO
996///
997MLStatement *Parser::parseMLStatement(MLFunction *currentFunction) {
998 switch (curToken.getKind()) {
999 default:
1000 return (emitError("expected ML statement"), nullptr);
1001
1002 // TODO: add parsing of ML statements
1003 }
1004}
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001005
Chris Lattner4c95a502018-06-23 16:03:42 -07001006//===----------------------------------------------------------------------===//
1007// Top-level entity parsing.
1008//===----------------------------------------------------------------------===//
1009
Chris Lattnere79379a2018-06-22 10:39:19 -07001010/// This is the top-level module parser.
1011Module *Parser::parseModule() {
1012 while (1) {
1013 switch (curToken.getKind()) {
1014 default:
1015 emitError("expected a top level entity");
1016 return nullptr;
1017
1018 // If we got to the end of the file, then we're done.
1019 case Token::eof:
1020 return module.release();
1021
1022 // If we got an error token, then the lexer already emitted an error, just
1023 // stop. Someday we could introduce error recovery if there was demand for
1024 // it.
1025 case Token::error:
1026 return nullptr;
1027
1028 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -07001029 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -07001030 break;
1031
Chris Lattner4c95a502018-06-23 16:03:42 -07001032 case Token::kw_cfgfunc:
1033 if (parseCFGFunc()) return nullptr;
1034 break;
Chris Lattner8da0c282018-06-29 11:15:56 -07001035 case Token::affine_map_identifier:
MLIR Teamf85a6262018-06-27 11:03:08 -07001036 if (parseAffineMapDef()) return nullptr;
1037 break;
Chris Lattner4c95a502018-06-23 16:03:42 -07001038
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001039 case Token::kw_mlfunc:
1040 if (parseMLFunc()) return nullptr;
1041 break;
1042
1043 // TODO: affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -07001044 }
1045 }
1046}
1047
1048//===----------------------------------------------------------------------===//
1049
Jacques Pienaar7b829702018-07-03 13:24:09 -07001050void mlir::defaultErrorReporter(const llvm::SMDiagnostic &error) {
1051 const auto &sourceMgr = *error.getSourceMgr();
1052 sourceMgr.PrintMessage(error.getLoc(), error.getKind(), error.getMessage());
1053}
1054
Chris Lattnere79379a2018-06-22 10:39:19 -07001055/// This parses the file specified by the indicated SourceMgr and returns an
1056/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Jacques Pienaar9c411be2018-06-24 19:17:35 -07001057Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context,
Jacques Pienaar7b829702018-07-03 13:24:09 -07001058 SMDiagnosticHandlerTy errorReporter) {
1059 return Parser(sourceMgr, context,
1060 errorReporter ? std::move(errorReporter) : defaultErrorReporter)
1061 .parseModule();
Chris Lattnere79379a2018-06-22 10:39:19 -07001062}