blob: 42d7935cb6cdc987bc4dd5ecf7592838af3ffd05 [file] [log] [blame]
Chris Lattnere79379a2018-06-22 10:39:19 -07001//===- Parser.cpp - MLIR Parser Implementation ----------------------------===//
2//
3// Copyright 2019 The MLIR Authors.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16// =============================================================================
17//
18// This file implements the parser for the MLIR textual form.
19//
20//===----------------------------------------------------------------------===//
21
22#include "mlir/Parser.h"
23#include "Lexer.h"
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070024#include "mlir/IR/AffineExpr.h"
MLIR Teamf85a6262018-06-27 11:03:08 -070025#include "mlir/IR/AffineMap.h"
Chris Lattner7121b802018-07-04 20:45:39 -070026#include "mlir/IR/Attributes.h"
Chris Lattner158e0a3e2018-07-08 20:51:38 -070027#include "mlir/IR/Builders.h"
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -070028#include "mlir/IR/MLFunction.h"
Chris Lattner21e67f62018-07-06 10:46:19 -070029#include "mlir/IR/Module.h"
30#include "mlir/IR/OperationSet.h"
Chris Lattnerf7e22732018-06-22 22:03:48 -070031#include "mlir/IR/Types.h"
Chris Lattnere79379a2018-06-22 10:39:19 -070032#include "llvm/Support/SourceMgr.h"
33using namespace mlir;
34using llvm::SourceMgr;
Chris Lattner4c95a502018-06-23 16:03:42 -070035using llvm::SMLoc;
Chris Lattnere79379a2018-06-22 10:39:19 -070036
37namespace {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070038class AffineMapParserState;
Chris Lattner48af7d12018-07-09 19:05:38 -070039} // end anonymous namespace
Chris Lattner4c95a502018-06-23 16:03:42 -070040
Chris Lattnerf7e22732018-06-22 22:03:48 -070041/// Simple enum to make code read better in cases that would otherwise return a
42/// bool value. Failure is "true" in a boolean context.
Chris Lattnere79379a2018-06-22 10:39:19 -070043enum ParseResult {
44 ParseSuccess,
45 ParseFailure
46};
47
Uday Bondhugula015cbb12018-07-03 20:16:08 -070048/// Lower precedence ops (all at the same precedence level). LNoOp is false in
49/// the boolean sense.
50enum AffineLowPrecOp {
51 /// Null value.
52 LNoOp,
53 Add,
54 Sub
55};
56
57/// Higher precedence ops - all at the same precedence level. HNoOp is false in
58/// the boolean sense.
59enum AffineHighPrecOp {
60 /// Null value.
61 HNoOp,
62 Mul,
63 FloorDiv,
64 CeilDiv,
65 Mod
66};
67
Chris Lattner48af7d12018-07-09 19:05:38 -070068namespace {
69class Parser;
70
71/// This class refers to all of the state maintained globally by the parser,
72/// such as the current lexer position etc. The Parser base class provides
73/// methods to access this.
74class ParserState {
Chris Lattnered65a732018-06-28 20:45:33 -070075public:
Chris Lattner48af7d12018-07-09 19:05:38 -070076 ParserState(llvm::SourceMgr &sourceMgr, MLIRContext *context,
77 SMDiagnosticHandlerTy errorReporter)
78 : context(context), lex(sourceMgr, errorReporter),
Jacques Pienaar7b829702018-07-03 13:24:09 -070079 curToken(lex.lexToken()), errorReporter(std::move(errorReporter)) {
Chris Lattner158e0a3e2018-07-08 20:51:38 -070080 module.reset(new Module(context));
Chris Lattnere79379a2018-06-22 10:39:19 -070081 }
82
Chris Lattnere79379a2018-06-22 10:39:19 -070083private:
Chris Lattner48af7d12018-07-09 19:05:38 -070084 ParserState(const ParserState &) = delete;
85 void operator=(const ParserState &) = delete;
86
87 friend class Parser;
88
89 // The context we're parsing into.
90 MLIRContext *context;
Chris Lattnerf7e22732018-06-22 22:03:48 -070091
92 // The lexer for the source file we're parsing.
Chris Lattnere79379a2018-06-22 10:39:19 -070093 Lexer lex;
94
95 // This is the next token that hasn't been consumed yet.
96 Token curToken;
97
Jacques Pienaar9c411be2018-06-24 19:17:35 -070098 // The diagnostic error reporter.
Jacques Pienaar7b829702018-07-03 13:24:09 -070099 SMDiagnosticHandlerTy errorReporter;
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700100
Chris Lattnere79379a2018-06-22 10:39:19 -0700101 // This is the result module we are parsing into.
102 std::unique_ptr<Module> module;
103
MLIR Teamf85a6262018-06-27 11:03:08 -0700104 // A map from affine map identifier to AffineMap.
Chris Lattner7121b802018-07-04 20:45:39 -0700105 llvm::StringMap<AffineMap*> affineMapDefinitions;
Chris Lattner48af7d12018-07-09 19:05:38 -0700106};
107} // end anonymous namespace
MLIR Teamf85a6262018-06-27 11:03:08 -0700108
Chris Lattner48af7d12018-07-09 19:05:38 -0700109namespace {
110
111/// This class implement support for parsing global entities like types and
112/// shared entities like SSA names. It is intended to be subclassed by
113/// specialized subparsers that include state, e.g. when a local symbol table.
114class Parser {
115public:
116 Parser(ParserState &state) : state(state), builder(state.context) {}
117 Module *parseModule();
118
Chris Lattnere79379a2018-06-22 10:39:19 -0700119 // Helper methods.
Chris Lattner48af7d12018-07-09 19:05:38 -0700120 MLIRContext *getContext() const { return state.context; }
121 Module *getModule() { return state.module.get(); }
122
123 /// Return the current token the parser is inspecting.
124 const Token &getToken() const { return state.curToken; }
125 StringRef getTokenSpelling() const { return state.curToken.getSpelling(); }
Chris Lattnere79379a2018-06-22 10:39:19 -0700126
127 /// Emit an error and return failure.
Chris Lattner4c95a502018-06-23 16:03:42 -0700128 ParseResult emitError(const Twine &message) {
Chris Lattner48af7d12018-07-09 19:05:38 -0700129 return emitError(state.curToken.getLoc(), message);
Chris Lattner4c95a502018-06-23 16:03:42 -0700130 }
131 ParseResult emitError(SMLoc loc, const Twine &message);
Chris Lattnere79379a2018-06-22 10:39:19 -0700132
133 /// Advance the current lexer onto the next token.
134 void consumeToken() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700135 assert(state.curToken.isNot(Token::eof, Token::error) &&
Chris Lattnere79379a2018-06-22 10:39:19 -0700136 "shouldn't advance past EOF or errors");
Chris Lattner48af7d12018-07-09 19:05:38 -0700137 state.curToken = state.lex.lexToken();
Chris Lattnere79379a2018-06-22 10:39:19 -0700138 }
139
140 /// Advance the current lexer onto the next token, asserting what the expected
141 /// current token is. This is preferred to the above method because it leads
142 /// to more self-documenting code with better checking.
Chris Lattner8da0c282018-06-29 11:15:56 -0700143 void consumeToken(Token::Kind kind) {
Chris Lattner48af7d12018-07-09 19:05:38 -0700144 assert(state.curToken.is(kind) && "consumed an unexpected token");
Chris Lattnere79379a2018-06-22 10:39:19 -0700145 consumeToken();
146 }
147
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700148 /// If the current token has the specified kind, consume it and return true.
149 /// If not, return false.
Chris Lattner8da0c282018-06-29 11:15:56 -0700150 bool consumeIf(Token::Kind kind) {
Chris Lattner48af7d12018-07-09 19:05:38 -0700151 if (state.curToken.isNot(kind))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700152 return false;
153 consumeToken(kind);
154 return true;
155 }
156
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700157 // Binary affine op parsing
158 AffineLowPrecOp consumeIfLowPrecOp();
159 AffineHighPrecOp consumeIfHighPrecOp();
160
Chris Lattner8da0c282018-06-29 11:15:56 -0700161 ParseResult parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700162 const std::function<ParseResult()> &parseElement,
163 bool allowEmptyList = true);
164
Chris Lattnerf7e22732018-06-22 22:03:48 -0700165 // We have two forms of parsing methods - those that return a non-null
166 // pointer on success, and those that return a ParseResult to indicate whether
167 // they returned a failure. The second class fills in by-reference arguments
168 // as the results of their action.
169
Chris Lattnere79379a2018-06-22 10:39:19 -0700170 // Type parsing.
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700171 Type *parsePrimitiveType();
Chris Lattnerf7e22732018-06-22 22:03:48 -0700172 Type *parseElementType();
173 VectorType *parseVectorType();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700174 ParseResult parseDimensionListRanked(SmallVectorImpl<int> &dimensions);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700175 Type *parseTensorType();
176 Type *parseMemRefType();
177 Type *parseFunctionType();
178 Type *parseType();
179 ParseResult parseTypeList(SmallVectorImpl<Type*> &elements);
Chris Lattnere79379a2018-06-22 10:39:19 -0700180
Chris Lattner7121b802018-07-04 20:45:39 -0700181 // Attribute parsing.
182 Attribute *parseAttribute();
183 ParseResult parseAttributeDict(SmallVectorImpl<NamedAttribute> &attributes);
184
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700185 // Parsing identifiers' lists for polyhedral structures.
186 ParseResult parseDimIdList(AffineMapParserState &state);
187 ParseResult parseSymbolIdList(AffineMapParserState &state);
188 ParseResult parseDimOrSymbolId(AffineMapParserState &state, bool dim);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700189
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700190 // Polyhedral structures.
MLIR Teamf85a6262018-06-27 11:03:08 -0700191 ParseResult parseAffineMapDef();
Chris Lattner7121b802018-07-04 20:45:39 -0700192 AffineMap *parseAffineMapInline(StringRef mapId);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700193 AffineExpr *parseAffineExpr(const AffineMapParserState &state);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700194 AffineExpr *parseParentheticalExpr(const AffineMapParserState &state);
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700195 AffineExpr *parseNegateExpression(AffineExpr *lhs,
196 const AffineMapParserState &state);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700197 AffineExpr *parseIntegerExpr(const AffineMapParserState &state);
198 AffineExpr *parseBareIdExpr(const AffineMapParserState &state);
199
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700200 AffineExpr *getBinaryAffineOpExpr(AffineHighPrecOp op, AffineExpr *lhs,
201 AffineExpr *rhs);
202 AffineExpr *getBinaryAffineOpExpr(AffineLowPrecOp op, AffineExpr *lhs,
203 AffineExpr *rhs);
204 AffineExpr *parseAffineOperandExpr(AffineExpr *lhs,
205 const AffineMapParserState &state);
206 AffineExpr *parseAffineLowPrecOpExpr(AffineExpr *llhs, AffineLowPrecOp llhsOp,
207 const AffineMapParserState &state);
208 AffineExpr *parseAffineHighPrecOpExpr(AffineExpr *llhs,
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700209 AffineHighPrecOp llhsOp,
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700210 const AffineMapParserState &state);
MLIR Teamf85a6262018-06-27 11:03:08 -0700211
Chris Lattner78276e32018-07-07 15:48:26 -0700212 // SSA
213 ParseResult parseSSAUse();
214 ParseResult parseOptionalSSAUseList(Token::Kind endToken);
215 ParseResult parseSSAUseAndType();
216 ParseResult parseOptionalSSAUseAndTypeList(Token::Kind endToken);
217
Chris Lattner4c95a502018-06-23 16:03:42 -0700218 // Functions.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700219 ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
Chris Lattnere79379a2018-06-22 10:39:19 -0700220 ParseResult parseExtFunc();
Chris Lattner4c95a502018-06-23 16:03:42 -0700221 ParseResult parseCFGFunc();
Chris Lattner78276e32018-07-07 15:48:26 -0700222 ParseResult parseMLFunc();
Chris Lattner48af7d12018-07-09 19:05:38 -0700223
224private:
225 // The Parser is subclassed and reinstantiated. Do not add additional
226 // non-trivial state here, add it to the ParserState class.
227 ParserState &state;
228 Builder builder;
Chris Lattnere79379a2018-06-22 10:39:19 -0700229};
230} // end anonymous namespace
231
232//===----------------------------------------------------------------------===//
233// Helper methods.
234//===----------------------------------------------------------------------===//
235
Chris Lattner4c95a502018-06-23 16:03:42 -0700236ParseResult Parser::emitError(SMLoc loc, const Twine &message) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700237 // If we hit a parse error in response to a lexer error, then the lexer
Jacques Pienaar9c411be2018-06-24 19:17:35 -0700238 // already reported the error.
Chris Lattner48af7d12018-07-09 19:05:38 -0700239 if (getToken().is(Token::error))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700240 return ParseFailure;
241
Chris Lattner48af7d12018-07-09 19:05:38 -0700242 auto &sourceMgr = state.lex.getSourceMgr();
243 state.errorReporter(sourceMgr.GetMessage(loc, SourceMgr::DK_Error, message));
Chris Lattnere79379a2018-06-22 10:39:19 -0700244 return ParseFailure;
245}
246
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700247/// Parse a comma-separated list of elements, terminated with an arbitrary
248/// token. This allows empty lists if allowEmptyList is true.
249///
250/// abstract-list ::= rightToken // if allowEmptyList == true
251/// abstract-list ::= element (',' element)* rightToken
252///
253ParseResult Parser::
Chris Lattner8da0c282018-06-29 11:15:56 -0700254parseCommaSeparatedList(Token::Kind rightToken,
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700255 const std::function<ParseResult()> &parseElement,
256 bool allowEmptyList) {
257 // Handle the empty case.
Chris Lattner48af7d12018-07-09 19:05:38 -0700258 if (getToken().is(rightToken)) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700259 if (!allowEmptyList)
260 return emitError("expected list element");
261 consumeToken(rightToken);
262 return ParseSuccess;
263 }
264
265 // Non-empty case starts with an element.
266 if (parseElement())
267 return ParseFailure;
268
269 // Otherwise we have a list of comma separated elements.
270 while (consumeIf(Token::comma)) {
271 if (parseElement())
272 return ParseFailure;
273 }
274
275 // Consume the end character.
276 if (!consumeIf(rightToken))
Chris Lattner8da0c282018-06-29 11:15:56 -0700277 return emitError("expected ',' or '" + Token::getTokenSpelling(rightToken) +
278 "'");
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700279
280 return ParseSuccess;
281}
Chris Lattnere79379a2018-06-22 10:39:19 -0700282
283//===----------------------------------------------------------------------===//
284// Type Parsing
285//===----------------------------------------------------------------------===//
286
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700287/// Parse the low-level fixed dtypes in the system.
288///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700289/// primitive-type ::= `f16` | `bf16` | `f32` | `f64`
290/// primitive-type ::= integer-type
291/// primitive-type ::= `affineint`
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700292///
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700293Type *Parser::parsePrimitiveType() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700294 switch (getToken().getKind()) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700295 default:
296 return (emitError("expected type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700297 case Token::kw_bf16:
298 consumeToken(Token::kw_bf16);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700299 return builder.getBF16Type();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700300 case Token::kw_f16:
301 consumeToken(Token::kw_f16);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700302 return builder.getF16Type();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700303 case Token::kw_f32:
304 consumeToken(Token::kw_f32);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700305 return builder.getF32Type();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700306 case Token::kw_f64:
307 consumeToken(Token::kw_f64);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700308 return builder.getF64Type();
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700309 case Token::kw_affineint:
310 consumeToken(Token::kw_affineint);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700311 return builder.getAffineIntType();
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700312 case Token::inttype: {
Chris Lattner48af7d12018-07-09 19:05:38 -0700313 auto width = getToken().getIntTypeBitwidth();
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700314 if (!width.hasValue())
315 return (emitError("invalid integer width"), nullptr);
316 consumeToken(Token::inttype);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700317 return builder.getIntegerType(width.getValue());
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700318 }
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700319 }
320}
321
322/// Parse the element type of a tensor or memref type.
323///
324/// element-type ::= primitive-type | vector-type
325///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700326Type *Parser::parseElementType() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700327 if (getToken().is(Token::kw_vector))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700328 return parseVectorType();
329
330 return parsePrimitiveType();
331}
332
333/// Parse a vector type.
334///
335/// vector-type ::= `vector` `<` const-dimension-list primitive-type `>`
336/// const-dimension-list ::= (integer-literal `x`)+
337///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700338VectorType *Parser::parseVectorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700339 consumeToken(Token::kw_vector);
340
341 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700342 return (emitError("expected '<' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700343
Chris Lattner48af7d12018-07-09 19:05:38 -0700344 if (getToken().isNot(Token::integer))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700345 return (emitError("expected dimension size in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700346
347 SmallVector<unsigned, 4> dimensions;
Chris Lattner48af7d12018-07-09 19:05:38 -0700348 while (getToken().is(Token::integer)) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700349 // Make sure this integer value is in bound and valid.
Chris Lattner48af7d12018-07-09 19:05:38 -0700350 auto dimension = getToken().getUnsignedIntegerValue();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700351 if (!dimension.hasValue())
Chris Lattnerf7e22732018-06-22 22:03:48 -0700352 return (emitError("invalid dimension in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700353 dimensions.push_back(dimension.getValue());
354
355 consumeToken(Token::integer);
356
357 // Make sure we have an 'x' or something like 'xbf32'.
Chris Lattner48af7d12018-07-09 19:05:38 -0700358 if (getToken().isNot(Token::bare_identifier) ||
359 getTokenSpelling()[0] != 'x')
Chris Lattnerf7e22732018-06-22 22:03:48 -0700360 return (emitError("expected 'x' in vector dimension list"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700361
362 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
Chris Lattner48af7d12018-07-09 19:05:38 -0700363 if (getTokenSpelling().size() != 1)
364 state.lex.resetPointer(getTokenSpelling().data() + 1);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700365
366 // Consume the 'x'.
367 consumeToken(Token::bare_identifier);
368 }
369
370 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700371 auto *elementType = parsePrimitiveType();
372 if (!elementType)
373 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700374
375 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700376 return (emitError("expected '>' in vector type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700377
Chris Lattnerf7e22732018-06-22 22:03:48 -0700378 return VectorType::get(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700379}
380
381/// Parse a dimension list of a tensor or memref type. This populates the
382/// dimension list, returning -1 for the '?' dimensions.
383///
384/// dimension-list-ranked ::= (dimension `x`)*
385/// dimension ::= `?` | integer-literal
386///
387ParseResult Parser::parseDimensionListRanked(SmallVectorImpl<int> &dimensions) {
Chris Lattner48af7d12018-07-09 19:05:38 -0700388 while (getToken().isAny(Token::integer, Token::question)) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700389 if (consumeIf(Token::question)) {
390 dimensions.push_back(-1);
391 } else {
392 // Make sure this integer value is in bound and valid.
Chris Lattner48af7d12018-07-09 19:05:38 -0700393 auto dimension = getToken().getUnsignedIntegerValue();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700394 if (!dimension.hasValue() || (int)dimension.getValue() < 0)
395 return emitError("invalid dimension");
396 dimensions.push_back((int)dimension.getValue());
397 consumeToken(Token::integer);
398 }
399
400 // Make sure we have an 'x' or something like 'xbf32'.
Chris Lattner48af7d12018-07-09 19:05:38 -0700401 if (getToken().isNot(Token::bare_identifier) ||
402 getTokenSpelling()[0] != 'x')
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700403 return emitError("expected 'x' in dimension list");
404
405 // If we had a prefix of 'x', lex the next token immediately after the 'x'.
Chris Lattner48af7d12018-07-09 19:05:38 -0700406 if (getTokenSpelling().size() != 1)
407 state.lex.resetPointer(getTokenSpelling().data() + 1);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700408
409 // Consume the 'x'.
410 consumeToken(Token::bare_identifier);
411 }
412
413 return ParseSuccess;
414}
415
416/// Parse a tensor type.
417///
418/// tensor-type ::= `tensor` `<` dimension-list element-type `>`
419/// dimension-list ::= dimension-list-ranked | `??`
420///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700421Type *Parser::parseTensorType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700422 consumeToken(Token::kw_tensor);
423
424 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700425 return (emitError("expected '<' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700426
427 bool isUnranked;
428 SmallVector<int, 4> dimensions;
429
430 if (consumeIf(Token::questionquestion)) {
431 isUnranked = true;
432 } else {
433 isUnranked = false;
434 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700435 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700436 }
437
438 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700439 auto elementType = parseElementType();
440 if (!elementType)
441 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700442
443 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700444 return (emitError("expected '>' in tensor type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700445
MLIR Team355ec862018-06-23 18:09:09 -0700446 if (isUnranked)
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700447 return builder.getTensorType(elementType);
448 return builder.getTensorType(dimensions, elementType);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700449}
450
451/// Parse a memref type.
452///
453/// memref-type ::= `memref` `<` dimension-list-ranked element-type
454/// (`,` semi-affine-map-composition)? (`,` memory-space)? `>`
455///
456/// semi-affine-map-composition ::= (semi-affine-map `,` )* semi-affine-map
457/// memory-space ::= integer-literal /* | TODO: address-space-id */
458///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700459Type *Parser::parseMemRefType() {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700460 consumeToken(Token::kw_memref);
461
462 if (!consumeIf(Token::less))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700463 return (emitError("expected '<' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700464
465 SmallVector<int, 4> dimensions;
466 if (parseDimensionListRanked(dimensions))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700467 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700468
469 // Parse the element type.
Chris Lattnerf7e22732018-06-22 22:03:48 -0700470 auto elementType = parseElementType();
471 if (!elementType)
472 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700473
474 // TODO: Parse semi-affine-map-composition.
475 // TODO: Parse memory-space.
476
477 if (!consumeIf(Token::greater))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700478 return (emitError("expected '>' in memref type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700479
Chris Lattnerf7e22732018-06-22 22:03:48 -0700480 // FIXME: Add an IR representation for memref types.
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700481 return builder.getIntegerType(1);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700482}
483
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700484/// Parse a function type.
485///
486/// function-type ::= type-list-parens `->` type-list
487///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700488Type *Parser::parseFunctionType() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700489 assert(getToken().is(Token::l_paren));
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700490
Chris Lattnerf7e22732018-06-22 22:03:48 -0700491 SmallVector<Type*, 4> arguments;
492 if (parseTypeList(arguments))
493 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700494
495 if (!consumeIf(Token::arrow))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700496 return (emitError("expected '->' in function type"), nullptr);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700497
Chris Lattnerf7e22732018-06-22 22:03:48 -0700498 SmallVector<Type*, 4> results;
499 if (parseTypeList(results))
500 return nullptr;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700501
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700502 return builder.getFunctionType(arguments, results);
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700503}
504
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700505/// Parse an arbitrary type.
506///
507/// type ::= primitive-type
508/// | vector-type
509/// | tensor-type
510/// | memref-type
511/// | function-type
512/// element-type ::= primitive-type | vector-type
513///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700514Type *Parser::parseType() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700515 switch (getToken().getKind()) {
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700516 case Token::kw_memref: return parseMemRefType();
517 case Token::kw_tensor: return parseTensorType();
518 case Token::kw_vector: return parseVectorType();
519 case Token::l_paren: return parseFunctionType();
520 default:
521 return parsePrimitiveType();
522 }
523}
524
525/// Parse a "type list", which is a singular type, or a parenthesized list of
526/// types.
527///
528/// type-list ::= type-list-parens | type
529/// type-list-parens ::= `(` `)`
530/// | `(` type (`,` type)* `)`
531///
Chris Lattnerf7e22732018-06-22 22:03:48 -0700532ParseResult Parser::parseTypeList(SmallVectorImpl<Type*> &elements) {
533 auto parseElt = [&]() -> ParseResult {
534 auto elt = parseType();
535 elements.push_back(elt);
536 return elt ? ParseSuccess : ParseFailure;
537 };
538
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700539 // If there is no parens, then it must be a singular type.
540 if (!consumeIf(Token::l_paren))
Chris Lattnerf7e22732018-06-22 22:03:48 -0700541 return parseElt();
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700542
Chris Lattnerf7e22732018-06-22 22:03:48 -0700543 if (parseCommaSeparatedList(Token::r_paren, parseElt))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700544 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700545
Chris Lattnerbb8fafc2018-06-22 15:52:02 -0700546 return ParseSuccess;
547}
548
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700549namespace {
550/// This class represents the transient parser state while parsing an affine
551/// expression.
552class AffineMapParserState {
553 public:
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700554 explicit AffineMapParserState() {}
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700555
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700556 void addDim(StringRef sRef) { dims.insert({sRef, dims.size()}); }
557 void addSymbol(StringRef sRef) { symbols.insert({sRef, symbols.size()}); }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700558
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700559 unsigned getNumDims() const { return dims.size(); }
560 unsigned getNumSymbols() const { return symbols.size(); }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700561
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700562 // TODO(bondhugula): could just use an vector/ArrayRef and scan the numbers.
563 const llvm::StringMap<unsigned> &getDims() const { return dims; }
564 const llvm::StringMap<unsigned> &getSymbols() const { return symbols; }
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700565
566 private:
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700567 llvm::StringMap<unsigned> dims;
568 llvm::StringMap<unsigned> symbols;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700569};
570} // end anonymous namespace
571
Chris Lattner4c95a502018-06-23 16:03:42 -0700572//===----------------------------------------------------------------------===//
Chris Lattner7121b802018-07-04 20:45:39 -0700573// Attribute parsing.
574//===----------------------------------------------------------------------===//
575
576
577/// Attribute parsing.
578///
579/// attribute-value ::= bool-literal
580/// | integer-literal
581/// | float-literal
582/// | string-literal
583/// | `[` (attribute-value (`,` attribute-value)*)? `]`
584///
585Attribute *Parser::parseAttribute() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700586 switch (getToken().getKind()) {
Chris Lattner7121b802018-07-04 20:45:39 -0700587 case Token::kw_true:
588 consumeToken(Token::kw_true);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700589 return BoolAttr::get(true, builder.getContext());
Chris Lattner7121b802018-07-04 20:45:39 -0700590 case Token::kw_false:
591 consumeToken(Token::kw_false);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700592 return BoolAttr::get(false, builder.getContext());
Chris Lattner7121b802018-07-04 20:45:39 -0700593
594 case Token::integer: {
Chris Lattner48af7d12018-07-09 19:05:38 -0700595 auto val = getToken().getUInt64IntegerValue();
Chris Lattner7121b802018-07-04 20:45:39 -0700596 if (!val.hasValue() || (int64_t)val.getValue() < 0)
597 return (emitError("integer too large for attribute"), nullptr);
598 consumeToken(Token::integer);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700599 return IntegerAttr::get((int64_t)val.getValue(), builder.getContext());
Chris Lattner7121b802018-07-04 20:45:39 -0700600 }
601
602 case Token::minus: {
603 consumeToken(Token::minus);
Chris Lattner48af7d12018-07-09 19:05:38 -0700604 if (getToken().is(Token::integer)) {
605 auto val = getToken().getUInt64IntegerValue();
Chris Lattner7121b802018-07-04 20:45:39 -0700606 if (!val.hasValue() || (int64_t)-val.getValue() >= 0)
607 return (emitError("integer too large for attribute"), nullptr);
608 consumeToken(Token::integer);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700609 return IntegerAttr::get((int64_t)-val.getValue(), builder.getContext());
Chris Lattner7121b802018-07-04 20:45:39 -0700610 }
611
612 return (emitError("expected constant integer or floating point value"),
613 nullptr);
614 }
615
616 case Token::string: {
Chris Lattner48af7d12018-07-09 19:05:38 -0700617 auto val = getToken().getStringValue();
Chris Lattner7121b802018-07-04 20:45:39 -0700618 consumeToken(Token::string);
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700619 return StringAttr::get(val, builder.getContext());
Chris Lattner7121b802018-07-04 20:45:39 -0700620 }
621
622 case Token::l_bracket: {
623 consumeToken(Token::l_bracket);
624 SmallVector<Attribute*, 4> elements;
625
626 auto parseElt = [&]() -> ParseResult {
627 elements.push_back(parseAttribute());
628 return elements.back() ? ParseSuccess : ParseFailure;
629 };
630
631 if (parseCommaSeparatedList(Token::r_bracket, parseElt))
632 return nullptr;
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700633 return ArrayAttr::get(elements, builder.getContext());
Chris Lattner7121b802018-07-04 20:45:39 -0700634 }
635 default:
636 // TODO: Handle floating point.
637 return (emitError("expected constant attribute value"), nullptr);
638 }
639}
640
Chris Lattner7121b802018-07-04 20:45:39 -0700641/// Attribute dictionary.
642///
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700643/// attribute-dict ::= `{` `}`
644/// | `{` attribute-entry (`,` attribute-entry)* `}`
645/// attribute-entry ::= bare-id `:` attribute-value
Chris Lattner7121b802018-07-04 20:45:39 -0700646///
647ParseResult Parser::parseAttributeDict(
648 SmallVectorImpl<NamedAttribute> &attributes) {
649 consumeToken(Token::l_brace);
650
651 auto parseElt = [&]() -> ParseResult {
652 // We allow keywords as attribute names.
Chris Lattner48af7d12018-07-09 19:05:38 -0700653 if (getToken().isNot(Token::bare_identifier, Token::inttype) &&
654 !getToken().isKeyword())
Chris Lattner7121b802018-07-04 20:45:39 -0700655 return emitError("expected attribute name");
Chris Lattner48af7d12018-07-09 19:05:38 -0700656 auto nameId = Identifier::get(getTokenSpelling(), builder.getContext());
Chris Lattner7121b802018-07-04 20:45:39 -0700657 consumeToken();
658
659 if (!consumeIf(Token::colon))
660 return emitError("expected ':' in attribute list");
661
662 auto attr = parseAttribute();
663 if (!attr) return ParseFailure;
664
665 attributes.push_back({nameId, attr});
666 return ParseSuccess;
667 };
668
669 if (parseCommaSeparatedList(Token::r_brace, parseElt))
670 return ParseFailure;
671
672 return ParseSuccess;
673}
674
675//===----------------------------------------------------------------------===//
MLIR Teamf85a6262018-06-27 11:03:08 -0700676// Polyhedral structures.
677//===----------------------------------------------------------------------===//
678
679/// Affine map declaration.
680///
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700681/// affine-map-def ::= affine-map-id `=` affine-map-inline
MLIR Teamf85a6262018-06-27 11:03:08 -0700682///
683ParseResult Parser::parseAffineMapDef() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700684 assert(getToken().is(Token::hash_identifier));
MLIR Teamf85a6262018-06-27 11:03:08 -0700685
Chris Lattner48af7d12018-07-09 19:05:38 -0700686 StringRef affineMapId = getTokenSpelling().drop_front();
Chris Lattner7121b802018-07-04 20:45:39 -0700687
688 // Check for redefinitions.
Chris Lattner48af7d12018-07-09 19:05:38 -0700689 auto *&entry = state.affineMapDefinitions[affineMapId];
Chris Lattner7121b802018-07-04 20:45:39 -0700690 if (entry)
691 return emitError("redefinition of affine map id '" + affineMapId + "'");
692
Chris Lattner78276e32018-07-07 15:48:26 -0700693 consumeToken(Token::hash_identifier);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700694
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700695 // Parse the '='
696 if (!consumeIf(Token::equal))
697 return emitError("expected '=' in affine map outlined definition");
MLIR Teamf85a6262018-06-27 11:03:08 -0700698
Chris Lattner7121b802018-07-04 20:45:39 -0700699 entry = parseAffineMapInline(affineMapId);
700 if (!entry)
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700701 return ParseFailure;
MLIR Teamf85a6262018-06-27 11:03:08 -0700702
Chris Lattner48af7d12018-07-09 19:05:38 -0700703 getModule()->affineMapList.push_back(entry);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700704 return ParseSuccess;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700705}
706
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700707/// Create an affine binary high precedence op expression (mul's, div's, mod)
708AffineExpr *Parser::getBinaryAffineOpExpr(AffineHighPrecOp op, AffineExpr *lhs,
709 AffineExpr *rhs) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700710 switch (op) {
711 case Mul:
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700712 if (!lhs->isSymbolic() && !rhs->isSymbolic()) {
713 emitError("non-affine expression: at least one of the multiply "
714 "operands has to be either a constant or symbolic");
715 return nullptr;
716 }
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700717 return AffineMulExpr::get(lhs, rhs, builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700718 case FloorDiv:
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700719 if (!rhs->isSymbolic()) {
720 emitError("non-affine expression: right operand of floordiv "
721 "has to be either a constant or symbolic");
722 return nullptr;
723 }
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700724 return AffineFloorDivExpr::get(lhs, rhs, builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700725 case CeilDiv:
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700726 if (!rhs->isSymbolic()) {
727 emitError("non-affine expression: right operand of ceildiv "
728 "has to be either a constant or symbolic");
729 return nullptr;
730 }
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700731 return AffineCeilDivExpr::get(lhs, rhs, builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700732 case Mod:
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700733 if (!rhs->isSymbolic()) {
734 emitError("non-affine expression: right operand of mod "
735 "has to be either a constant or symbolic");
736 return nullptr;
737 }
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700738 return AffineModExpr::get(lhs, rhs, builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700739 case HNoOp:
740 llvm_unreachable("can't create affine expression for null high prec op");
741 return nullptr;
742 }
743}
744
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700745/// Create an affine binary low precedence op expression (add, sub).
746AffineExpr *Parser::getBinaryAffineOpExpr(AffineLowPrecOp op, AffineExpr *lhs,
747 AffineExpr *rhs) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700748 switch (op) {
749 case AffineLowPrecOp::Add:
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700750 return AffineAddExpr::get(lhs, rhs, builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700751 case AffineLowPrecOp::Sub:
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700752 return AffineSubExpr::get(lhs, rhs, builder.getContext());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700753 case AffineLowPrecOp::LNoOp:
754 llvm_unreachable("can't create affine expression for null low prec op");
755 return nullptr;
756 }
757}
758
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700759/// Consume this token if it is a lower precedence affine op (there are only two
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700760/// precedence levels).
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700761AffineLowPrecOp Parser::consumeIfLowPrecOp() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700762 switch (getToken().getKind()) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700763 case Token::plus:
764 consumeToken(Token::plus);
765 return AffineLowPrecOp::Add;
766 case Token::minus:
767 consumeToken(Token::minus);
768 return AffineLowPrecOp::Sub;
769 default:
770 return AffineLowPrecOp::LNoOp;
771 }
772}
773
774/// Consume this token if it is a higher precedence affine op (there are only
775/// two precedence levels)
776AffineHighPrecOp Parser::consumeIfHighPrecOp() {
Chris Lattner48af7d12018-07-09 19:05:38 -0700777 switch (getToken().getKind()) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700778 case Token::star:
779 consumeToken(Token::star);
780 return Mul;
781 case Token::kw_floordiv:
782 consumeToken(Token::kw_floordiv);
783 return FloorDiv;
784 case Token::kw_ceildiv:
785 consumeToken(Token::kw_ceildiv);
786 return CeilDiv;
787 case Token::kw_mod:
788 consumeToken(Token::kw_mod);
789 return Mod;
790 default:
791 return HNoOp;
792 }
793}
794
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700795/// Parse a high precedence op expression list: mul, div, and mod are high
796/// precedence binary ops, i.e., parse a
797/// expr_1 op_1 expr_2 op_2 ... expr_n
798/// where op_1, op_2 are all a AffineHighPrecOp (mul, div, mod).
799/// All affine binary ops are left associative.
800/// Given llhs, returns (llhs llhsOp lhs) op rhs, or (lhs op rhs) if llhs is
801/// null. If no rhs can be found, returns (llhs llhsOp lhs) or lhs if llhs is
802/// null.
803AffineExpr *
804Parser::parseAffineHighPrecOpExpr(AffineExpr *llhs, AffineHighPrecOp llhsOp,
805 const AffineMapParserState &state) {
806 AffineExpr *lhs = parseAffineOperandExpr(llhs, state);
807 if (!lhs)
808 return nullptr;
809
810 AffineHighPrecOp op = HNoOp;
811 // Found an LHS. Parse the remaining expression.
812 if ((op = consumeIfHighPrecOp())) {
813 if (llhs) {
814 AffineExpr *expr = getBinaryAffineOpExpr(llhsOp, llhs, lhs);
815 if (!expr)
816 return nullptr;
817 return parseAffineHighPrecOpExpr(expr, op, state);
818 }
819 // No LLHS, get RHS
820 return parseAffineHighPrecOpExpr(lhs, op, state);
821 }
822
823 // This is the last operand in this expression.
824 if (llhs)
825 return getBinaryAffineOpExpr(llhsOp, llhs, lhs);
826
827 // No llhs, 'lhs' itself is the expression.
828 return lhs;
829}
830
831/// Parse an affine expression inside parentheses.
832///
833/// affine-expr ::= `(` affine-expr `)`
834AffineExpr *Parser::parseParentheticalExpr(const AffineMapParserState &state) {
835 if (!consumeIf(Token::l_paren))
836 return (emitError("expected '('"), nullptr);
Chris Lattner48af7d12018-07-09 19:05:38 -0700837 if (getToken().is(Token::r_paren))
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700838 return (emitError("no expression inside parentheses"), nullptr);
839 auto *expr = parseAffineExpr(state);
840 if (!expr)
841 // Error would have been emitted by parseAffineExpr.
842 return nullptr;
843 if (!consumeIf(Token::r_paren))
844 return (emitError("expected ')'"), nullptr);
845 return expr;
846}
847
848/// Parse the negation expression.
849///
850/// affine-expr ::= `-` affine-expr
851AffineExpr *Parser::parseNegateExpression(AffineExpr *lhs,
852 const AffineMapParserState &state) {
853 if (!consumeIf(Token::minus))
854 return (emitError("expected '-'"), nullptr);
855
856 AffineExpr *operand = parseAffineOperandExpr(lhs, state);
857 // Since negation has the highest precedence of all ops (including high
858 // precedence ops) but lower than parentheses, we are only going to use
859 // parseAffineOperandExpr instead of parseAffineExpr here.
860 if (!operand)
861 // Extra error message although parseAffineOperandExpr would have
862 // complained. Leads to a better diagnostic.
863 return (emitError("missing operand of negation"), nullptr);
864 AffineConstantExpr *minusOne =
865 AffineConstantExpr::get(-1, builder.getContext());
866 return AffineMulExpr::get(minusOne, operand, builder.getContext());
867}
868
869/// Parse a bare id that may appear in an affine expression.
870///
871/// affine-expr ::= bare-id
872AffineExpr *Parser::parseBareIdExpr(const AffineMapParserState &state) {
Chris Lattner48af7d12018-07-09 19:05:38 -0700873 if (getToken().isNot(Token::bare_identifier))
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700874 return (emitError("expected bare identifier"), nullptr);
875
Chris Lattner48af7d12018-07-09 19:05:38 -0700876 StringRef sRef = getTokenSpelling();
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700877 const auto &dims = state.getDims();
878 const auto &symbols = state.getSymbols();
879 if (dims.count(sRef)) {
880 consumeToken(Token::bare_identifier);
881 return AffineDimExpr::get(dims.lookup(sRef), builder.getContext());
882 }
883 if (symbols.count(sRef)) {
884 consumeToken(Token::bare_identifier);
885 return AffineSymbolExpr::get(symbols.lookup(sRef), builder.getContext());
886 }
887 return (emitError("identifier is neither dimensional nor symbolic"), nullptr);
888}
889
890/// Parse a positive integral constant appearing in an affine expression.
891///
892/// affine-expr ::= integer-literal
893AffineExpr *Parser::parseIntegerExpr(const AffineMapParserState &state) {
894 // No need to handle negative numbers separately here. They are naturally
895 // handled via the unary negation operator, although (FIXME) MININT_64 still
896 // not correctly handled.
Chris Lattner48af7d12018-07-09 19:05:38 -0700897 if (getToken().isNot(Token::integer))
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700898 return (emitError("expected integer"), nullptr);
899
Chris Lattner48af7d12018-07-09 19:05:38 -0700900 auto val = getToken().getUInt64IntegerValue();
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700901 if (!val.hasValue() || (int64_t)val.getValue() < 0) {
902 return (emitError("constant too large for affineint"), nullptr);
903 }
904 consumeToken(Token::integer);
905 return AffineConstantExpr::get((int64_t)val.getValue(), builder.getContext());
906}
907
908/// Parses an expression that can be a valid operand of an affine expression.
Uday Bondhugula76345202018-07-09 13:47:52 -0700909/// lhs: if non-null, lhs is an affine expression that is the lhs of a binary
910/// operator, the rhs of which is being parsed. This is used to determine
911/// whether an error should be emitted for a missing right operand.
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700912// Eg: for an expression without parentheses (like i + j + k + l), each
913// of the four identifiers is an operand. For i + j*k + l, j*k is not an
914// operand expression, it's an op expression and will be parsed via
915// parseAffineHighPrecOpExpression(). However, for i + (j*k) + -l, (j*k) and -l
916// are valid operands that will be parsed by this function.
917AffineExpr *Parser::parseAffineOperandExpr(AffineExpr *lhs,
918 const AffineMapParserState &state) {
Chris Lattner48af7d12018-07-09 19:05:38 -0700919 switch (getToken().getKind()) {
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700920 case Token::bare_identifier:
921 return parseBareIdExpr(state);
922 case Token::integer:
923 return parseIntegerExpr(state);
924 case Token::l_paren:
925 return parseParentheticalExpr(state);
926 case Token::minus:
927 return parseNegateExpression(lhs, state);
Uday Bondhugula76345202018-07-09 13:47:52 -0700928 case Token::kw_ceildiv:
929 case Token::kw_floordiv:
930 case Token::kw_mod:
931 case Token::plus:
932 case Token::star:
933 if (lhs)
934 emitError("missing right operand of binary operator");
935 else
936 emitError("missing left operand of binary operator");
937 return nullptr;
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700938 default:
939 if (lhs)
Uday Bondhugula76345202018-07-09 13:47:52 -0700940 emitError("missing right operand of binary operator");
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700941 else
942 emitError("expected affine expression");
943 return nullptr;
944 }
945}
946
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700947/// Parse affine expressions that are bare-id's, integer constants,
948/// parenthetical affine expressions, and affine op expressions that are a
949/// composition of those.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700950///
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700951/// All binary op's associate from left to right.
952///
953/// {add, sub} have lower precedence than {mul, div, and mod}.
954///
Uday Bondhugula76345202018-07-09 13:47:52 -0700955/// Add, sub'are themselves at the same precedence level. Mul, floordiv,
956/// ceildiv, and mod are at the same higher precedence level. Negation has
957/// higher precedence than any binary op.
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700958///
959/// llhs: the affine expression appearing on the left of the one being parsed.
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700960/// This function will return ((llhs llhsOp lhs) op rhs) if llhs is non null,
961/// and lhs op rhs otherwise; if there is no rhs, llhs llhsOp lhs is returned if
962/// llhs is non-null; otherwise lhs is returned. This is to deal with left
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700963/// associativity.
964///
965/// Eg: when the expression is e1 + e2*e3 + e4, with e1 as llhs, this function
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700966/// will return the affine expr equivalent of (e1 + (e2*e3)) + e4, where (e2*e3)
967/// will be parsed using parseAffineHighPrecOpExpr().
968AffineExpr *
969Parser::parseAffineLowPrecOpExpr(AffineExpr *llhs, AffineLowPrecOp llhsOp,
970 const AffineMapParserState &state) {
Uday Bondhugula76345202018-07-09 13:47:52 -0700971 AffineExpr *lhs;
972 if (!(lhs = parseAffineOperandExpr(llhs, state)))
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700973 return nullptr;
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700974
975 // Found an LHS. Deal with the ops.
976 AffineLowPrecOp lOp;
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700977 AffineHighPrecOp hOp;
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700978 if ((lOp = consumeIfLowPrecOp())) {
979 if (llhs) {
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700980 AffineExpr *sum = getBinaryAffineOpExpr(llhsOp, llhs, lhs);
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700981 return parseAffineLowPrecOpExpr(sum, lOp, state);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700982 }
983 // No LLHS, get RHS and form the expression.
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700984 return parseAffineLowPrecOpExpr(lhs, lOp, state);
985 }
986 if ((hOp = consumeIfHighPrecOp())) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700987 // We have a higher precedence op here. Get the rhs operand for the llhs
988 // through parseAffineHighPrecOpExpr.
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700989 AffineExpr *highRes = parseAffineHighPrecOpExpr(lhs, hOp, state);
990 if (!highRes)
991 return nullptr;
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700992 // If llhs is null, the product forms the first operand of the yet to be
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700993 // found expression. If non-null, the op to associate with llhs is llhsOp.
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700994 AffineExpr *expr =
Chris Lattner158e0a3e2018-07-08 20:51:38 -0700995 llhs ? getBinaryAffineOpExpr(llhsOp, llhs, highRes) : highRes;
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700996 // Recurse for subsequent low prec op's after the affine high prec op
997 // expression.
998 AffineLowPrecOp nextOp;
999 if ((nextOp = consumeIfLowPrecOp()))
1000 return parseAffineLowPrecOpExpr(expr, nextOp, state);
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001001 return expr;
1002 }
Uday Bondhugula3934d4d2018-07-09 09:00:25 -07001003 // Last operand in the expression list.
1004 if (llhs)
1005 return getBinaryAffineOpExpr(llhsOp, llhs, lhs);
1006 // No llhs, 'lhs' itself is the expression.
1007 return lhs;
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001008}
1009
1010/// Parse an affine expression.
Uday Bondhugula3934d4d2018-07-09 09:00:25 -07001011/// affine-expr ::= `(` affine-expr `)`
1012/// | `-` affine-expr
1013/// | affine-expr `+` affine-expr
1014/// | affine-expr `-` affine-expr
1015/// | affine-expr `*` affine-expr
1016/// | affine-expr `floordiv` affine-expr
1017/// | affine-expr `ceildiv` affine-expr
1018/// | affine-expr `mod` affine-expr
1019/// | bare-id
1020/// | integer-literal
1021///
1022/// Additional conditions are checked depending on the production. For eg., one
1023/// of the operands for `*` has to be either constant/symbolic; the second
1024/// operand for floordiv, ceildiv, and mod has to be a positive integer.
1025/// Use 'state' to check if valid identifiers appear in the expressoins.
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001026AffineExpr *Parser::parseAffineExpr(const AffineMapParserState &state) {
Uday Bondhugula76345202018-07-09 13:47:52 -07001027 return parseAffineLowPrecOpExpr(nullptr, AffineLowPrecOp::LNoOp, state);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001028}
1029
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001030/// Parse a dim or symbol from the lists appearing before the actual expressions
1031/// of the affine map. Update state to store the dimensional/symbolic
1032/// identifier. 'dim': whether it's the dim list or symbol list that is being
1033/// parsed.
1034ParseResult Parser::parseDimOrSymbolId(AffineMapParserState &state, bool dim) {
Chris Lattner48af7d12018-07-09 19:05:38 -07001035 if (getToken().isNot(Token::bare_identifier))
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001036 return emitError("expected bare identifier");
Chris Lattner48af7d12018-07-09 19:05:38 -07001037 auto sRef = getTokenSpelling();
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001038 consumeToken(Token::bare_identifier);
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001039 if (state.getDims().count(sRef) == 1)
1040 return emitError("dimensional identifier name reused");
1041 if (state.getSymbols().count(sRef) == 1)
1042 return emitError("symbolic identifier name reused");
1043 if (dim)
1044 state.addDim(sRef);
1045 else
1046 state.addSymbol(sRef);
1047 return ParseSuccess;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001048}
1049
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001050/// Parse the list of symbolic identifiers to an affine map.
1051ParseResult Parser::parseSymbolIdList(AffineMapParserState &state) {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001052 if (!consumeIf(Token::l_bracket)) return emitError("expected '['");
1053
1054 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001055 return parseDimOrSymbolId(state, false);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001056 };
1057 return parseCommaSeparatedList(Token::r_bracket, parseElt);
1058}
1059
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001060/// Parse the list of dimensional identifiers to an affine map.
1061ParseResult Parser::parseDimIdList(AffineMapParserState &state) {
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001062 if (!consumeIf(Token::l_paren))
1063 return emitError("expected '(' at start of dimensional identifiers list");
1064
1065 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001066 return parseDimOrSymbolId(state, true);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001067 };
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001068 return parseCommaSeparatedList(Token::r_paren, parseElt);
1069}
1070
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001071/// Parse an affine map definition.
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001072///
Uday Bondhugula3934d4d2018-07-09 09:00:25 -07001073/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
1074/// (`size` `(` dim-size (`,` dim-size)* `)`)?
1075/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001076///
Uday Bondhugula3934d4d2018-07-09 09:00:25 -07001077/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
1078// TODO(bondhugula): parse range size information.
Chris Lattner7121b802018-07-04 20:45:39 -07001079AffineMap *Parser::parseAffineMapInline(StringRef mapId) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001080 AffineMapParserState state;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001081
1082 // List of dimensional identifiers.
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001083 if (parseDimIdList(state))
Chris Lattner7121b802018-07-04 20:45:39 -07001084 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001085
1086 // Symbols are optional.
Chris Lattner48af7d12018-07-09 19:05:38 -07001087 if (getToken().is(Token::l_bracket)) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001088 if (parseSymbolIdList(state))
Chris Lattner7121b802018-07-04 20:45:39 -07001089 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001090 }
1091 if (!consumeIf(Token::arrow)) {
Chris Lattner7121b802018-07-04 20:45:39 -07001092 return (emitError("expected '->' or '['"), nullptr);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001093 }
1094 if (!consumeIf(Token::l_paren)) {
1095 emitError("expected '(' at start of affine map range");
Chris Lattner7121b802018-07-04 20:45:39 -07001096 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001097 }
1098
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001099 SmallVector<AffineExpr *, 4> exprs;
1100 auto parseElt = [&]() -> ParseResult {
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001101 auto *elt = parseAffineExpr(state);
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001102 ParseResult res = elt ? ParseSuccess : ParseFailure;
1103 exprs.push_back(elt);
1104 return res;
1105 };
1106
1107 // Parse a multi-dimensional affine expression (a comma-separated list of 1-d
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001108 // affine expressions); the list cannot be empty.
1109 // Grammar: multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
1110 if (parseCommaSeparatedList(Token::r_paren, parseElt, false))
Chris Lattner7121b802018-07-04 20:45:39 -07001111 return nullptr;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001112
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001113 // Parsed a valid affine map.
Chris Lattner7121b802018-07-04 20:45:39 -07001114 return AffineMap::get(state.getNumDims(), state.getNumSymbols(), exprs,
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001115 builder.getContext());
MLIR Teamf85a6262018-06-27 11:03:08 -07001116}
1117
1118//===----------------------------------------------------------------------===//
Chris Lattner78276e32018-07-07 15:48:26 -07001119// SSA
Chris Lattner4c95a502018-06-23 16:03:42 -07001120//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -07001121
Chris Lattner78276e32018-07-07 15:48:26 -07001122/// Parse a SSA operand for an instruction or statement.
1123///
1124/// ssa-use ::= ssa-id | ssa-constant
1125///
1126ParseResult Parser::parseSSAUse() {
Chris Lattner48af7d12018-07-09 19:05:38 -07001127 if (getToken().is(Token::percent_identifier)) {
1128 StringRef name = getTokenSpelling().drop_front();
Chris Lattner78276e32018-07-07 15:48:26 -07001129 consumeToken(Token::percent_identifier);
1130 // TODO: Return this use.
1131 (void)name;
1132 return ParseSuccess;
1133 }
1134
1135 // TODO: Parse SSA constants.
1136
1137 return emitError("expected SSA operand");
1138}
1139
1140/// Parse a (possibly empty) list of SSA operands.
1141///
1142/// ssa-use-list ::= ssa-use (`,` ssa-use)*
1143/// ssa-use-list-opt ::= ssa-use-list?
1144///
1145ParseResult Parser::parseOptionalSSAUseList(Token::Kind endToken) {
1146 // TODO: Build and return this.
1147 return parseCommaSeparatedList(
1148 endToken, [&]() -> ParseResult { return parseSSAUse(); });
1149}
1150
1151/// Parse an SSA use with an associated type.
1152///
1153/// ssa-use-and-type ::= ssa-use `:` type
1154ParseResult Parser::parseSSAUseAndType() {
1155 if (parseSSAUse())
1156 return ParseFailure;
1157
1158 if (!consumeIf(Token::colon))
1159 return emitError("expected ':' and type for SSA operand");
1160
1161 if (!parseType())
1162 return ParseFailure;
1163
1164 return ParseSuccess;
1165}
1166
1167/// Parse a (possibly empty) list of SSA operands with types.
1168///
1169/// ssa-use-and-type-list ::= ssa-use-and-type (`,` ssa-use-and-type)*
1170///
1171ParseResult Parser::parseOptionalSSAUseAndTypeList(Token::Kind endToken) {
1172 // TODO: Build and return this.
1173 return parseCommaSeparatedList(
1174 endToken, [&]() -> ParseResult { return parseSSAUseAndType(); });
1175}
1176
1177//===----------------------------------------------------------------------===//
1178// Functions
1179//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -07001180
1181/// Parse a function signature, starting with a name and including the parameter
1182/// list.
1183///
1184/// argument-list ::= type (`,` type)* | /*empty*/
1185/// function-signature ::= function-id `(` argument-list `)` (`->` type-list)?
1186///
Chris Lattnerf7e22732018-06-22 22:03:48 -07001187ParseResult Parser::parseFunctionSignature(StringRef &name,
1188 FunctionType *&type) {
Chris Lattner48af7d12018-07-09 19:05:38 -07001189 if (getToken().isNot(Token::at_identifier))
Chris Lattnere79379a2018-06-22 10:39:19 -07001190 return emitError("expected a function identifier like '@foo'");
1191
Chris Lattner48af7d12018-07-09 19:05:38 -07001192 name = getTokenSpelling().drop_front();
Chris Lattnere79379a2018-06-22 10:39:19 -07001193 consumeToken(Token::at_identifier);
1194
Chris Lattner48af7d12018-07-09 19:05:38 -07001195 if (getToken().isNot(Token::l_paren))
Chris Lattnere79379a2018-06-22 10:39:19 -07001196 return emitError("expected '(' in function signature");
Chris Lattnere79379a2018-06-22 10:39:19 -07001197
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -07001198 SmallVector<Type*, 4> arguments;
1199 if (parseTypeList(arguments))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001200 return ParseFailure;
Chris Lattnere79379a2018-06-22 10:39:19 -07001201
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001202 // Parse the return type if present.
Chris Lattnerf7e22732018-06-22 22:03:48 -07001203 SmallVector<Type*, 4> results;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001204 if (consumeIf(Token::arrow)) {
Chris Lattnerf7e22732018-06-22 22:03:48 -07001205 if (parseTypeList(results))
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001206 return ParseFailure;
Chris Lattnerbb8fafc2018-06-22 15:52:02 -07001207 }
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001208 type = builder.getFunctionType(arguments, results);
Chris Lattnere79379a2018-06-22 10:39:19 -07001209 return ParseSuccess;
1210}
1211
Chris Lattnere79379a2018-06-22 10:39:19 -07001212/// External function declarations.
1213///
1214/// ext-func ::= `extfunc` function-signature
1215///
1216ParseResult Parser::parseExtFunc() {
1217 consumeToken(Token::kw_extfunc);
1218
1219 StringRef name;
Chris Lattnerf7e22732018-06-22 22:03:48 -07001220 FunctionType *type = nullptr;
1221 if (parseFunctionSignature(name, type))
Chris Lattnere79379a2018-06-22 10:39:19 -07001222 return ParseFailure;
1223
Chris Lattnere79379a2018-06-22 10:39:19 -07001224 // Okay, the external function definition was parsed correctly.
Chris Lattner48af7d12018-07-09 19:05:38 -07001225 getModule()->functionList.push_back(new ExtFunction(name, type));
Chris Lattnere79379a2018-06-22 10:39:19 -07001226 return ParseSuccess;
1227}
1228
Chris Lattner48af7d12018-07-09 19:05:38 -07001229//===----------------------------------------------------------------------===//
1230// CFG Functions
1231//===----------------------------------------------------------------------===//
Chris Lattnere79379a2018-06-22 10:39:19 -07001232
Chris Lattner4c95a502018-06-23 16:03:42 -07001233namespace {
Chris Lattner48af7d12018-07-09 19:05:38 -07001234/// This is a specialized parser for CFGFunction's, maintaining the state
1235/// transient to their bodies.
1236class CFGFunctionParser : public Parser {
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001237public:
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001238 CFGFunction *function;
1239 llvm::StringMap<std::pair<BasicBlock*, SMLoc>> blocksByName;
Chris Lattner48af7d12018-07-09 19:05:38 -07001240
1241 /// This builder intentionally shadows the builder in the base class, with a
1242 /// more specific builder type.
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001243 CFGFuncBuilder builder;
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001244
Chris Lattner48af7d12018-07-09 19:05:38 -07001245 CFGFunctionParser(ParserState &state, CFGFunction *function)
1246 : Parser(state), function(function), builder(function) {}
Chris Lattner4c95a502018-06-23 16:03:42 -07001247
1248 /// Get the basic block with the specified name, creating it if it doesn't
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001249 /// already exist. The location specified is the point of use, which allows
1250 /// us to diagnose references to blocks that are not defined precisely.
1251 BasicBlock *getBlockNamed(StringRef name, SMLoc loc) {
1252 auto &blockAndLoc = blocksByName[name];
1253 if (!blockAndLoc.first) {
Chris Lattner3a467cc2018-07-01 20:28:00 -07001254 blockAndLoc.first = new BasicBlock();
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001255 blockAndLoc.second = loc;
Chris Lattner4c95a502018-06-23 16:03:42 -07001256 }
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001257 return blockAndLoc.first;
Chris Lattner4c95a502018-06-23 16:03:42 -07001258 }
Chris Lattner48af7d12018-07-09 19:05:38 -07001259
1260 ParseResult parseFunctionBody();
1261 ParseResult parseBasicBlock();
1262 OperationInst *parseCFGOperation();
1263 TerminatorInst *parseTerminator();
Chris Lattner4c95a502018-06-23 16:03:42 -07001264};
1265} // end anonymous namespace
1266
1267
1268/// CFG function declarations.
1269///
1270/// cfg-func ::= `cfgfunc` function-signature `{` basic-block+ `}`
1271///
1272ParseResult Parser::parseCFGFunc() {
1273 consumeToken(Token::kw_cfgfunc);
1274
1275 StringRef name;
1276 FunctionType *type = nullptr;
1277 if (parseFunctionSignature(name, type))
1278 return ParseFailure;
1279
Chris Lattner4c95a502018-06-23 16:03:42 -07001280 // Okay, the CFG function signature was parsed correctly, create the function.
1281 auto function = new CFGFunction(name, type);
1282
Chris Lattner48af7d12018-07-09 19:05:38 -07001283 CFGFunctionParser cfgFuncParser(state, function);
1284 return cfgFuncParser.parseFunctionBody();
1285}
Chris Lattner4c95a502018-06-23 16:03:42 -07001286
Chris Lattner48af7d12018-07-09 19:05:38 -07001287ParseResult CFGFunctionParser::parseFunctionBody() {
1288 if (!consumeIf(Token::l_brace))
1289 return emitError("expected '{' in CFG function");
1290
1291 // Make sure we have at least one block.
1292 if (getToken().is(Token::r_brace))
1293 return emitError("CFG functions must have at least one basic block");
Chris Lattner4c95a502018-06-23 16:03:42 -07001294
1295 // Parse the list of blocks.
1296 while (!consumeIf(Token::r_brace))
Chris Lattner48af7d12018-07-09 19:05:38 -07001297 if (parseBasicBlock())
Chris Lattner4c95a502018-06-23 16:03:42 -07001298 return ParseFailure;
1299
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001300 // Verify that all referenced blocks were defined. Iteration over a
1301 // StringMap isn't determinstic, but this is good enough for our purposes.
Chris Lattner48af7d12018-07-09 19:05:38 -07001302 for (auto &elt : blocksByName) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001303 auto *bb = elt.second.first;
Chris Lattner3a467cc2018-07-01 20:28:00 -07001304 if (!bb->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001305 return emitError(elt.second.second,
1306 "reference to an undefined basic block '" +
1307 elt.first() + "'");
1308 }
1309
Chris Lattner48af7d12018-07-09 19:05:38 -07001310 getModule()->functionList.push_back(function);
Chris Lattner4c95a502018-06-23 16:03:42 -07001311 return ParseSuccess;
1312}
1313
1314/// Basic block declaration.
1315///
1316/// basic-block ::= bb-label instruction* terminator-stmt
1317/// bb-label ::= bb-id bb-arg-list? `:`
1318/// bb-id ::= bare-id
1319/// bb-arg-list ::= `(` ssa-id-and-type-list? `)`
1320///
Chris Lattner48af7d12018-07-09 19:05:38 -07001321ParseResult CFGFunctionParser::parseBasicBlock() {
1322 SMLoc nameLoc = getToken().getLoc();
1323 auto name = getTokenSpelling();
Chris Lattner4c95a502018-06-23 16:03:42 -07001324 if (!consumeIf(Token::bare_identifier))
1325 return emitError("expected basic block name");
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001326
Chris Lattner48af7d12018-07-09 19:05:38 -07001327 auto *block = getBlockNamed(name, nameLoc);
Chris Lattner4c95a502018-06-23 16:03:42 -07001328
1329 // If this block has already been parsed, then this is a redefinition with the
1330 // same block name.
Chris Lattner3a467cc2018-07-01 20:28:00 -07001331 if (block->getFunction())
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001332 return emitError(nameLoc, "redefinition of block '" + name.str() + "'");
1333
Chris Lattner3a467cc2018-07-01 20:28:00 -07001334 // Add the block to the function.
Chris Lattner48af7d12018-07-09 19:05:38 -07001335 function->push_back(block);
Chris Lattner4c95a502018-06-23 16:03:42 -07001336
Chris Lattner78276e32018-07-07 15:48:26 -07001337 // If an argument list is present, parse it.
1338 if (consumeIf(Token::l_paren)) {
1339 if (parseOptionalSSAUseAndTypeList(Token::r_paren))
1340 return ParseFailure;
1341
1342 // TODO: attach it.
1343 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001344
1345 if (!consumeIf(Token::colon))
1346 return emitError("expected ':' after basic block name");
1347
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001348 // Set the insertion point to the block we want to insert new operations into.
Chris Lattner48af7d12018-07-09 19:05:38 -07001349 builder.setInsertionPoint(block);
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001350
Chris Lattnered65a732018-06-28 20:45:33 -07001351 // Parse the list of operations that make up the body of the block.
Chris Lattner48af7d12018-07-09 19:05:38 -07001352 while (getToken().isNot(Token::kw_return, Token::kw_br)) {
1353 auto loc = getToken().getLoc();
1354 auto *inst = parseCFGOperation();
Chris Lattner3a467cc2018-07-01 20:28:00 -07001355 if (!inst)
Chris Lattnered65a732018-06-28 20:45:33 -07001356 return ParseFailure;
Chris Lattner3a467cc2018-07-01 20:28:00 -07001357
Chris Lattner21e67f62018-07-06 10:46:19 -07001358 // We just parsed an operation. If it is a recognized one, verify that it
1359 // is structurally as we expect. If not, produce an error with a reasonable
1360 // source location.
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001361 if (auto *opInfo = inst->getAbstractOperation(builder.getContext()))
Chris Lattner21e67f62018-07-06 10:46:19 -07001362 if (auto error = opInfo->verifyInvariants(inst))
1363 return emitError(loc, error);
Chris Lattnered65a732018-06-28 20:45:33 -07001364 }
Chris Lattner4c95a502018-06-23 16:03:42 -07001365
Chris Lattner48af7d12018-07-09 19:05:38 -07001366 auto *term = parseTerminator();
Chris Lattner3a467cc2018-07-01 20:28:00 -07001367 if (!term)
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001368 return ParseFailure;
Chris Lattner4c95a502018-06-23 16:03:42 -07001369
1370 return ParseSuccess;
1371}
1372
Chris Lattnered65a732018-06-28 20:45:33 -07001373/// Parse the CFG operation.
1374///
1375/// TODO(clattner): This is a change from the MLIR spec as written, it is an
1376/// experiment that will eliminate "builtin" instructions as a thing.
1377///
1378/// cfg-operation ::=
1379/// (ssa-id `=`)? string '(' ssa-use-list? ')' attribute-dict?
1380/// `:` function-type
1381///
Chris Lattner48af7d12018-07-09 19:05:38 -07001382OperationInst *CFGFunctionParser::parseCFGOperation() {
Chris Lattner78276e32018-07-07 15:48:26 -07001383 StringRef resultID;
Chris Lattner48af7d12018-07-09 19:05:38 -07001384 if (getToken().is(Token::percent_identifier)) {
1385 resultID = getTokenSpelling().drop_front();
Chris Lattner78276e32018-07-07 15:48:26 -07001386 consumeToken();
1387 if (!consumeIf(Token::equal))
1388 return (emitError("expected '=' after SSA name"), nullptr);
1389 }
Chris Lattnered65a732018-06-28 20:45:33 -07001390
Chris Lattner48af7d12018-07-09 19:05:38 -07001391 if (getToken().isNot(Token::string))
Chris Lattner3a467cc2018-07-01 20:28:00 -07001392 return (emitError("expected operation name in quotes"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001393
Chris Lattner48af7d12018-07-09 19:05:38 -07001394 auto name = getToken().getStringValue();
Chris Lattnered65a732018-06-28 20:45:33 -07001395 if (name.empty())
Chris Lattner3a467cc2018-07-01 20:28:00 -07001396 return (emitError("empty operation name is invalid"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001397
1398 consumeToken(Token::string);
1399
1400 if (!consumeIf(Token::l_paren))
Chris Lattner7121b802018-07-04 20:45:39 -07001401 return (emitError("expected '(' to start operand list"), nullptr);
Chris Lattnered65a732018-06-28 20:45:33 -07001402
Chris Lattner78276e32018-07-07 15:48:26 -07001403 // Parse the operand list.
1404 parseOptionalSSAUseList(Token::r_paren);
Chris Lattner7121b802018-07-04 20:45:39 -07001405
1406 SmallVector<NamedAttribute, 4> attributes;
Chris Lattner48af7d12018-07-09 19:05:38 -07001407 if (getToken().is(Token::l_brace)) {
Chris Lattner7121b802018-07-04 20:45:39 -07001408 if (parseAttributeDict(attributes))
1409 return nullptr;
1410 }
Chris Lattnered65a732018-06-28 20:45:33 -07001411
Chris Lattner78276e32018-07-07 15:48:26 -07001412 // TODO: Don't drop result name and operand names on the floor.
Chris Lattner158e0a3e2018-07-08 20:51:38 -07001413 auto nameId = Identifier::get(name, builder.getContext());
Chris Lattner48af7d12018-07-09 19:05:38 -07001414 return builder.createOperation(nameId, attributes);
Chris Lattnered65a732018-06-28 20:45:33 -07001415}
1416
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001417/// Parse the terminator instruction for a basic block.
1418///
1419/// terminator-stmt ::= `br` bb-id branch-use-list?
1420/// branch-use-list ::= `(` ssa-use-and-type-list? `)`
1421/// terminator-stmt ::=
1422/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id branch-use-list?
1423/// terminator-stmt ::= `return` ssa-use-and-type-list?
1424///
Chris Lattner48af7d12018-07-09 19:05:38 -07001425TerminatorInst *CFGFunctionParser::parseTerminator() {
1426 switch (getToken().getKind()) {
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001427 default:
Chris Lattner3a467cc2018-07-01 20:28:00 -07001428 return (emitError("expected terminator at end of basic block"), nullptr);
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001429
1430 case Token::kw_return:
1431 consumeToken(Token::kw_return);
Chris Lattner48af7d12018-07-09 19:05:38 -07001432 return builder.createReturnInst();
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001433
1434 case Token::kw_br: {
1435 consumeToken(Token::kw_br);
Chris Lattner48af7d12018-07-09 19:05:38 -07001436 auto destBB = getBlockNamed(getTokenSpelling(), getToken().getLoc());
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001437 if (!consumeIf(Token::bare_identifier))
Chris Lattner3a467cc2018-07-01 20:28:00 -07001438 return (emitError("expected basic block name"), nullptr);
Chris Lattner48af7d12018-07-09 19:05:38 -07001439 return builder.createBranchInst(destBB);
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001440 }
Chris Lattner78276e32018-07-07 15:48:26 -07001441 // TODO: cond_br.
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001442 }
1443}
1444
Chris Lattner48af7d12018-07-09 19:05:38 -07001445//===----------------------------------------------------------------------===//
1446// ML Functions
1447//===----------------------------------------------------------------------===//
1448
1449namespace {
1450/// Refined parser for MLFunction bodies.
1451class MLFunctionParser : public Parser {
1452public:
1453 MLFunction *function;
1454
1455 /// This builder intentionally shadows the builder in the base class, with a
1456 /// more specific builder type.
1457 // TODO: MLFuncBuilder builder;
1458
1459 MLFunctionParser(ParserState &state, MLFunction *function)
1460 : Parser(state), function(function) {}
1461
1462 ParseResult parseFunctionBody();
1463 Statement *parseStatement(ParentType parent);
1464 ForStmt *parseForStmt(ParentType parent);
1465 IfStmt *parseIfStmt(ParentType parent);
1466 ParseResult parseNestedStatements(NodeStmt *parent);
1467};
1468} // end anonymous namespace
1469
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001470/// ML function declarations.
1471///
1472/// ml-func ::= `mlfunc` ml-func-signature `{` ml-stmt* ml-return-stmt `}`
1473///
1474ParseResult Parser::parseMLFunc() {
1475 consumeToken(Token::kw_mlfunc);
1476
1477 StringRef name;
1478 FunctionType *type = nullptr;
1479
1480 // FIXME: Parse ML function signature (args + types)
1481 // by passing pointer to SmallVector<identifier> into parseFunctionSignature
1482 if (parseFunctionSignature(name, type))
1483 return ParseFailure;
1484
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001485 // Okay, the ML function signature was parsed correctly, create the function.
1486 auto function = new MLFunction(name, type);
1487
Chris Lattner48af7d12018-07-09 19:05:38 -07001488 MLFunctionParser mlFuncParser(state, function);
1489 return mlFuncParser.parseFunctionBody();
1490}
1491
1492ParseResult MLFunctionParser::parseFunctionBody() {
1493 if (!consumeIf(Token::l_brace))
1494 return emitError("expected '{' in ML function");
1495
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001496 // Make sure we have at least one statement.
Chris Lattner48af7d12018-07-09 19:05:38 -07001497 if (getToken().is(Token::r_brace))
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001498 return emitError("ML function must end with return statement");
1499
1500 // Parse the list of instructions.
1501 while (!consumeIf(Token::kw_return)) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001502 auto *stmt = parseStatement(function);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001503 if (!stmt)
1504 return ParseFailure;
1505 function->stmtList.push_back(stmt);
1506 }
1507
1508 // TODO: parse return statement operands
1509 if (!consumeIf(Token::r_brace))
1510 emitError("expected '}' in ML function");
1511
Chris Lattner48af7d12018-07-09 19:05:38 -07001512 getModule()->functionList.push_back(function);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001513
1514 return ParseSuccess;
1515}
1516
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001517/// Statement.
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001518///
Chris Lattner48af7d12018-07-09 19:05:38 -07001519/// ml-stmt ::= instruction | ml-for-stmt | ml-if-stmt
1520///
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001521/// TODO: fix terminology in MLSpec document. ML functions
1522/// contain operation statements, not instructions.
1523///
Chris Lattner48af7d12018-07-09 19:05:38 -07001524Statement *MLFunctionParser::parseStatement(ParentType parent) {
1525 switch (getToken().getKind()) {
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001526 default:
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001527 //TODO: parse OperationStmt
1528 return (emitError("expected statement"), nullptr);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001529
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001530 case Token::kw_for:
1531 return parseForStmt(parent);
1532
1533 case Token::kw_if:
1534 return parseIfStmt(parent);
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001535 }
1536}
Chris Lattnerf6d80a02018-06-24 11:18:29 -07001537
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001538/// For statement.
1539///
Chris Lattner48af7d12018-07-09 19:05:38 -07001540/// ml-for-stmt ::= `for` ssa-id `=` lower-bound `to` upper-bound
1541/// (`step` integer-literal)? `{` ml-stmt* `}`
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001542///
Chris Lattner48af7d12018-07-09 19:05:38 -07001543ForStmt *MLFunctionParser::parseForStmt(ParentType parent) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001544 consumeToken(Token::kw_for);
1545
1546 //TODO: parse loop header
1547 ForStmt *stmt = new ForStmt(parent);
1548 if (parseNestedStatements(stmt)) {
1549 delete stmt;
1550 return nullptr;
1551 }
1552 return stmt;
1553}
1554
1555/// If statement.
1556///
Chris Lattner48af7d12018-07-09 19:05:38 -07001557/// ml-if-head ::= `if` ml-if-cond `{` ml-stmt* `}`
1558/// | ml-if-head `else` `if` ml-if-cond `{` ml-stmt* `}`
1559/// ml-if-stmt ::= ml-if-head
1560/// | ml-if-head `else` `{` ml-stmt* `}`
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001561///
Chris Lattner48af7d12018-07-09 19:05:38 -07001562IfStmt *
1563MLFunctionParser::parseIfStmt(PointerUnion<MLFunction *, NodeStmt *> parent) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001564 consumeToken(Token::kw_if);
1565
1566 //TODO: parse condition
1567 IfStmt *stmt = new IfStmt(parent);
1568 if (parseNestedStatements(stmt)) {
1569 delete stmt;
1570 return nullptr;
1571 }
1572
1573 int clauseNum = 0;
1574 while (consumeIf(Token::kw_else)) {
1575 if (consumeIf(Token::kw_if)) {
1576 //TODO: parse condition
1577 }
1578 ElseClause * clause = new ElseClause(stmt, clauseNum);
1579 ++clauseNum;
1580 if (parseNestedStatements(clause)) {
1581 delete clause;
1582 return nullptr;
1583 }
1584 }
1585
1586 return stmt;
1587}
1588
1589///
1590/// Parse `{` ml-stmt* `}`
1591///
Chris Lattner48af7d12018-07-09 19:05:38 -07001592ParseResult MLFunctionParser::parseNestedStatements(NodeStmt *parent) {
Tatiana Shpeismanbf079c92018-07-03 17:51:28 -07001593 if (!consumeIf(Token::l_brace))
1594 return emitError("expected '{' before statement list");
1595
1596 if (consumeIf(Token::r_brace)) {
1597 // TODO: parse OperationStmt
1598 return ParseSuccess;
1599 }
1600
1601 while (!consumeIf(Token::r_brace)) {
1602 auto *stmt = parseStatement(parent);
1603 if (!stmt)
1604 return ParseFailure;
1605 parent->children.push_back(stmt);
1606 }
1607
1608 return ParseSuccess;
1609}
1610
Chris Lattner4c95a502018-06-23 16:03:42 -07001611//===----------------------------------------------------------------------===//
1612// Top-level entity parsing.
1613//===----------------------------------------------------------------------===//
1614
Chris Lattnere79379a2018-06-22 10:39:19 -07001615/// This is the top-level module parser.
1616Module *Parser::parseModule() {
1617 while (1) {
Chris Lattner48af7d12018-07-09 19:05:38 -07001618 switch (getToken().getKind()) {
Chris Lattnere79379a2018-06-22 10:39:19 -07001619 default:
1620 emitError("expected a top level entity");
1621 return nullptr;
1622
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001623 // If we got to the end of the file, then we're done.
Chris Lattnere79379a2018-06-22 10:39:19 -07001624 case Token::eof:
Chris Lattner48af7d12018-07-09 19:05:38 -07001625 return state.module.release();
Chris Lattnere79379a2018-06-22 10:39:19 -07001626
1627 // If we got an error token, then the lexer already emitted an error, just
1628 // stop. Someday we could introduce error recovery if there was demand for
1629 // it.
1630 case Token::error:
1631 return nullptr;
1632
1633 case Token::kw_extfunc:
Chris Lattner4c95a502018-06-23 16:03:42 -07001634 if (parseExtFunc()) return nullptr;
Chris Lattnere79379a2018-06-22 10:39:19 -07001635 break;
1636
Chris Lattner4c95a502018-06-23 16:03:42 -07001637 case Token::kw_cfgfunc:
1638 if (parseCFGFunc()) return nullptr;
1639 break;
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001640
Chris Lattner78276e32018-07-07 15:48:26 -07001641 case Token::hash_identifier:
MLIR Teamf85a6262018-06-27 11:03:08 -07001642 if (parseAffineMapDef()) return nullptr;
1643 break;
Chris Lattner4c95a502018-06-23 16:03:42 -07001644
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -07001645 case Token::kw_mlfunc:
1646 if (parseMLFunc()) return nullptr;
1647 break;
1648
Uday Bondhugula015cbb12018-07-03 20:16:08 -07001649 // TODO: affine entity declarations, etc.
Chris Lattnere79379a2018-06-22 10:39:19 -07001650 }
1651 }
1652}
1653
1654//===----------------------------------------------------------------------===//
1655
Jacques Pienaar7b829702018-07-03 13:24:09 -07001656void mlir::defaultErrorReporter(const llvm::SMDiagnostic &error) {
1657 const auto &sourceMgr = *error.getSourceMgr();
1658 sourceMgr.PrintMessage(error.getLoc(), error.getKind(), error.getMessage());
1659}
1660
Chris Lattnere79379a2018-06-22 10:39:19 -07001661/// This parses the file specified by the indicated SourceMgr and returns an
1662/// MLIR module if it was valid. If not, it emits diagnostics and returns null.
Jacques Pienaar9c411be2018-06-24 19:17:35 -07001663Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context,
Jacques Pienaar7b829702018-07-03 13:24:09 -07001664 SMDiagnosticHandlerTy errorReporter) {
Chris Lattner48af7d12018-07-09 19:05:38 -07001665 ParserState state(sourceMgr, context,
1666 errorReporter ? std::move(errorReporter)
1667 : defaultErrorReporter);
1668 auto *result = Parser(state).parseModule();
Chris Lattner21e67f62018-07-06 10:46:19 -07001669
1670 // Make sure the parse module has no other structural problems detected by the
1671 // verifier.
1672 if (result)
1673 result->verify();
1674 return result;
Chris Lattnere79379a2018-06-22 10:39:19 -07001675}