blob: c36d3b9cfcc7829607bdb0c5cc28bf3177a4fa8a [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.
97 void consumeToken(Token::TokenKind kind) {
98 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.
104 bool consumeIf(Token::TokenKind kind) {
105 if (curToken.isNot(kind))
106 return false;
107 consumeToken(kind);
108 return true;
109 }
110
111 ParseResult parseCommaSeparatedList(Token::TokenKind rightToken,
112 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::
172parseCommaSeparatedList(Token::TokenKind rightToken,
173 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))
195 return emitError("expected ',' or ')'");
196
197 return ParseSuccess;
198}
Chris Lattnere79379a2018-06-22 10:39:19 -0700199
200//===----------------------------------------------------------------------===//
201// Type Parsing
202//===----------------------------------------------------------------------===//
203
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700204/// Parse the low-level fixed dtypes in the system.
205///
206/// primitive-type
207/// ::= `f16` | `bf16` | `f32` | `f64` // Floating point
208/// | `i1` | `i8` | `i16` | `i32` | `i64` // Sized integers
209/// | `int`
210///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700211PrimitiveType *Parser::parsePrimitiveType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700212 switch (curToken.getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700213 default:
214 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700215 case Token::kw_bf16:
216 consumeToken(Token::kw_bf16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700217 return Type::getBF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700218 case Token::kw_f16:
219 consumeToken(Token::kw_f16);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700220 return Type::getF16(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700221 case Token::kw_f32:
222 consumeToken(Token::kw_f32);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700223 return Type::getF32(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700224 case Token::kw_f64:
225 consumeToken(Token::kw_f64);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700226 return Type::getF64(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700227 case Token::kw_i1:
228 consumeToken(Token::kw_i1);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700229 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700230 case Token::kw_i8:
231 consumeToken(Token::kw_i8);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700232 return Type::getI8(context);
233 case Token::kw_i16:
234 consumeToken(Token::kw_i16);
235 return Type::getI16(context);
236 case Token::kw_i32:
237 consumeToken(Token::kw_i32);
238 return Type::getI32(context);
239 case Token::kw_i64:
240 consumeToken(Token::kw_i64);
241 return Type::getI64(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700242 case Token::kw_int:
243 consumeToken(Token::kw_int);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700244 return Type::getInt(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700245 }
246}
247
248/// Parse the element type of a tensor or memref type.
249///
250/// element-type ::= primitive-type | vector-type
251///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700252Type *Parser::parseElementType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700253 if (curToken.is(Token::kw_vector))
254 return parseVectorType();
255
256 return parsePrimitiveType();
257}
258
259/// Parse a vector type.
260///
261/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
262/// const-dimension-list ::= (integer-literal `x`)+
263///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700264VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700265 consumeToken(Token::kw_vector);
266
267 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700268 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700269
270 if (curToken.isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700271 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700272
273 SmallVector<unsigned, 4> dimensions;
274 while (curToken.is(Token::integer)) {
275 // Make sure this integer value is in bound and valid.
276 auto dimension = curToken.getUnsignedIntegerValue();
277 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700278 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700279 dimensions.push_back(dimension.getValue());
280
281 consumeToken(Token::integer);
282
283 // Make sure we have an 'x' or something like 'xbf32'.
284 if (curToken.isNot(Token::bare_identifier) ||
285 curToken.getSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700286 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700287
288 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
289 if (curToken.getSpelling().size() != 1)
290 lex.resetPointer(curToken.getSpelling().data()+1);
291
292 // Consume the 'x'.
293 consumeToken(Token::bare_identifier);
294 }
295
296 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700297 auto *elementType = parsePrimitiveType();
298 if (!elementType)
299 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700300
301 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700302 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700303
Chris Lattnerf7e22732018-06-22 22:03:48 -0700304 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700305}
306
307/// Parse a dimension list of a tensor or memref type. This populates the
308/// dimension list, returning -1 for the '?' dimensions.
309///
310/// dimension-list-ranked ::= (dimension `x`)*
311/// dimension ::= `?` | integer-literal
312///
313ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
314 while (curToken.isAny(Token::integer, Token::question)) {
315 if (consumeIf(Token::question)) {
316 dimensions.push_back(-1);
317 } else {
318 // Make sure this integer value is in bound and valid.
319 auto dimension = curToken.getUnsignedIntegerValue();
320 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
321 return emitError("invalid dimension");
322 dimensions.push_back((int)dimension.getValue());
323 consumeToken(Token::integer);
324 }
325
326 // Make sure we have an 'x' or something like 'xbf32'.
327 if (curToken.isNot(Token::bare_identifier) ||
328 curToken.getSpelling()[0] != 'x')
329 return emitError("expected 'x' in dimension list");
330
331 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
332 if (curToken.getSpelling().size() != 1)
333 lex.resetPointer(curToken.getSpelling().data()+1);
334
335 // Consume the 'x'.
336 consumeToken(Token::bare_identifier);
337 }
338
339 return ParseSuccess;
340}
341
342/// Parse a tensor type.
343///
344/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
345/// dimension-list ::= dimension-list-ranked | `??`
346///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700347Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700348 consumeToken(Token::kw_tensor);
349
350 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700351 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700352
353 bool isUnranked;
354 SmallVector<int, 4> dimensions;
355
356 if (consumeIf(Token::questionquestion)) {
357 isUnranked = true;
358 } else {
359 isUnranked = false;
360 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700361 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700362 }
363
364 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700365 auto elementType = parseElementType();
366 if (!elementType)
367 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700368
369 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700370 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700371
MLIR Team355ec862018-06-23 18:09:09 -0700372 if (isUnranked)
373 return UnrankedTensorType::get(elementType);
374 return RankedTensorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700375}
376
377/// Parse a memref type.
378///
379/// memref-type ::= `memref` `<` dimension-list-ranked element-type
380/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
381///
382/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
383/// memory-space ::= integer-literal /* | TODO: address-space-id */
384///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700385Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700386 consumeToken(Token::kw_memref);
387
388 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700389 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700390
391 SmallVector<int, 4> dimensions;
392 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700393 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700394
395 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700396 auto elementType = parseElementType();
397 if (!elementType)
398 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700399
400 // TODO: Parse semi-affine-map-composition.
401 // TODO: Parse memory-space.
402
403 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700404 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700405
Chris Lattnerf7e22732018-06-22 22:03:48 -0700406 // FIXME: Add an IR representation for memref types.
407 return Type::getI1(context);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700408}
409
410
411
412/// 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
433
434/// Parse an arbitrary type.
435///
436/// type ::= primitive-type
437/// | vector-type
438/// | tensor-type
439/// | memref-type
440/// | function-type
441/// element-type ::= primitive-type | vector-type
442///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700443Type *Parser::parseType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700444 switch (curToken.getKind()) {
445 case Token::kw_memref: return parseMemRefType();
446 case Token::kw_tensor: return parseTensorType();
447 case Token::kw_vector: return parseVectorType();
448 case Token::l_paren: return parseFunctionType();
449 default:
450 return parsePrimitiveType();
451 }
452}
453
454/// Parse a "type list", which is a singular type, or a parenthesized list of
455/// types.
456///
457/// type-list ::= type-list-parens | type
458/// type-list-parens ::= `(` `)`
459/// | `(` type (`,` type)* `)`
460///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700461ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
462 auto parseElt = [&]() -> ParseResult {
463 auto elt = parseType();
464 elements.push_back(elt);
465 return elt ? ParseSuccess : ParseFailure;
466 };
467
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700468 // If there is no parens, then it must be a singular type.
469 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700470 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700471
Chris Lattnerf7e22732018-06-22 22:03:48 -0700472 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700473 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700474
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700475 return ParseSuccess;
476}
477
Chris Lattner4c95a502018-06-23 16:03:42 -0700478//===----------------------------------------------------------------------===//
MLIR Teamf85a6262018-06-27 11:03:08 -0700479// Polyhedral structures.
480//===----------------------------------------------------------------------===//
481
482/// Affine map declaration.
483///
484/// affine-map-def ::= affine-map-id `=` affine-map-inline
485/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
486/// ( `size` `(` dim-size (`,` dim-size)* `)` )?
487/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
488///
489ParseResult Parser::parseAffineMapDef() {
490 assert(curToken.is(Token::affine_map_id));
491
492 StringRef affineMapId = curToken.getSpelling().drop_front();
493 // Check that 'affineMapId' is unique.
494 // TODO(andydavis) Add a unit test for this case.
495 if (affineMaps.count(affineMapId) > 0)
Chris Lattnered65a732018-06-28 20:45:33 -0700496 return emitError("redefinition of affine map id '" + affineMapId + "'");
MLIR Teamf85a6262018-06-27 11:03:08 -0700497
498 consumeToken(Token::affine_map_id);
499
500 // TODO(andydavis,bondhugula) Parse affine map definition.
501 affineMaps[affineMapId].reset(new AffineMap(1, 0));
502 return ParseSuccess;
503}
504
505//===----------------------------------------------------------------------===//
Chris Lattner4c95a502018-06-23 16:03:42 -0700506// Functions
507//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -0700508
Chris Lattnere79379a2018-06-22 10:39:19 -0700509
510/// Parse a function signature, starting with a name and including the parameter
511/// list.
512///
513/// argument-list ::= type (`,` type)* | /*empty*/
514/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
515///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700516ParseResult Parser::parseFunctionSignature(StringRef &name,
517 FunctionType *&type) {
Chris Lattnere79379a2018-06-22 10:39:19 -0700518 if (curToken.isNot(Token::at_identifier))
519 return emitError("expected a function identifier like '@foo'");
520
521 name = curToken.getSpelling().drop_front();
522 consumeToken(Token::at_identifier);
523
524 if (curToken.isNot(Token::l_paren))
525 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -0700526
Chris Lattnerf7e22732018-06-22 22:03:48 -0700527 SmallVector<Type*, 4> arguments;
528 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700529 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -0700530
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700531 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700532 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700533 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700534 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700535 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700536 }
Chris Lattnerf7e22732018-06-22 22:03:48 -0700537 type = FunctionType::get(arguments, results, context);
Chris Lattnere79379a2018-06-22 10:39:19 -0700538 return ParseSuccess;
539}
540
Chris Lattnere79379a2018-06-22 10:39:19 -0700541/// External function declarations.
542///
543/// ext-func ::= `extfunc` function-signature
544///
545ParseResult Parser::parseExtFunc() {
546 consumeToken(Token::kw_extfunc);
547
548 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700549 FunctionType *type = nullptr;
550 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -0700551 return ParseFailure;
552
553
554 // Okay, the external function definition was parsed correctly.
Chris Lattner4c95a502018-06-23 16:03:42 -0700555 module->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -0700556 return ParseSuccess;
557}
558
559
Chris Lattner4c95a502018-06-23 16:03:42 -0700560namespace {
561/// This class represents the transient parser state for the internals of a
562/// function as we are parsing it, e.g. the names for basic blocks. It handles
563/// forward references.
564class CFGFunctionParserState {
565public:
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700566 CFGFunction *function;
567 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
568
Chris Lattner4c95a502018-06-23 16:03:42 -0700569 CFGFunctionParserState(CFGFunction *function) : function(function) {}
570
571 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700572 /// already exist. The location specified is the point of use, which allows
573 /// us to diagnose references to blocks that are not defined precisely.
574 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
575 auto &blockAndLoc = blocksByName[name];
576 if (!blockAndLoc.first) {
577 blockAndLoc.first = new BasicBlock(function);
578 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -0700579 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700580 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -0700581 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700582};
583} // end anonymous namespace
584
585
586/// CFG function declarations.
587///
588/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
589///
590ParseResult Parser::parseCFGFunc() {
591 consumeToken(Token::kw_cfgfunc);
592
593 StringRef name;
594 FunctionType *type = nullptr;
595 if (parseFunctionSignature(name, type))
596 return ParseFailure;
597
598 if (!consumeIf(Token::l_brace))
599 return emitError("expected '{' in CFG function");
600
601 // Okay, the CFG function signature was parsed correctly, create the function.
602 auto function = new CFGFunction(name, type);
603
604 // Make sure we have at least one block.
605 if (curToken.is(Token::r_brace))
606 return emitError("CFG functions must have at least one basic block");
607
608 CFGFunctionParserState functionState(function);
609
610 // Parse the list of blocks.
611 while (!consumeIf(Token::r_brace))
612 if (parseBasicBlock(functionState))
613 return ParseFailure;
614
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700615 // Verify that all referenced blocks were defined. Iteration over a
616 // StringMap isn't determinstic, but this is good enough for our purposes.
617 for (auto &elt : functionState.blocksByName) {
618 auto *bb = elt.second.first;
619 if (!bb->getTerminator())
620 return emitError(elt.second.second,
621 "reference to an undefined basic block '" +
622 elt.first() + "'");
623 }
624
Chris Lattner4c95a502018-06-23 16:03:42 -0700625 module->functionList.push_back(function);
626 return ParseSuccess;
627}
628
629/// Basic block declaration.
630///
631/// basic-block ::= bb-label instruction* terminator-stmt
632/// bb-label ::= bb-id bb-arg-list? `:`
633/// bb-id ::= bare-id
634/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
635///
636ParseResult Parser::parseBasicBlock(CFGFunctionParserState &functionState) {
637 SMLoc nameLoc = curToken.getLoc();
638 auto name = curToken.getSpelling();
639 if (!consumeIf(Token::bare_identifier))
640 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700641
642 auto block = functionState.getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -0700643
644 // If this block has already been parsed, then this is a redefinition with the
645 // same block name.
646 if (block->getTerminator())
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700647 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
648
649 // References to blocks can occur in any order, but we need to reassemble the
650 // function in the order that occurs in the source file. Do this by moving
651 // each block to the end of the list as it is defined.
652 // FIXME: This is inefficient for large functions given that blockList is a
653 // vector. blockList will eventually be an ilist, which will make this fast.
654 auto &blockList = functionState.function->blockList;
655 if (blockList.back() != block) {
656 auto it = std::find(blockList.begin(), blockList.end(), block);
657 assert(it != blockList.end() && "Block has to be in the blockList");
658 std::swap(*it, blockList.back());
659 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700660
661 // TODO: parse bb argument list.
662
663 if (!consumeIf(Token::colon))
664 return emitError("expected ':' after basic block name");
665
Chris Lattnered65a732018-06-28 20:45:33 -0700666 // Parse the list of operations that make up the body of the block.
667 while (curToken.isNot(Token::kw_return, Token::kw_br)) {
668 if (parseCFGOperation(block, functionState))
669 return ParseFailure;
670 }
Chris Lattner4c95a502018-06-23 16:03:42 -0700671
Chris Lattnered65a732018-06-28 20:45:33 -0700672 if (parseTerminator(block, functionState))
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700673 return ParseFailure;
Chris Lattner4c95a502018-06-23 16:03:42 -0700674
675 return ParseSuccess;
676}
677
678
Chris Lattnered65a732018-06-28 20:45:33 -0700679/// Parse the CFG operation.
680///
681/// TODO(clattner): This is a change from the MLIR spec as written, it is an
682/// experiment that will eliminate "builtin" instructions as a thing.
683///
684/// cfg-operation ::=
685/// (ssa-id `=`)? string '(' ssa-use-list? ')' attribute-dict?
686/// `:` function-type
687///
688ParseResult Parser::
689parseCFGOperation(BasicBlock *currentBB,
690 CFGFunctionParserState &functionState) {
691
692 // TODO: parse ssa-id.
693
694 if (curToken.isNot(Token::string))
695 return emitError("expected operation name in quotes");
696
697 auto name = curToken.getStringValue();
698 if (name.empty())
699 return emitError("empty operation name is invalid");
700
701 consumeToken(Token::string);
702
703 if (!consumeIf(Token::l_paren))
704 return emitError("expected '(' in operation");
705
706 // TODO: Parse operands.
707 if (!consumeIf(Token::r_paren))
708 return emitError("expected '(' in operation");
709
710 auto nameId = Identifier::get(name, context);
711 new OperationInst(nameId, currentBB);
712
713 // TODO: add instruction the per-function symbol table.
714 return ParseSuccess;
715}
716
717
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700718/// Parse the terminator instruction for a basic block.
719///
720/// terminator-stmt ::= `br` bb-id branch-use-list?
721/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
722/// terminator-stmt ::=
723/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
724/// terminator-stmt ::= `return` ssa-use-and-type-list?
725///
Chris Lattnered65a732018-06-28 20:45:33 -0700726ParseResult Parser::parseTerminator(BasicBlock *currentBB,
727 CFGFunctionParserState &functionState) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700728 switch (curToken.getKind()) {
729 default:
Chris Lattnered65a732018-06-28 20:45:33 -0700730 return emitError("expected terminator at end of basic block");
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700731
732 case Token::kw_return:
733 consumeToken(Token::kw_return);
Chris Lattnered65a732018-06-28 20:45:33 -0700734 new ReturnInst(currentBB);
735 return ParseSuccess;
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700736
737 case Token::kw_br: {
738 consumeToken(Token::kw_br);
739 auto destBB = functionState.getBlockNamed(curToken.getSpelling(),
740 curToken.getLoc());
741 if (!consumeIf(Token::bare_identifier))
Chris Lattnered65a732018-06-28 20:45:33 -0700742 return emitError("expected basic block name");
743 new BranchInst(destBB, currentBB);
744 return ParseSuccess;
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700745 }
746 }
747}
748
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700749/// ML function declarations.
750///
751/// ml-func ::= `mlfunc` ml-func-signature `{` ml-stmt* ml-return-stmt `}`
752///
753ParseResult Parser::parseMLFunc() {
754 consumeToken(Token::kw_mlfunc);
755
756 StringRef name;
757 FunctionType *type = nullptr;
758
759 // FIXME: Parse ML function signature (args + types)
760 // by passing pointer to SmallVector<identifier> into parseFunctionSignature
761 if (parseFunctionSignature(name, type))
762 return ParseFailure;
763
764 if (!consumeIf(Token::l_brace))
765 return emitError("expected '{' in ML function");
766
767 // Okay, the ML function signature was parsed correctly, create the function.
768 auto function = new MLFunction(name, type);
769
770 // Make sure we have at least one statement.
771 if (curToken.is(Token::r_brace))
772 return emitError("ML function must end with return statement");
773
774 // Parse the list of instructions.
775 while (!consumeIf(Token::kw_return)) {
776 auto *stmt = parseMLStatement(function);
777 if (!stmt)
778 return ParseFailure;
779 function->stmtList.push_back(stmt);
780 }
781
782 // TODO: parse return statement operands
783 if (!consumeIf(Token::r_brace))
784 emitError("expected '}' in ML function");
785
786 module->functionList.push_back(function);
787
788 return ParseSuccess;
789}
790
791/// Parse an MLStatement
792/// TODO
793///
794MLStatement *Parser::parseMLStatement(MLFunction *currentFunction) {
795 switch (curToken.getKind()) {
796 default:
797 return (emitError("expected ML statement"), nullptr);
798
799 // TODO: add parsing of ML statements
800 }
801}
Chris Lattnerf6d80a02018-06-24 11:18:29 -0700802
Chris Lattner4c95a502018-06-23 16:03:42 -0700803//===----------------------------------------------------------------------===//
804// Top-level entity parsing.
805//===----------------------------------------------------------------------===//
806
Chris Lattnere79379a2018-06-22 10:39:19 -0700807/// This is the top-level module parser.
808Module *Parser::parseModule() {
809 while (1) {
810 switch (curToken.getKind()) {
811 default:
812 emitError("expected a top level entity");
813 return nullptr;
814
815 // If we got to the end of the file, then we're done.
816 case Token::eof:
817 return module.release();
818
819 // If we got an error token, then the lexer already emitted an error, just
820 // stop. Someday we could introduce error recovery if there was demand for
821 // it.
822 case Token::error:
823 return nullptr;
824
825 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -0700826 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -0700827 break;
828
Chris Lattner4c95a502018-06-23 16:03:42 -0700829 case Token::kw_cfgfunc:
830 if (parseCFGFunc()) return nullptr;
831 break;
MLIR Teamf85a6262018-06-27 11:03:08 -0700832 case Token::affine_map_id:
833 if (parseAffineMapDef()) return nullptr;
834 break;
Chris Lattner4c95a502018-06-23 16:03:42 -0700835
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700836 case Token::kw_mlfunc:
837 if (parseMLFunc()) return nullptr;
838 break;
839
840 // TODO: affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -0700841 }
842 }
843}
844
845//===----------------------------------------------------------------------===//
846
847/// This parses the file specified by the indicated SourceMgr and returns an
848/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700849Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context,
850 const SMDiagnosticHandlerTy &errorReporter) {
851 return Parser(sourceMgr, context, errorReporter).parseModule();
Chris Lattnere79379a2018-06-22 10:39:19 -0700852}