blob: c62ee5d14f630794a143819ce85dc71fad5f0ee4 [file] [log] [blame]
Chris Lattnere79379a2018-06-22 10:39:19 -07001//===- Parser.cpp - MLIR Parser Implementation ----------------------------===//
2//
3// Copyright 2019 The MLIR Authors.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16// =============================================================================
17//
18// This file implements the parser for the MLIR textual form.
19//
20//===----------------------------------------------------------------------===//
21
22#include "mlir/Parser.h"
23#include "Lexer.h"
MLIR Teamf85a6262018-06-27 11:03:08 -070024#include "mlir/IR/AffineMap.h"
Chris Lattnere79379a2018-06-22 10:39:19 -070025#include "mlir/IR/Module.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070026#include "mlir/IR/CFGFunction.h"
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -070027#include "mlir/IR/MLFunction.h"
Chris Lattnerf7e22732018-06-22 22:03:48 -070028#include "mlir/IR/Types.h"
Chris Lattnere79379a2018-06-22 10:39:19 -070029#include "llvm/Support/SourceMgr.h"
30using namespace mlir;
31using llvm::SourceMgr;
Chris Lattner4c95a502018-06-23 16:03:42 -070032using llvm::SMLoc;
Chris Lattnere79379a2018-06-22 10:39:19 -070033
34namespace {
Chris Lattner4c95a502018-06-23 16:03:42 -070035class CFGFunctionParserState;
36
Chris Lattnerf7e22732018-06-22 22:03:48 -070037/// Simple enum to make code read better in cases that would otherwise return a
38/// bool value. Failure is "true" in a boolean context.
Chris Lattnere79379a2018-06-22 10:39:19 -070039enum ParseResult {
40 ParseSuccess,
41 ParseFailure
42};
43
44/// Main parser implementation.
45class Parser {
Chris Lattnered65a732018-06-28 20:45:33 -070046public:
Jacques Pienaar9c411be2018-06-24 19:17:35 -070047 Parser(llvm::SourceMgr &sourceMgr, MLIRContext *context,
48 const SMDiagnosticHandlerTy &errorReporter)
49 : context(context),
50 lex(sourceMgr, errorReporter),
51 curToken(lex.lexToken()),
52 errorReporter(errorReporter) {
Chris Lattnere79379a2018-06-22 10:39:19 -070053 module.reset(new Module());
54 }
55
56 Module *parseModule();
57private:
58 // State.
Chris Lattnerf7e22732018-06-22 22:03:48 -070059 MLIRContext *const context;
60
61 // The lexer for the source file we're parsing.
Chris Lattnere79379a2018-06-22 10:39:19 -070062 Lexer lex;
63
64 // This is the next token that hasn't been consumed yet.
65 Token curToken;
66
Jacques Pienaar9c411be2018-06-24 19:17:35 -070067 // The diagnostic error reporter.
68 const SMDiagnosticHandlerTy &errorReporter;
69
Chris Lattnere79379a2018-06-22 10:39:19 -070070 // This is the result module we are parsing into.
71 std::unique_ptr<Module> module;
72
MLIR Teamf85a6262018-06-27 11:03:08 -070073 // A map from affine map identifier to AffineMap.
74 // TODO(andydavis) Remove use of unique_ptr when AffineMaps are bump pointer
75 // allocated.
76 llvm::StringMap<std::unique_ptr<AffineMap>> affineMaps;
77
Chris Lattnere79379a2018-06-22 10:39:19 -070078private:
79 // Helper methods.
80
81 /// Emit an error and return failure.
Chris Lattner4c95a502018-06-23 16:03:42 -070082 ParseResult emitError(const Twine &message) {
83 return emitError(curToken.getLoc(), message);
84 }
85 ParseResult emitError(SMLoc loc, const Twine &message);
Chris Lattnere79379a2018-06-22 10:39:19 -070086
87 /// Advance the current lexer onto the next token.
88 void consumeToken() {
89 assert(curToken.isNot(Token::eof, Token::error) &&
90 "shouldn't advance past EOF or errors");
91 curToken = lex.lexToken();
92 }
93
94 /// Advance the current lexer onto the next token, asserting what the expected
95 /// current token is. This is preferred to the above method because it leads
96 /// to more self-documenting code with better checking.
Chris Lattner8da0c282018-06-29 11:15:56 -070097 void consumeToken(Token::Kind kind) {
Chris Lattnere79379a2018-06-22 10:39:19 -070098 assert(curToken.is(kind) && "consumed an unexpected token");
99 consumeToken();
100 }
101
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700102 /// If the current token has the specified kind, consume it and return true.
103 /// If not, return false.
Chris Lattner8da0c282018-06-29 11:15:56 -0700104 bool consumeIf(Token::Kind kind) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700105 if (curToken.isNot(kind))
106 return false;
107 consumeToken(kind);
108 return true;
109 }
110
Chris Lattner8da0c282018-06-29 11:15:56 -0700111 ParseResult parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700112 const std::function<ParseResult()> &parseElement,
113 bool allowEmptyList = true);
114
Chris Lattnerf7e22732018-06-22 22:03:48 -0700115 // We have two forms of parsing methods - those that return a non-null
116 // pointer on success, and those that return a ParseResult to indicate whether
117 // they returned a failure. The second class fills in by-reference arguments
118 // as the results of their action.
119
Chris Lattnere79379a2018-06-22 10:39:19 -0700120 // Type parsing.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700121 PrimitiveType *parsePrimitiveType();
122 Type *parseElementType();
123 VectorType *parseVectorType();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700124 ParseResult parseDimensionListRanked(SmallVectorImpl<int> &dimensions);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700125 Type *parseTensorType();
126 Type *parseMemRefType();
127 Type *parseFunctionType();
128 Type *parseType();
129 ParseResult parseTypeList(SmallVectorImpl<Type*> &elements);
Chris Lattnere79379a2018-06-22 10:39:19 -0700130
MLIR Teamf85a6262018-06-27 11:03:08 -0700131 // Polyhedral structures
132 ParseResult parseAffineMapDef();
133
Chris Lattner4c95a502018-06-23 16:03:42 -0700134 // Functions.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700135 ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
Chris Lattnere79379a2018-06-22 10:39:19 -0700136 ParseResult parseExtFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700137 ParseResult parseCFGFunc();
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700138 ParseResult parseMLFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700139 ParseResult parseBasicBlock(CFGFunctionParserState &functionState);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700140 MLStatement *parseMLStatement(MLFunction *currentFunction);
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700141
Chris Lattnered65a732018-06-28 20:45:33 -0700142 ParseResult parseCFGOperation(BasicBlock *currentBB,
143 CFGFunctionParserState &functionState);
144 ParseResult parseTerminator(BasicBlock *currentBB,
145 CFGFunctionParserState &functionState);
146
Chris Lattnere79379a2018-06-22 10:39:19 -0700147};
148} // end anonymous namespace
149
150//===----------------------------------------------------------------------===//
151// Helper methods.
152//===----------------------------------------------------------------------===//
153
Chris Lattner4c95a502018-06-23 16:03:42 -0700154ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700155 // If we hit a parse error in response to a lexer error, then the lexer
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700156 // already reported the error.
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700157 if (curToken.is(Token::error))
158 return ParseFailure;
159
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700160 errorReporter(
161 lex.getSourceMgr().GetMessage(loc, SourceMgr::DK_Error, message));
Chris Lattnere79379a2018-06-22 10:39:19 -0700162 return ParseFailure;
163}
164
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700165/// Parse a comma-separated list of elements, terminated with an arbitrary
166/// token. This allows empty lists if allowEmptyList is true.
167///
168/// abstract-list ::= rightToken // if allowEmptyList == true
169/// abstract-list ::= element (',' element)* rightToken
170///
171ParseResult Parser::
Chris Lattner8da0c282018-06-29 11:15:56 -0700172parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700173 const std::function<ParseResult()> &parseElement,
174 bool allowEmptyList) {
175 // Handle the empty case.
176 if (curToken.is(rightToken)) {
177 if (!allowEmptyList)
178 return emitError("expected list element");
179 consumeToken(rightToken);
180 return ParseSuccess;
181 }
182
183 // Non-empty case starts with an element.
184 if (parseElement())
185 return ParseFailure;
186
187 // Otherwise we have a list of comma separated elements.
188 while (consumeIf(Token::comma)) {
189 if (parseElement())
190 return ParseFailure;
191 }
192
193 // Consume the end character.
194 if (!consumeIf(rightToken))
Chris Lattner8da0c282018-06-29 11:15:56 -0700195 return emitError("expected ',' or '" + Token::getTokenSpelling(rightToken) +
196 "'");
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700197
198 return ParseSuccess;
199}
Chris Lattnere79379a2018-06-22 10:39:19 -0700200
201//===----------------------------------------------------------------------===//
202// Type Parsing
203//===----------------------------------------------------------------------===//
204
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700205/// Parse the low-level fixed dtypes in the system.
206///
207/// primitive-type
208/// ::= `f16` | `bf16` | `f32` | `f64` // Floating point
209/// | `i1` | `i8` | `i16` | `i32` | `i64` // Sized integers
210/// | `int`
211///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700212PrimitiveType *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700213 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700214 default:
215 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700216 case Token::kw_bf16:
217 consumeToken(Token::kw_bf16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700218 return Type::getBF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700219 case Token::kw_f16:
220 consumeToken(Token::kw_f16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700221 return Type::getF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700222 case Token::kw_f32:
223 consumeToken(Token::kw_f32);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700224 return Type::getF32(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700225 case Token::kw_f64:
226 consumeToken(Token::kw_f64);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700227 return Type::getF64(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700228 case Token::kw_i1:
229 consumeToken(Token::kw_i1);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700230 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700231 case Token::kw_i8:
232 consumeToken(Token::kw_i8);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700233 return Type::getI8(context);
234 case Token::kw_i16:
235 consumeToken(Token::kw_i16);
236 return Type::getI16(context);
237 case Token::kw_i32:
238 consumeToken(Token::kw_i32);
239 return Type::getI32(context);
240 case Token::kw_i64:
241 consumeToken(Token::kw_i64);
242 return Type::getI64(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700243 case Token::kw_int:
244 consumeToken(Token::kw_int);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700245 return Type::getInt(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700246 }
247}
248
249/// Parse the element type of a tensor or memref type.
250///
251/// element-type ::= primitive-type | vector-type
252///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700253Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700254 if (curToken.is(Token::kw_vector))
255 return parseVectorType();
256
257 return parsePrimitiveType();
258}
259
260/// Parse a vector type.
261///
262/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
263/// const-dimension-list ::= (integer-literal `x`)+
264///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700265VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700266 consumeToken(Token::kw_vector);
267
268 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700269 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700270
271 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700272 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700273
274 SmallVector<unsigned, 4> dimensions;
275 while (curToken.is(Token::integer)) {
276 // Make sure this integer value is in bound and valid.
277 auto dimension = curToken.getUnsignedIntegerValue();
278 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700279 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700280 dimensions.push_back(dimension.getValue());
281
282 consumeToken(Token::integer);
283
284 // Make sure we have an 'x' or something like 'xbf32'.
285 if (curToken.isNot(Token::bare_identifier) ||
286 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700287 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700288
289 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
290 if (curToken.getSpelling().size() != 1)
291 lex.resetPointer(curToken.getSpelling().data()+1);
292
293 // Consume the 'x'.
294 consumeToken(Token::bare_identifier);
295 }
296
297 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700298 auto *elementType = parsePrimitiveType();
299 if (!elementType)
300 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700301
302 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700303 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700304
Chris Lattnerf7e22732018-06-22 22:03:48 -0700305 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700306}
307
308/// Parse a dimension list of a tensor or memref type. This populates the
309/// dimension list, returning -1 for the '?' dimensions.
310///
311/// dimension-list-ranked ::= (dimension `x`)*
312/// dimension ::= `?` | integer-literal
313///
314ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
315 while (curToken.isAny(Token::integer, Token::question)) {
316 if (consumeIf(Token::question)) {
317 dimensions.push_back(-1);
318 } else {
319 // Make sure this integer value is in bound and valid.
320 auto dimension = curToken.getUnsignedIntegerValue();
321 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
322 return emitError("invalid dimension");
323 dimensions.push_back((int)dimension.getValue());
324 consumeToken(Token::integer);
325 }
326
327 // Make sure we have an 'x' or something like 'xbf32'.
328 if (curToken.isNot(Token::bare_identifier) ||
329 curToken.getSpelling()[0] != 'x')
330 return emitError("expected 'x' in dimension list");
331
332 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
333 if (curToken.getSpelling().size() != 1)
334 lex.resetPointer(curToken.getSpelling().data()+1);
335
336 // Consume the 'x'.
337 consumeToken(Token::bare_identifier);
338 }
339
340 return ParseSuccess;
341}
342
343/// Parse a tensor type.
344///
345/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
346/// dimension-list ::= dimension-list-ranked | `??`
347///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700348Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700349 consumeToken(Token::kw_tensor);
350
351 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700352 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700353
354 bool isUnranked;
355 SmallVector<int, 4> dimensions;
356
357 if (consumeIf(Token::questionquestion)) {
358 isUnranked = true;
359 } else {
360 isUnranked = false;
361 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700362 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700363 }
364
365 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700366 auto elementType = parseElementType();
367 if (!elementType)
368 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700369
370 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700371 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700372
MLIR Team355ec862018-06-23 18:09:09 -0700373 if (isUnranked)
374 return UnrankedTensorType::get(elementType);
375 return RankedTensorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700376}
377
378/// Parse a memref type.
379///
380/// memref-type ::= `memref` `<` dimension-list-ranked element-type
381/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
382///
383/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
384/// memory-space ::= integer-literal /* | TODO: address-space-id */
385///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700386Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700387 consumeToken(Token::kw_memref);
388
389 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700390 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700391
392 SmallVector<int, 4> dimensions;
393 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700394 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700395
396 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700397 auto elementType = parseElementType();
398 if (!elementType)
399 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700400
401 // TODO: Parse semi-affine-map-composition.
402 // TODO: Parse memory-space.
403
404 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700405 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700406
Chris Lattnerf7e22732018-06-22 22:03:48 -0700407 // FIXME: Add an IR representation for memref types.
408 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700409}
410
411
412
413/// Parse a function type.
414///
415/// function-type ::= type-list-parens `->` type-list
416///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700417Type *Parser::parseFunctionType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700418 assert(curToken.is(Token::l_paren));
419
Chris Lattnerf7e22732018-06-22 22:03:48 -0700420 SmallVector<Type*, 4> arguments;
421 if (parseTypeList(arguments))
422 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700423
424 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700425 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700426
Chris Lattnerf7e22732018-06-22 22:03:48 -0700427 SmallVector<Type*, 4> results;
428 if (parseTypeList(results))
429 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700430
Chris Lattnerf7e22732018-06-22 22:03:48 -0700431 return FunctionType::get(arguments, results, context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700432}
433
434
435/// Parse an arbitrary type.
436///
437/// type ::= primitive-type
438/// | vector-type
439/// | tensor-type
440/// | memref-type
441/// | function-type
442/// element-type ::= primitive-type | vector-type
443///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700444Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700445 switch (curToken.getKind()) {
446 case Token::kw_memref: return parseMemRefType();
447 case Token::kw_tensor: return parseTensorType();
448 case Token::kw_vector: return parseVectorType();
449 case Token::l_paren: return parseFunctionType();
450 default:
451 return parsePrimitiveType();
452 }
453}
454
455/// Parse a "type list", which is a singular type, or a parenthesized list of
456/// types.
457///
458/// type-list ::= type-list-parens | type
459/// type-list-parens ::= `(` `)`
460/// | `(` type (`,` type)* `)`
461///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700462ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
463 auto parseElt = [&]() -> ParseResult {
464 auto elt = parseType();
465 elements.push_back(elt);
466 return elt ? ParseSuccess : ParseFailure;
467 };
468
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700469 // If there is no parens, then it must be a singular type.
470 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700471 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700472
Chris Lattnerf7e22732018-06-22 22:03:48 -0700473 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700474 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700475
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700476 return ParseSuccess;
477}
478
Chris Lattner4c95a502018-06-23 16:03:42 -0700479//===----------------------------------------------------------------------===//
MLIR Teamf85a6262018-06-27 11:03:08 -0700480// Polyhedral structures.
481//===----------------------------------------------------------------------===//
482
483/// Affine map declaration.
484///
485/// affine-map-def ::= affine-map-id `=` affine-map-inline
486/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
487/// ( `size` `(` dim-size (`,` dim-size)* `)` )?
488/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
489///
490ParseResult Parser::parseAffineMapDef() {
Chris Lattner8da0c282018-06-29 11:15:56 -0700491 assert(curToken.is(Token::affine_map_identifier));
MLIR Teamf85a6262018-06-27 11:03:08 -0700492
493 StringRef affineMapId = curToken.getSpelling().drop_front();
494 // Check that 'affineMapId' is unique.
495 // TODO(andydavis) Add a unit test for this case.
496 if (affineMaps.count(affineMapId) > 0)
Chris Lattnered65a732018-06-28 20:45:33 -0700497 return emitError("redefinition of affine map id '" + affineMapId + "'");
MLIR Teamf85a6262018-06-27 11:03:08 -0700498
Chris Lattner8da0c282018-06-29 11:15:56 -0700499 consumeToken(Token::affine_map_identifier);
MLIR Teamf85a6262018-06-27 11:03:08 -0700500
501 // TODO(andydavis,bondhugula) Parse affine map definition.
502 affineMaps[affineMapId].reset(new AffineMap(1, 0));
503 return ParseSuccess;
504}
505
506//===----------------------------------------------------------------------===//
Chris Lattner4c95a502018-06-23 16:03:42 -0700507// Functions
508//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -0700509
Chris Lattnere79379a2018-06-22 10:39:19 -0700510
511/// Parse a function signature, starting with a name and including the parameter
512/// list.
513///
514/// argument-list ::= type (`,` type)* | /*empty*/
515/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
516///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700517ParseResult Parser::parseFunctionSignature(StringRef &name,
518 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700519 if (curToken.isNot(Token::at_identifier))
520 return emitError("expected a function identifier like '@foo'");
521
522 name = curToken.getSpelling().drop_front();
523 consumeToken(Token::at_identifier);
524
525 if (curToken.isNot(Token::l_paren))
526 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -0700527
Chris Lattnerf7e22732018-06-22 22:03:48 -0700528 SmallVector<Type*, 4> arguments;
529 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700530 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -0700531
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700532 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700533 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700534 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700535 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700536 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700537 }
Chris Lattnerf7e22732018-06-22 22:03:48 -0700538 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -0700539 return ParseSuccess;
540}
541
Chris Lattnere79379a2018-06-22 10:39:19 -0700542/// External function declarations.
543///
544/// ext-func ::= `extfunc` function-signature
545///
546ParseResult Parser::parseExtFunc() {
547 consumeToken(Token::kw_extfunc);
548
549 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700550 FunctionType *type = nullptr;
551 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -0700552 return ParseFailure;
553
554
555 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -0700556 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -0700557 return ParseSuccess;
558}
559
560
Chris Lattner4c95a502018-06-23 16:03:42 -0700561namespace {
562/// This class represents the transient parser state for the internals of a
563/// function as we are parsing it, e.g. the names for basic blocks. It handles
564/// forward references.
565class CFGFunctionParserState {
566public:
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700567 CFGFunction *function;
568 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
569
Chris Lattner4c95a502018-06-23 16:03:42 -0700570 CFGFunctionParserState(CFGFunction *function) : function(function) {}
571
572 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700573 /// already exist. The location specified is the point of use, which allows
574 /// us to diagnose references to blocks that are not defined precisely.
575 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
576 auto &blockAndLoc = blocksByName[name];
577 if (!blockAndLoc.first) {
578 blockAndLoc.first = new BasicBlock(function);
579 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -0700580 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700581 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -0700582 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700583};
584} // end anonymous namespace
585
586
587/// CFG function declarations.
588///
589/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
590///
591ParseResult Parser::parseCFGFunc() {
592 consumeToken(Token::kw_cfgfunc);
593
594 StringRef name;
595 FunctionType *type = nullptr;
596 if (parseFunctionSignature(name, type))
597 return ParseFailure;
598
599 if (!consumeIf(Token::l_brace))
600 return emitError("expected '{' in CFG function");
601
602 // Okay, the CFG function signature was parsed correctly, create the function.
603 auto function = new CFGFunction(name, type);
604
605 // Make sure we have at least one block.
606 if (curToken.is(Token::r_brace))
607 return emitError("CFG functions must have at least one basic block");
608
609 CFGFunctionParserState functionState(function);
610
611 // Parse the list of blocks.
612 while (!consumeIf(Token::r_brace))
613 if (parseBasicBlock(functionState))
614 return ParseFailure;
615
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700616 // Verify that all referenced blocks were defined. Iteration over a
617 // StringMap isn't determinstic, but this is good enough for our purposes.
618 for (auto &elt : functionState.blocksByName) {
619 auto *bb = elt.second.first;
620 if (!bb->getTerminator())
621 return emitError(elt.second.second,
622 "reference to an undefined basic block '" +
623 elt.first() + "'");
624 }
625
Chris Lattner4c95a502018-06-23 16:03:42 -0700626 module->functionList.push_back(function);
627 return ParseSuccess;
628}
629
630/// Basic block declaration.
631///
632/// basic-block ::= bb-label instruction* terminator-stmt
633/// bb-label ::= bb-id bb-arg-list? `:`
634/// bb-id ::= bare-id
635/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
636///
637ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
638 SMLoc nameLoc = curToken.getLoc();
639 auto name = curToken.getSpelling();
640 if (!consumeIf(Token::bare_identifier))
641 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700642
643 auto block = functionState.getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -0700644
645 // If this block has already been parsed, then this is a redefinition with the
646 // same block name.
647 if (block->getTerminator())
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700648 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
649
650 // References to blocks can occur in any order, but we need to reassemble the
651 // function in the order that occurs in the source file. Do this by moving
652 // each block to the end of the list as it is defined.
653 // FIXME: This is inefficient for large functions given that blockList is a
654 // vector. blockList will eventually be an ilist, which will make this fast.
655 auto &blockList = functionState.function->blockList;
656 if (blockList.back() != block) {
657 auto it = std::find(blockList.begin(), blockList.end(), block);
658 assert(it != blockList.end() && "Block has to be in the blockList");
659 std::swap(*it, blockList.back());
660 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700661
662 // TODO: parse bb argument list.
663
664 if (!consumeIf(Token::colon))
665 return emitError("expected ':' after basic block name");
666
Chris Lattnered65a732018-06-28 20:45:33 -0700667 // Parse the list of operations that make up the body of the block.
668 while (curToken.isNot(Token::kw_return, Token::kw_br)) {
669 if (parseCFGOperation(block, functionState))
670 return ParseFailure;
671 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700672
Chris Lattnered65a732018-06-28 20:45:33 -0700673 if (parseTerminator(block, functionState))
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700674 return ParseFailure;
Chris Lattner4c95a502018-06-23 16:03:42 -0700675
676 return ParseSuccess;
677}
678
679
Chris Lattnered65a732018-06-28 20:45:33 -0700680/// Parse the CFG operation.
681///
682/// TODO(clattner): This is a change from the MLIR spec as written, it is an
683/// experiment that will eliminate "builtin" instructions as a thing.
684///
685/// cfg-operation ::=
686/// (ssa-id `=`)? string '(' ssa-use-list? ')' attribute-dict?
687/// `:` function-type
688///
689ParseResult Parser::
690parseCFGOperation(BasicBlock *currentBB,
691 CFGFunctionParserState &functionState) {
692
693 // TODO: parse ssa-id.
694
695 if (curToken.isNot(Token::string))
696 return emitError("expected operation name in quotes");
697
698 auto name = curToken.getStringValue();
699 if (name.empty())
700 return emitError("empty operation name is invalid");
701
702 consumeToken(Token::string);
703
704 if (!consumeIf(Token::l_paren))
705 return emitError("expected '(' in operation");
706
707 // TODO: Parse operands.
708 if (!consumeIf(Token::r_paren))
709 return emitError("expected '(' in operation");
710
711 auto nameId = Identifier::get(name, context);
712 new OperationInst(nameId, currentBB);
713
714 // TODO: add instruction the per-function symbol table.
715 return ParseSuccess;
716}
717
718
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700719/// Parse the terminator instruction for a basic block.
720///
721/// terminator-stmt ::= `br` bb-id branch-use-list?
722/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
723/// terminator-stmt ::=
724/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
725/// terminator-stmt ::= `return` ssa-use-and-type-list?
726///
Chris Lattnered65a732018-06-28 20:45:33 -0700727ParseResult Parser::parseTerminator(BasicBlock *currentBB,
728 CFGFunctionParserState &functionState) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700729 switch (curToken.getKind()) {
730 default:
Chris Lattnered65a732018-06-28 20:45:33 -0700731 return emitError("expected terminator at end of basic block");
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700732
733 case Token::kw_return:
734 consumeToken(Token::kw_return);
Chris Lattnered65a732018-06-28 20:45:33 -0700735 new ReturnInst(currentBB);
736 return ParseSuccess;
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700737
738 case Token::kw_br: {
739 consumeToken(Token::kw_br);
740 auto destBB = functionState.getBlockNamed(curToken.getSpelling(),
741 curToken.getLoc());
742 if (!consumeIf(Token::bare_identifier))
Chris Lattnered65a732018-06-28 20:45:33 -0700743 return emitError("expected basic block name");
744 new BranchInst(destBB, currentBB);
745 return ParseSuccess;
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700746 }
747 }
748}
749
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700750/// ML function declarations.
751///
752/// ml-func ::= `mlfunc` ml-func-signature `{` ml-stmt* ml-return-stmt `}`
753///
754ParseResult Parser::parseMLFunc() {
755 consumeToken(Token::kw_mlfunc);
756
757 StringRef name;
758 FunctionType *type = nullptr;
759
760 // FIXME: Parse ML function signature (args + types)
761 // by passing pointer to SmallVector<identifier> into parseFunctionSignature
762 if (parseFunctionSignature(name, type))
763 return ParseFailure;
764
765 if (!consumeIf(Token::l_brace))
766 return emitError("expected '{' in ML function");
767
768 // Okay, the ML function signature was parsed correctly, create the function.
769 auto function = new MLFunction(name, type);
770
771 // Make sure we have at least one statement.
772 if (curToken.is(Token::r_brace))
773 return emitError("ML function must end with return statement");
774
775 // Parse the list of instructions.
776 while (!consumeIf(Token::kw_return)) {
777 auto *stmt = parseMLStatement(function);
778 if (!stmt)
779 return ParseFailure;
780 function->stmtList.push_back(stmt);
781 }
782
783 // TODO: parse return statement operands
784 if (!consumeIf(Token::r_brace))
785 emitError("expected '}' in ML function");
786
787 module->functionList.push_back(function);
788
789 return ParseSuccess;
790}
791
792/// Parse an MLStatement
793/// TODO
794///
795MLStatement *Parser::parseMLStatement(MLFunction *currentFunction) {
796 switch (curToken.getKind()) {
797 default:
798 return (emitError("expected ML statement"), nullptr);
799
800 // TODO: add parsing of ML statements
801 }
802}
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700803
Chris Lattner4c95a502018-06-23 16:03:42 -0700804//===----------------------------------------------------------------------===//
805// Top-level entity parsing.
806//===----------------------------------------------------------------------===//
807
Chris Lattnere79379a2018-06-22 10:39:19 -0700808/// This is the top-level module parser.
809Module *Parser::parseModule() {
810 while (1) {
811 switch (curToken.getKind()) {
812 default:
813 emitError("expected a top level entity");
814 return nullptr;
815
816 // If we got to the end of the file, then we're done.
817 case Token::eof:
818 return module.release();
819
820 // If we got an error token, then the lexer already emitted an error, just
821 // stop. Someday we could introduce error recovery if there was demand for
822 // it.
823 case Token::error:
824 return nullptr;
825
826 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -0700827 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -0700828 break;
829
Chris Lattner4c95a502018-06-23 16:03:42 -0700830 case Token::kw_cfgfunc:
831 if (parseCFGFunc()) return nullptr;
832 break;
Chris Lattner8da0c282018-06-29 11:15:56 -0700833 case Token::affine_map_identifier:
MLIR Teamf85a6262018-06-27 11:03:08 -0700834 if (parseAffineMapDef()) return nullptr;
835 break;
Chris Lattner4c95a502018-06-23 16:03:42 -0700836
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700837 case Token::kw_mlfunc:
838 if (parseMLFunc()) return nullptr;
839 break;
840
841 // TODO: affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -0700842 }
843 }
844}
845
846//===----------------------------------------------------------------------===//
847
848/// This parses the file specified by the indicated SourceMgr and returns an
849/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700850Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context,
851 const SMDiagnosticHandlerTy &errorReporter) {
852 return Parser(sourceMgr, context, errorReporter).parseModule();
Chris Lattnere79379a2018-06-22 10:39:19 -0700853}