File: | build/source/mlir/lib/AsmParser/Parser.cpp |
Warning: | line 1227, column 5 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- Parser.cpp - MLIR Parser Implementation ----------------------------===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | // | |||
9 | // This file implements the parser for the MLIR textual form. | |||
10 | // | |||
11 | //===----------------------------------------------------------------------===// | |||
12 | ||||
13 | #include "Parser.h" | |||
14 | #include "AsmParserImpl.h" | |||
15 | #include "mlir/AsmParser/AsmParser.h" | |||
16 | #include "mlir/AsmParser/AsmParserState.h" | |||
17 | #include "mlir/AsmParser/CodeComplete.h" | |||
18 | #include "mlir/IR/AffineMap.h" | |||
19 | #include "mlir/IR/AsmState.h" | |||
20 | #include "mlir/IR/BuiltinOps.h" | |||
21 | #include "mlir/IR/Dialect.h" | |||
22 | #include "mlir/IR/Verifier.h" | |||
23 | #include "llvm/ADT/DenseMap.h" | |||
24 | #include "llvm/ADT/ScopeExit.h" | |||
25 | #include "llvm/ADT/StringSet.h" | |||
26 | #include "llvm/ADT/bit.h" | |||
27 | #include "llvm/Support/Endian.h" | |||
28 | #include "llvm/Support/PrettyStackTrace.h" | |||
29 | #include "llvm/Support/SourceMgr.h" | |||
30 | #include <algorithm> | |||
31 | #include <optional> | |||
32 | ||||
33 | using namespace mlir; | |||
34 | using namespace mlir::detail; | |||
35 | ||||
36 | //===----------------------------------------------------------------------===// | |||
37 | // CodeComplete | |||
38 | //===----------------------------------------------------------------------===// | |||
39 | ||||
40 | AsmParserCodeCompleteContext::~AsmParserCodeCompleteContext() = default; | |||
41 | ||||
42 | //===----------------------------------------------------------------------===// | |||
43 | // Parser | |||
44 | //===----------------------------------------------------------------------===// | |||
45 | ||||
46 | /// Parse a list of comma-separated items with an optional delimiter. If a | |||
47 | /// delimiter is provided, then an empty list is allowed. If not, then at | |||
48 | /// least one element will be parsed. | |||
49 | ParseResult | |||
50 | Parser::parseCommaSeparatedList(Delimiter delimiter, | |||
51 | function_ref<ParseResult()> parseElementFn, | |||
52 | StringRef contextMessage) { | |||
53 | switch (delimiter) { | |||
54 | case Delimiter::None: | |||
55 | break; | |||
56 | case Delimiter::OptionalParen: | |||
57 | if (getToken().isNot(Token::l_paren)) | |||
58 | return success(); | |||
59 | [[fallthrough]]; | |||
60 | case Delimiter::Paren: | |||
61 | if (parseToken(Token::l_paren, "expected '('" + contextMessage)) | |||
62 | return failure(); | |||
63 | // Check for empty list. | |||
64 | if (consumeIf(Token::r_paren)) | |||
65 | return success(); | |||
66 | break; | |||
67 | case Delimiter::OptionalLessGreater: | |||
68 | // Check for absent list. | |||
69 | if (getToken().isNot(Token::less)) | |||
70 | return success(); | |||
71 | [[fallthrough]]; | |||
72 | case Delimiter::LessGreater: | |||
73 | if (parseToken(Token::less, "expected '<'" + contextMessage)) | |||
74 | return success(); | |||
75 | // Check for empty list. | |||
76 | if (consumeIf(Token::greater)) | |||
77 | return success(); | |||
78 | break; | |||
79 | case Delimiter::OptionalSquare: | |||
80 | if (getToken().isNot(Token::l_square)) | |||
81 | return success(); | |||
82 | [[fallthrough]]; | |||
83 | case Delimiter::Square: | |||
84 | if (parseToken(Token::l_square, "expected '['" + contextMessage)) | |||
85 | return failure(); | |||
86 | // Check for empty list. | |||
87 | if (consumeIf(Token::r_square)) | |||
88 | return success(); | |||
89 | break; | |||
90 | case Delimiter::OptionalBraces: | |||
91 | if (getToken().isNot(Token::l_brace)) | |||
92 | return success(); | |||
93 | [[fallthrough]]; | |||
94 | case Delimiter::Braces: | |||
95 | if (parseToken(Token::l_brace, "expected '{'" + contextMessage)) | |||
96 | return failure(); | |||
97 | // Check for empty list. | |||
98 | if (consumeIf(Token::r_brace)) | |||
99 | return success(); | |||
100 | break; | |||
101 | } | |||
102 | ||||
103 | // Non-empty case starts with an element. | |||
104 | if (parseElementFn()) | |||
105 | return failure(); | |||
106 | ||||
107 | // Otherwise we have a list of comma separated elements. | |||
108 | while (consumeIf(Token::comma)) { | |||
109 | if (parseElementFn()) | |||
110 | return failure(); | |||
111 | } | |||
112 | ||||
113 | switch (delimiter) { | |||
114 | case Delimiter::None: | |||
115 | return success(); | |||
116 | case Delimiter::OptionalParen: | |||
117 | case Delimiter::Paren: | |||
118 | return parseToken(Token::r_paren, "expected ')'" + contextMessage); | |||
119 | case Delimiter::OptionalLessGreater: | |||
120 | case Delimiter::LessGreater: | |||
121 | return parseToken(Token::greater, "expected '>'" + contextMessage); | |||
122 | case Delimiter::OptionalSquare: | |||
123 | case Delimiter::Square: | |||
124 | return parseToken(Token::r_square, "expected ']'" + contextMessage); | |||
125 | case Delimiter::OptionalBraces: | |||
126 | case Delimiter::Braces: | |||
127 | return parseToken(Token::r_brace, "expected '}'" + contextMessage); | |||
128 | } | |||
129 | llvm_unreachable("Unknown delimiter")::llvm::llvm_unreachable_internal("Unknown delimiter", "mlir/lib/AsmParser/Parser.cpp" , 129); | |||
130 | } | |||
131 | ||||
132 | /// Parse a comma-separated list of elements, terminated with an arbitrary | |||
133 | /// token. This allows empty lists if allowEmptyList is true. | |||
134 | /// | |||
135 | /// abstract-list ::= rightToken // if allowEmptyList == true | |||
136 | /// abstract-list ::= element (',' element)* rightToken | |||
137 | /// | |||
138 | ParseResult | |||
139 | Parser::parseCommaSeparatedListUntil(Token::Kind rightToken, | |||
140 | function_ref<ParseResult()> parseElement, | |||
141 | bool allowEmptyList) { | |||
142 | // Handle the empty case. | |||
143 | if (getToken().is(rightToken)) { | |||
144 | if (!allowEmptyList) | |||
145 | return emitWrongTokenError("expected list element"); | |||
146 | consumeToken(rightToken); | |||
147 | return success(); | |||
148 | } | |||
149 | ||||
150 | if (parseCommaSeparatedList(parseElement) || | |||
151 | parseToken(rightToken, "expected ',' or '" + | |||
152 | Token::getTokenSpelling(rightToken) + "'")) | |||
153 | return failure(); | |||
154 | ||||
155 | return success(); | |||
156 | } | |||
157 | ||||
158 | InFlightDiagnostic Parser::emitError(const Twine &message) { | |||
159 | auto loc = state.curToken.getLoc(); | |||
160 | if (state.curToken.isNot(Token::eof)) | |||
161 | return emitError(loc, message); | |||
162 | ||||
163 | // If the error is to be emitted at EOF, move it back one character. | |||
164 | return emitError(SMLoc::getFromPointer(loc.getPointer() - 1), message); | |||
165 | } | |||
166 | ||||
167 | InFlightDiagnostic Parser::emitError(SMLoc loc, const Twine &message) { | |||
168 | auto diag = mlir::emitError(getEncodedSourceLocation(loc), message); | |||
169 | ||||
170 | // If we hit a parse error in response to a lexer error, then the lexer | |||
171 | // already reported the error. | |||
172 | if (getToken().is(Token::error)) | |||
173 | diag.abandon(); | |||
174 | return diag; | |||
175 | } | |||
176 | ||||
177 | /// Emit an error about a "wrong token". If the current token is at the | |||
178 | /// start of a source line, this will apply heuristics to back up and report | |||
179 | /// the error at the end of the previous line, which is where the expected | |||
180 | /// token is supposed to be. | |||
181 | InFlightDiagnostic Parser::emitWrongTokenError(const Twine &message) { | |||
182 | auto loc = state.curToken.getLoc(); | |||
183 | ||||
184 | // If the error is to be emitted at EOF, move it back one character. | |||
185 | if (state.curToken.is(Token::eof)) | |||
186 | loc = SMLoc::getFromPointer(loc.getPointer() - 1); | |||
187 | ||||
188 | // This is the location we were originally asked to report the error at. | |||
189 | auto originalLoc = loc; | |||
190 | ||||
191 | // Determine if the token is at the start of the current line. | |||
192 | const char *bufferStart = state.lex.getBufferBegin(); | |||
193 | const char *curPtr = loc.getPointer(); | |||
194 | ||||
195 | // Use this StringRef to keep track of what we are going to back up through, | |||
196 | // it provides nicer string search functions etc. | |||
197 | StringRef startOfBuffer(bufferStart, curPtr - bufferStart); | |||
198 | ||||
199 | // Back up over entirely blank lines. | |||
200 | while (true) { | |||
201 | // Back up until we see a \n, but don't look past the buffer start. | |||
202 | startOfBuffer = startOfBuffer.rtrim(" \t"); | |||
203 | ||||
204 | // For tokens with no preceding source line, just emit at the original | |||
205 | // location. | |||
206 | if (startOfBuffer.empty()) | |||
207 | return emitError(originalLoc, message); | |||
208 | ||||
209 | // If we found something that isn't the end of line, then we're done. | |||
210 | if (startOfBuffer.back() != '\n' && startOfBuffer.back() != '\r') | |||
211 | return emitError(SMLoc::getFromPointer(startOfBuffer.end()), message); | |||
212 | ||||
213 | // Drop the \n so we emit the diagnostic at the end of the line. | |||
214 | startOfBuffer = startOfBuffer.drop_back(); | |||
215 | ||||
216 | // Check to see if the preceding line has a comment on it. We assume that a | |||
217 | // `//` is the start of a comment, which is mostly correct. | |||
218 | // TODO: This will do the wrong thing for // in a string literal. | |||
219 | auto prevLine = startOfBuffer; | |||
220 | size_t newLineIndex = prevLine.find_last_of("\n\r"); | |||
221 | if (newLineIndex != StringRef::npos) | |||
222 | prevLine = prevLine.drop_front(newLineIndex); | |||
223 | ||||
224 | // If we find a // in the current line, then emit the diagnostic before it. | |||
225 | size_t commentStart = prevLine.find("//"); | |||
226 | if (commentStart != StringRef::npos) | |||
227 | startOfBuffer = startOfBuffer.drop_back(prevLine.size() - commentStart); | |||
228 | } | |||
229 | } | |||
230 | ||||
231 | /// Consume the specified token if present and return success. On failure, | |||
232 | /// output a diagnostic and return failure. | |||
233 | ParseResult Parser::parseToken(Token::Kind expectedToken, | |||
234 | const Twine &message) { | |||
235 | if (consumeIf(expectedToken)) | |||
236 | return success(); | |||
237 | return emitWrongTokenError(message); | |||
238 | } | |||
239 | ||||
240 | /// Parse an optional integer value from the stream. | |||
241 | OptionalParseResult Parser::parseOptionalInteger(APInt &result) { | |||
242 | // Parse `false` and `true` keywords as 0 and 1 respectively. | |||
243 | if (consumeIf(Token::kw_false)) { | |||
244 | result = false; | |||
245 | return success(); | |||
246 | } | |||
247 | if (consumeIf(Token::kw_true)) { | |||
248 | result = true; | |||
249 | return success(); | |||
250 | } | |||
251 | ||||
252 | Token curToken = getToken(); | |||
253 | if (curToken.isNot(Token::integer, Token::minus)) | |||
254 | return std::nullopt; | |||
255 | ||||
256 | bool negative = consumeIf(Token::minus); | |||
257 | Token curTok = getToken(); | |||
258 | if (parseToken(Token::integer, "expected integer value")) | |||
259 | return failure(); | |||
260 | ||||
261 | StringRef spelling = curTok.getSpelling(); | |||
262 | bool isHex = spelling.size() > 1 && spelling[1] == 'x'; | |||
263 | if (spelling.getAsInteger(isHex ? 0 : 10, result)) | |||
264 | return emitError(curTok.getLoc(), "integer value too large"); | |||
265 | ||||
266 | // Make sure we have a zero at the top so we return the right signedness. | |||
267 | if (result.isNegative()) | |||
268 | result = result.zext(result.getBitWidth() + 1); | |||
269 | ||||
270 | // Process the negative sign if present. | |||
271 | if (negative) | |||
272 | result.negate(); | |||
273 | ||||
274 | return success(); | |||
275 | } | |||
276 | ||||
277 | /// Parse a floating point value from an integer literal token. | |||
278 | ParseResult Parser::parseFloatFromIntegerLiteral( | |||
279 | std::optional<APFloat> &result, const Token &tok, bool isNegative, | |||
280 | const llvm::fltSemantics &semantics, size_t typeSizeInBits) { | |||
281 | SMLoc loc = tok.getLoc(); | |||
282 | StringRef spelling = tok.getSpelling(); | |||
283 | bool isHex = spelling.size() > 1 && spelling[1] == 'x'; | |||
284 | if (!isHex) { | |||
285 | return emitError(loc, "unexpected decimal integer literal for a " | |||
286 | "floating point value") | |||
287 | .attachNote() | |||
288 | << "add a trailing dot to make the literal a float"; | |||
289 | } | |||
290 | if (isNegative) { | |||
291 | return emitError(loc, "hexadecimal float literal should not have a " | |||
292 | "leading minus"); | |||
293 | } | |||
294 | ||||
295 | std::optional<uint64_t> value = tok.getUInt64IntegerValue(); | |||
296 | if (!value) | |||
297 | return emitError(loc, "hexadecimal float constant out of range for type"); | |||
298 | ||||
299 | if (&semantics == &APFloat::IEEEdouble()) { | |||
300 | result = APFloat(semantics, APInt(typeSizeInBits, *value)); | |||
301 | return success(); | |||
302 | } | |||
303 | ||||
304 | APInt apInt(typeSizeInBits, *value); | |||
305 | if (apInt != *value) | |||
306 | return emitError(loc, "hexadecimal float constant out of range for type"); | |||
307 | result = APFloat(semantics, apInt); | |||
308 | ||||
309 | return success(); | |||
310 | } | |||
311 | ||||
312 | ParseResult Parser::parseOptionalKeyword(StringRef *keyword) { | |||
313 | // Check that the current token is a keyword. | |||
314 | if (!isCurrentTokenAKeyword()) | |||
315 | return failure(); | |||
316 | ||||
317 | *keyword = getTokenSpelling(); | |||
318 | consumeToken(); | |||
319 | return success(); | |||
320 | } | |||
321 | ||||
322 | //===----------------------------------------------------------------------===// | |||
323 | // Resource Parsing | |||
324 | ||||
325 | FailureOr<AsmDialectResourceHandle> | |||
326 | Parser::parseResourceHandle(const OpAsmDialectInterface *dialect, | |||
327 | StringRef &name) { | |||
328 | assert(dialect && "expected valid dialect interface")(static_cast <bool> (dialect && "expected valid dialect interface" ) ? void (0) : __assert_fail ("dialect && \"expected valid dialect interface\"" , "mlir/lib/AsmParser/Parser.cpp", 328, __extension__ __PRETTY_FUNCTION__ )); | |||
329 | SMLoc nameLoc = getToken().getLoc(); | |||
330 | if (failed(parseOptionalKeyword(&name))) | |||
331 | return emitError("expected identifier key for 'resource' entry"); | |||
332 | auto &resources = getState().symbols.dialectResources; | |||
333 | ||||
334 | // If this is the first time encountering this handle, ask the dialect to | |||
335 | // resolve a reference to this handle. This allows for us to remap the name of | |||
336 | // the handle if necessary. | |||
337 | std::pair<std::string, AsmDialectResourceHandle> &entry = | |||
338 | resources[dialect][name]; | |||
339 | if (entry.first.empty()) { | |||
340 | FailureOr<AsmDialectResourceHandle> result = dialect->declareResource(name); | |||
341 | if (failed(result)) { | |||
342 | return emitError(nameLoc) | |||
343 | << "unknown 'resource' key '" << name << "' for dialect '" | |||
344 | << dialect->getDialect()->getNamespace() << "'"; | |||
345 | } | |||
346 | entry.first = dialect->getResourceKey(*result); | |||
347 | entry.second = *result; | |||
348 | } | |||
349 | ||||
350 | name = entry.first; | |||
351 | return entry.second; | |||
352 | } | |||
353 | ||||
354 | FailureOr<AsmDialectResourceHandle> | |||
355 | Parser::parseResourceHandle(Dialect *dialect) { | |||
356 | const auto *interface = dyn_cast<OpAsmDialectInterface>(dialect); | |||
357 | if (!interface) { | |||
358 | return emitError() << "dialect '" << dialect->getNamespace() | |||
359 | << "' does not expect resource handles"; | |||
360 | } | |||
361 | StringRef resourceName; | |||
362 | return parseResourceHandle(interface, resourceName); | |||
363 | } | |||
364 | ||||
365 | //===----------------------------------------------------------------------===// | |||
366 | // Code Completion | |||
367 | ||||
368 | ParseResult Parser::codeCompleteDialectName() { | |||
369 | state.codeCompleteContext->completeDialectName(); | |||
370 | return failure(); | |||
371 | } | |||
372 | ||||
373 | ParseResult Parser::codeCompleteOperationName(StringRef dialectName) { | |||
374 | // Perform some simple validation on the dialect name. This doesn't need to be | |||
375 | // extensive, it's more of an optimization (to avoid checking completion | |||
376 | // results when we know they will fail). | |||
377 | if (dialectName.empty() || dialectName.contains('.')) | |||
378 | return failure(); | |||
379 | state.codeCompleteContext->completeOperationName(dialectName); | |||
380 | return failure(); | |||
381 | } | |||
382 | ||||
383 | ParseResult Parser::codeCompleteDialectOrElidedOpName(SMLoc loc) { | |||
384 | // Check to see if there is anything else on the current line. This check | |||
385 | // isn't strictly necessary, but it does avoid unnecessarily triggering | |||
386 | // completions for operations and dialects in situations where we don't want | |||
387 | // them (e.g. at the end of an operation). | |||
388 | auto shouldIgnoreOpCompletion = [&]() { | |||
389 | const char *bufBegin = state.lex.getBufferBegin(); | |||
390 | const char *it = loc.getPointer() - 1; | |||
391 | for (; it > bufBegin && *it != '\n'; --it) | |||
392 | if (!StringRef(" \t\r").contains(*it)) | |||
393 | return true; | |||
394 | return false; | |||
395 | }; | |||
396 | if (shouldIgnoreOpCompletion()) | |||
397 | return failure(); | |||
398 | ||||
399 | // The completion here is either for a dialect name, or an operation name | |||
400 | // whose dialect prefix was elided. For this we simply invoke both of the | |||
401 | // individual completion methods. | |||
402 | (void)codeCompleteDialectName(); | |||
403 | return codeCompleteOperationName(state.defaultDialectStack.back()); | |||
404 | } | |||
405 | ||||
406 | ParseResult Parser::codeCompleteStringDialectOrOperationName(StringRef name) { | |||
407 | // If the name is empty, this is the start of the string and contains the | |||
408 | // dialect. | |||
409 | if (name.empty()) | |||
410 | return codeCompleteDialectName(); | |||
411 | ||||
412 | // Otherwise, we treat this as completing an operation name. The current name | |||
413 | // is used as the dialect namespace. | |||
414 | if (name.consume_back(".")) | |||
415 | return codeCompleteOperationName(name); | |||
416 | return failure(); | |||
417 | } | |||
418 | ||||
419 | ParseResult Parser::codeCompleteExpectedTokens(ArrayRef<StringRef> tokens) { | |||
420 | state.codeCompleteContext->completeExpectedTokens(tokens, /*optional=*/false); | |||
421 | return failure(); | |||
422 | } | |||
423 | ParseResult Parser::codeCompleteOptionalTokens(ArrayRef<StringRef> tokens) { | |||
424 | state.codeCompleteContext->completeExpectedTokens(tokens, /*optional=*/true); | |||
425 | return failure(); | |||
426 | } | |||
427 | ||||
428 | Attribute Parser::codeCompleteAttribute() { | |||
429 | state.codeCompleteContext->completeAttribute( | |||
430 | state.symbols.attributeAliasDefinitions); | |||
431 | return {}; | |||
432 | } | |||
433 | Type Parser::codeCompleteType() { | |||
434 | state.codeCompleteContext->completeType(state.symbols.typeAliasDefinitions); | |||
435 | return {}; | |||
436 | } | |||
437 | ||||
438 | Attribute | |||
439 | Parser::codeCompleteDialectSymbol(const llvm::StringMap<Attribute> &aliases) { | |||
440 | state.codeCompleteContext->completeDialectAttributeOrAlias(aliases); | |||
441 | return {}; | |||
442 | } | |||
443 | Type Parser::codeCompleteDialectSymbol(const llvm::StringMap<Type> &aliases) { | |||
444 | state.codeCompleteContext->completeDialectTypeOrAlias(aliases); | |||
445 | return {}; | |||
446 | } | |||
447 | ||||
448 | //===----------------------------------------------------------------------===// | |||
449 | // OperationParser | |||
450 | //===----------------------------------------------------------------------===// | |||
451 | ||||
452 | namespace { | |||
453 | /// This class provides support for parsing operations and regions of | |||
454 | /// operations. | |||
455 | class OperationParser : public Parser { | |||
456 | public: | |||
457 | OperationParser(ParserState &state, ModuleOp topLevelOp); | |||
458 | ~OperationParser(); | |||
459 | ||||
460 | /// After parsing is finished, this function must be called to see if there | |||
461 | /// are any remaining issues. | |||
462 | ParseResult finalize(); | |||
463 | ||||
464 | //===--------------------------------------------------------------------===// | |||
465 | // SSA Value Handling | |||
466 | //===--------------------------------------------------------------------===// | |||
467 | ||||
468 | using UnresolvedOperand = OpAsmParser::UnresolvedOperand; | |||
469 | using Argument = OpAsmParser::Argument; | |||
470 | ||||
471 | struct DeferredLocInfo { | |||
472 | SMLoc loc; | |||
473 | StringRef identifier; | |||
474 | }; | |||
475 | ||||
476 | /// Push a new SSA name scope to the parser. | |||
477 | void pushSSANameScope(bool isIsolated); | |||
478 | ||||
479 | /// Pop the last SSA name scope from the parser. | |||
480 | ParseResult popSSANameScope(); | |||
481 | ||||
482 | /// Register a definition of a value with the symbol table. | |||
483 | ParseResult addDefinition(UnresolvedOperand useInfo, Value value); | |||
484 | ||||
485 | /// Parse an optional list of SSA uses into 'results'. | |||
486 | ParseResult | |||
487 | parseOptionalSSAUseList(SmallVectorImpl<UnresolvedOperand> &results); | |||
488 | ||||
489 | /// Parse a single SSA use into 'result'. If 'allowResultNumber' is true then | |||
490 | /// we allow #42 syntax. | |||
491 | ParseResult parseSSAUse(UnresolvedOperand &result, | |||
492 | bool allowResultNumber = true); | |||
493 | ||||
494 | /// Given a reference to an SSA value and its type, return a reference. This | |||
495 | /// returns null on failure. | |||
496 | Value resolveSSAUse(UnresolvedOperand useInfo, Type type); | |||
497 | ||||
498 | ParseResult parseSSADefOrUseAndType( | |||
499 | function_ref<ParseResult(UnresolvedOperand, Type)> action); | |||
500 | ||||
501 | ParseResult parseOptionalSSAUseAndTypeList(SmallVectorImpl<Value> &results); | |||
502 | ||||
503 | /// Return the location of the value identified by its name and number if it | |||
504 | /// has been already reference. | |||
505 | std::optional<SMLoc> getReferenceLoc(StringRef name, unsigned number) { | |||
506 | auto &values = isolatedNameScopes.back().values; | |||
507 | if (!values.count(name) || number >= values[name].size()) | |||
508 | return {}; | |||
509 | if (values[name][number].value) | |||
510 | return values[name][number].loc; | |||
511 | return {}; | |||
512 | } | |||
513 | ||||
514 | //===--------------------------------------------------------------------===// | |||
515 | // Operation Parsing | |||
516 | //===--------------------------------------------------------------------===// | |||
517 | ||||
518 | /// Parse an operation instance. | |||
519 | ParseResult parseOperation(); | |||
520 | ||||
521 | /// Parse a single operation successor. | |||
522 | ParseResult parseSuccessor(Block *&dest); | |||
523 | ||||
524 | /// Parse a comma-separated list of operation successors in brackets. | |||
525 | ParseResult parseSuccessors(SmallVectorImpl<Block *> &destinations); | |||
526 | ||||
527 | /// Parse an operation instance that is in the generic form. | |||
528 | Operation *parseGenericOperation(); | |||
529 | ||||
530 | /// Parse different components, viz., use-info of operand(s), successor(s), | |||
531 | /// region(s), attribute(s) and function-type, of the generic form of an | |||
532 | /// operation instance and populate the input operation-state 'result' with | |||
533 | /// those components. If any of the components is explicitly provided, then | |||
534 | /// skip parsing that component. | |||
535 | ParseResult parseGenericOperationAfterOpName( | |||
536 | OperationState &result, | |||
537 | std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo = | |||
538 | std::nullopt, | |||
539 | std::optional<ArrayRef<Block *>> parsedSuccessors = std::nullopt, | |||
540 | std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions = | |||
541 | std::nullopt, | |||
542 | std::optional<ArrayRef<NamedAttribute>> parsedAttributes = std::nullopt, | |||
543 | std::optional<FunctionType> parsedFnType = std::nullopt); | |||
544 | ||||
545 | /// Parse an operation instance that is in the generic form and insert it at | |||
546 | /// the provided insertion point. | |||
547 | Operation *parseGenericOperation(Block *insertBlock, | |||
548 | Block::iterator insertPt); | |||
549 | ||||
550 | /// This type is used to keep track of things that are either an Operation or | |||
551 | /// a BlockArgument. We cannot use Value for this, because not all Operations | |||
552 | /// have results. | |||
553 | using OpOrArgument = llvm::PointerUnion<Operation *, BlockArgument>; | |||
554 | ||||
555 | /// Parse an optional trailing location and add it to the specifier Operation | |||
556 | /// or `UnresolvedOperand` if present. | |||
557 | /// | |||
558 | /// trailing-location ::= (`loc` (`(` location `)` | attribute-alias))? | |||
559 | /// | |||
560 | ParseResult parseTrailingLocationSpecifier(OpOrArgument opOrArgument); | |||
561 | ||||
562 | /// Parse a location alias, that is a sequence looking like: #loc42 | |||
563 | /// The alias may have already be defined or may be defined later, in which | |||
564 | /// case an OpaqueLoc is used a placeholder. | |||
565 | ParseResult parseLocationAlias(LocationAttr &loc); | |||
566 | ||||
567 | /// This is the structure of a result specifier in the assembly syntax, | |||
568 | /// including the name, number of results, and location. | |||
569 | using ResultRecord = std::tuple<StringRef, unsigned, SMLoc>; | |||
570 | ||||
571 | /// Parse an operation instance that is in the op-defined custom form. | |||
572 | /// resultInfo specifies information about the "%name =" specifiers. | |||
573 | Operation *parseCustomOperation(ArrayRef<ResultRecord> resultIDs); | |||
574 | ||||
575 | /// Parse the name of an operation, in the custom form. On success, return a | |||
576 | /// an object of type 'OperationName'. Otherwise, failure is returned. | |||
577 | FailureOr<OperationName> parseCustomOperationName(); | |||
578 | ||||
579 | //===--------------------------------------------------------------------===// | |||
580 | // Region Parsing | |||
581 | //===--------------------------------------------------------------------===// | |||
582 | ||||
583 | /// Parse a region into 'region' with the provided entry block arguments. | |||
584 | /// 'isIsolatedNameScope' indicates if the naming scope of this region is | |||
585 | /// isolated from those above. | |||
586 | ParseResult parseRegion(Region ®ion, ArrayRef<Argument> entryArguments, | |||
587 | bool isIsolatedNameScope = false); | |||
588 | ||||
589 | /// Parse a region body into 'region'. | |||
590 | ParseResult parseRegionBody(Region ®ion, SMLoc startLoc, | |||
591 | ArrayRef<Argument> entryArguments, | |||
592 | bool isIsolatedNameScope); | |||
593 | ||||
594 | //===--------------------------------------------------------------------===// | |||
595 | // Block Parsing | |||
596 | //===--------------------------------------------------------------------===// | |||
597 | ||||
598 | /// Parse a new block into 'block'. | |||
599 | ParseResult parseBlock(Block *&block); | |||
600 | ||||
601 | /// Parse a list of operations into 'block'. | |||
602 | ParseResult parseBlockBody(Block *block); | |||
603 | ||||
604 | /// Parse a (possibly empty) list of block arguments. | |||
605 | ParseResult parseOptionalBlockArgList(Block *owner); | |||
606 | ||||
607 | /// Get the block with the specified name, creating it if it doesn't | |||
608 | /// already exist. The location specified is the point of use, which allows | |||
609 | /// us to diagnose references to blocks that are not defined precisely. | |||
610 | Block *getBlockNamed(StringRef name, SMLoc loc); | |||
611 | ||||
612 | //===--------------------------------------------------------------------===// | |||
613 | // Code Completion | |||
614 | //===--------------------------------------------------------------------===// | |||
615 | ||||
616 | /// The set of various code completion methods. Every completion method | |||
617 | /// returns `failure` to stop the parsing process after providing completion | |||
618 | /// results. | |||
619 | ||||
620 | ParseResult codeCompleteSSAUse(); | |||
621 | ParseResult codeCompleteBlock(); | |||
622 | ||||
623 | private: | |||
624 | /// This class represents a definition of a Block. | |||
625 | struct BlockDefinition { | |||
626 | /// A pointer to the defined Block. | |||
627 | Block *block; | |||
628 | /// The location that the Block was defined at. | |||
629 | SMLoc loc; | |||
630 | }; | |||
631 | /// This class represents a definition of a Value. | |||
632 | struct ValueDefinition { | |||
633 | /// A pointer to the defined Value. | |||
634 | Value value; | |||
635 | /// The location that the Value was defined at. | |||
636 | SMLoc loc; | |||
637 | }; | |||
638 | ||||
639 | /// Returns the info for a block at the current scope for the given name. | |||
640 | BlockDefinition &getBlockInfoByName(StringRef name) { | |||
641 | return blocksByName.back()[name]; | |||
642 | } | |||
643 | ||||
644 | /// Insert a new forward reference to the given block. | |||
645 | void insertForwardRef(Block *block, SMLoc loc) { | |||
646 | forwardRef.back().try_emplace(block, loc); | |||
647 | } | |||
648 | ||||
649 | /// Erase any forward reference to the given block. | |||
650 | bool eraseForwardRef(Block *block) { return forwardRef.back().erase(block); } | |||
651 | ||||
652 | /// Record that a definition was added at the current scope. | |||
653 | void recordDefinition(StringRef def); | |||
654 | ||||
655 | /// Get the value entry for the given SSA name. | |||
656 | SmallVectorImpl<ValueDefinition> &getSSAValueEntry(StringRef name); | |||
657 | ||||
658 | /// Create a forward reference placeholder value with the given location and | |||
659 | /// result type. | |||
660 | Value createForwardRefPlaceholder(SMLoc loc, Type type); | |||
661 | ||||
662 | /// Return true if this is a forward reference. | |||
663 | bool isForwardRefPlaceholder(Value value) { | |||
664 | return forwardRefPlaceholders.count(value); | |||
665 | } | |||
666 | ||||
667 | /// This struct represents an isolated SSA name scope. This scope may contain | |||
668 | /// other nested non-isolated scopes. These scopes are used for operations | |||
669 | /// that are known to be isolated to allow for reusing names within their | |||
670 | /// regions, even if those names are used above. | |||
671 | struct IsolatedSSANameScope { | |||
672 | /// Record that a definition was added at the current scope. | |||
673 | void recordDefinition(StringRef def) { | |||
674 | definitionsPerScope.back().insert(def); | |||
675 | } | |||
676 | ||||
677 | /// Push a nested name scope. | |||
678 | void pushSSANameScope() { definitionsPerScope.push_back({}); } | |||
679 | ||||
680 | /// Pop a nested name scope. | |||
681 | void popSSANameScope() { | |||
682 | for (auto &def : definitionsPerScope.pop_back_val()) | |||
683 | values.erase(def.getKey()); | |||
684 | } | |||
685 | ||||
686 | /// This keeps track of all of the SSA values we are tracking for each name | |||
687 | /// scope, indexed by their name. This has one entry per result number. | |||
688 | llvm::StringMap<SmallVector<ValueDefinition, 1>> values; | |||
689 | ||||
690 | /// This keeps track of all of the values defined by a specific name scope. | |||
691 | SmallVector<llvm::StringSet<>, 2> definitionsPerScope; | |||
692 | }; | |||
693 | ||||
694 | /// A list of isolated name scopes. | |||
695 | SmallVector<IsolatedSSANameScope, 2> isolatedNameScopes; | |||
696 | ||||
697 | /// This keeps track of the block names as well as the location of the first | |||
698 | /// reference for each nested name scope. This is used to diagnose invalid | |||
699 | /// block references and memorize them. | |||
700 | SmallVector<DenseMap<StringRef, BlockDefinition>, 2> blocksByName; | |||
701 | SmallVector<DenseMap<Block *, SMLoc>, 2> forwardRef; | |||
702 | ||||
703 | /// These are all of the placeholders we've made along with the location of | |||
704 | /// their first reference, to allow checking for use of undefined values. | |||
705 | DenseMap<Value, SMLoc> forwardRefPlaceholders; | |||
706 | ||||
707 | /// Deffered locations: when parsing `loc(#loc42)` we add an entry to this | |||
708 | /// map. After parsing the definition `#loc42 = ...` we'll patch back users | |||
709 | /// of this location. | |||
710 | std::vector<DeferredLocInfo> deferredLocsReferences; | |||
711 | ||||
712 | /// The builder used when creating parsed operation instances. | |||
713 | OpBuilder opBuilder; | |||
714 | ||||
715 | /// The top level operation that holds all of the parsed operations. | |||
716 | Operation *topLevelOp; | |||
717 | }; | |||
718 | } // namespace | |||
719 | ||||
720 | MLIR_DECLARE_EXPLICIT_TYPE_ID(OperationParser::DeferredLocInfo *)namespace mlir { namespace detail { template <> class TypeIDResolver <OperationParser::DeferredLocInfo *> { public: static TypeID resolveTypeID() { return id; } private: static SelfOwningTypeID id; }; } } | |||
721 | MLIR_DEFINE_EXPLICIT_TYPE_ID(OperationParser::DeferredLocInfo *)namespace mlir { namespace detail { SelfOwningTypeID TypeIDResolver <OperationParser::DeferredLocInfo *>::id = {}; } } | |||
722 | ||||
723 | OperationParser::OperationParser(ParserState &state, ModuleOp topLevelOp) | |||
724 | : Parser(state), opBuilder(topLevelOp.getRegion()), topLevelOp(topLevelOp) { | |||
725 | // The top level operation starts a new name scope. | |||
726 | pushSSANameScope(/*isIsolated=*/true); | |||
727 | ||||
728 | // If we are populating the parser state, prepare it for parsing. | |||
729 | if (state.asmState) | |||
730 | state.asmState->initialize(topLevelOp); | |||
731 | } | |||
732 | ||||
733 | OperationParser::~OperationParser() { | |||
734 | for (auto &fwd : forwardRefPlaceholders) { | |||
735 | // Drop all uses of undefined forward declared reference and destroy | |||
736 | // defining operation. | |||
737 | fwd.first.dropAllUses(); | |||
738 | fwd.first.getDefiningOp()->destroy(); | |||
739 | } | |||
740 | for (const auto &scope : forwardRef) { | |||
741 | for (const auto &fwd : scope) { | |||
742 | // Delete all blocks that were created as forward references but never | |||
743 | // included into a region. | |||
744 | fwd.first->dropAllUses(); | |||
745 | delete fwd.first; | |||
746 | } | |||
747 | } | |||
748 | } | |||
749 | ||||
750 | /// After parsing is finished, this function must be called to see if there are | |||
751 | /// any remaining issues. | |||
752 | ParseResult OperationParser::finalize() { | |||
753 | // Check for any forward references that are left. If we find any, error | |||
754 | // out. | |||
755 | if (!forwardRefPlaceholders.empty()) { | |||
756 | SmallVector<const char *, 4> errors; | |||
757 | // Iteration over the map isn't deterministic, so sort by source location. | |||
758 | for (auto entry : forwardRefPlaceholders) | |||
759 | errors.push_back(entry.second.getPointer()); | |||
760 | llvm::array_pod_sort(errors.begin(), errors.end()); | |||
761 | ||||
762 | for (const char *entry : errors) { | |||
763 | auto loc = SMLoc::getFromPointer(entry); | |||
764 | emitError(loc, "use of undeclared SSA value name"); | |||
765 | } | |||
766 | return failure(); | |||
767 | } | |||
768 | ||||
769 | // Resolve the locations of any deferred operations. | |||
770 | auto &attributeAliases = state.symbols.attributeAliasDefinitions; | |||
771 | auto locID = TypeID::get<DeferredLocInfo *>(); | |||
772 | auto resolveLocation = [&, this](auto &opOrArgument) -> LogicalResult { | |||
773 | auto fwdLoc = dyn_cast<OpaqueLoc>(opOrArgument.getLoc()); | |||
774 | if (!fwdLoc || fwdLoc.getUnderlyingTypeID() != locID) | |||
775 | return success(); | |||
776 | auto locInfo = deferredLocsReferences[fwdLoc.getUnderlyingLocation()]; | |||
777 | Attribute attr = attributeAliases.lookup(locInfo.identifier); | |||
778 | if (!attr) | |||
779 | return this->emitError(locInfo.loc) | |||
780 | << "operation location alias was never defined"; | |||
781 | auto locAttr = dyn_cast<LocationAttr>(attr); | |||
782 | if (!locAttr) | |||
783 | return this->emitError(locInfo.loc) | |||
784 | << "expected location, but found '" << attr << "'"; | |||
785 | opOrArgument.setLoc(locAttr); | |||
786 | return success(); | |||
787 | }; | |||
788 | ||||
789 | auto walkRes = topLevelOp->walk([&](Operation *op) { | |||
790 | if (failed(resolveLocation(*op))) | |||
791 | return WalkResult::interrupt(); | |||
792 | for (Region ®ion : op->getRegions()) | |||
793 | for (Block &block : region.getBlocks()) | |||
794 | for (BlockArgument arg : block.getArguments()) | |||
795 | if (failed(resolveLocation(arg))) | |||
796 | return WalkResult::interrupt(); | |||
797 | return WalkResult::advance(); | |||
798 | }); | |||
799 | if (walkRes.wasInterrupted()) | |||
800 | return failure(); | |||
801 | ||||
802 | // Pop the top level name scope. | |||
803 | if (failed(popSSANameScope())) | |||
804 | return failure(); | |||
805 | ||||
806 | // Verify that the parsed operations are valid. | |||
807 | if (state.config.shouldVerifyAfterParse() && failed(verify(topLevelOp))) | |||
808 | return failure(); | |||
809 | ||||
810 | // If we are populating the parser state, finalize the top-level operation. | |||
811 | if (state.asmState) | |||
812 | state.asmState->finalize(topLevelOp); | |||
813 | return success(); | |||
814 | } | |||
815 | ||||
816 | //===----------------------------------------------------------------------===// | |||
817 | // SSA Value Handling | |||
818 | //===----------------------------------------------------------------------===// | |||
819 | ||||
820 | void OperationParser::pushSSANameScope(bool isIsolated) { | |||
821 | blocksByName.push_back(DenseMap<StringRef, BlockDefinition>()); | |||
822 | forwardRef.push_back(DenseMap<Block *, SMLoc>()); | |||
823 | ||||
824 | // Push back a new name definition scope. | |||
825 | if (isIsolated) | |||
826 | isolatedNameScopes.push_back({}); | |||
827 | isolatedNameScopes.back().pushSSANameScope(); | |||
828 | } | |||
829 | ||||
830 | ParseResult OperationParser::popSSANameScope() { | |||
831 | auto forwardRefInCurrentScope = forwardRef.pop_back_val(); | |||
832 | ||||
833 | // Verify that all referenced blocks were defined. | |||
834 | if (!forwardRefInCurrentScope.empty()) { | |||
835 | SmallVector<std::pair<const char *, Block *>, 4> errors; | |||
836 | // Iteration over the map isn't deterministic, so sort by source location. | |||
837 | for (auto entry : forwardRefInCurrentScope) { | |||
838 | errors.push_back({entry.second.getPointer(), entry.first}); | |||
839 | // Add this block to the top-level region to allow for automatic cleanup. | |||
840 | topLevelOp->getRegion(0).push_back(entry.first); | |||
841 | } | |||
842 | llvm::array_pod_sort(errors.begin(), errors.end()); | |||
843 | ||||
844 | for (auto entry : errors) { | |||
845 | auto loc = SMLoc::getFromPointer(entry.first); | |||
846 | emitError(loc, "reference to an undefined block"); | |||
847 | } | |||
848 | return failure(); | |||
849 | } | |||
850 | ||||
851 | // Pop the next nested namescope. If there is only one internal namescope, | |||
852 | // just pop the isolated scope. | |||
853 | auto ¤tNameScope = isolatedNameScopes.back(); | |||
854 | if (currentNameScope.definitionsPerScope.size() == 1) | |||
855 | isolatedNameScopes.pop_back(); | |||
856 | else | |||
857 | currentNameScope.popSSANameScope(); | |||
858 | ||||
859 | blocksByName.pop_back(); | |||
860 | return success(); | |||
861 | } | |||
862 | ||||
863 | /// Register a definition of a value with the symbol table. | |||
864 | ParseResult OperationParser::addDefinition(UnresolvedOperand useInfo, | |||
865 | Value value) { | |||
866 | auto &entries = getSSAValueEntry(useInfo.name); | |||
867 | ||||
868 | // Make sure there is a slot for this value. | |||
869 | if (entries.size() <= useInfo.number) | |||
870 | entries.resize(useInfo.number + 1); | |||
871 | ||||
872 | // If we already have an entry for this, check to see if it was a definition | |||
873 | // or a forward reference. | |||
874 | if (auto existing = entries[useInfo.number].value) { | |||
875 | if (!isForwardRefPlaceholder(existing)) { | |||
876 | return emitError(useInfo.location) | |||
877 | .append("redefinition of SSA value '", useInfo.name, "'") | |||
878 | .attachNote(getEncodedSourceLocation(entries[useInfo.number].loc)) | |||
879 | .append("previously defined here"); | |||
880 | } | |||
881 | ||||
882 | if (existing.getType() != value.getType()) { | |||
883 | return emitError(useInfo.location) | |||
884 | .append("definition of SSA value '", useInfo.name, "#", | |||
885 | useInfo.number, "' has type ", value.getType()) | |||
886 | .attachNote(getEncodedSourceLocation(entries[useInfo.number].loc)) | |||
887 | .append("previously used here with type ", existing.getType()); | |||
888 | } | |||
889 | ||||
890 | // If it was a forward reference, update everything that used it to use | |||
891 | // the actual definition instead, delete the forward ref, and remove it | |||
892 | // from our set of forward references we track. | |||
893 | existing.replaceAllUsesWith(value); | |||
894 | existing.getDefiningOp()->destroy(); | |||
895 | forwardRefPlaceholders.erase(existing); | |||
896 | ||||
897 | // If a definition of the value already exists, replace it in the assembly | |||
898 | // state. | |||
899 | if (state.asmState) | |||
900 | state.asmState->refineDefinition(existing, value); | |||
901 | } | |||
902 | ||||
903 | /// Record this definition for the current scope. | |||
904 | entries[useInfo.number] = {value, useInfo.location}; | |||
905 | recordDefinition(useInfo.name); | |||
906 | return success(); | |||
907 | } | |||
908 | ||||
909 | /// Parse a (possibly empty) list of SSA operands. | |||
910 | /// | |||
911 | /// ssa-use-list ::= ssa-use (`,` ssa-use)* | |||
912 | /// ssa-use-list-opt ::= ssa-use-list? | |||
913 | /// | |||
914 | ParseResult OperationParser::parseOptionalSSAUseList( | |||
915 | SmallVectorImpl<UnresolvedOperand> &results) { | |||
916 | if (!getToken().isOrIsCodeCompletionFor(Token::percent_identifier)) | |||
917 | return success(); | |||
918 | return parseCommaSeparatedList([&]() -> ParseResult { | |||
919 | UnresolvedOperand result; | |||
920 | if (parseSSAUse(result)) | |||
921 | return failure(); | |||
922 | results.push_back(result); | |||
923 | return success(); | |||
924 | }); | |||
925 | } | |||
926 | ||||
927 | /// Parse a SSA operand for an operation. | |||
928 | /// | |||
929 | /// ssa-use ::= ssa-id | |||
930 | /// | |||
931 | ParseResult OperationParser::parseSSAUse(UnresolvedOperand &result, | |||
932 | bool allowResultNumber) { | |||
933 | if (getToken().isCodeCompletion()) | |||
934 | return codeCompleteSSAUse(); | |||
935 | ||||
936 | result.name = getTokenSpelling(); | |||
937 | result.number = 0; | |||
938 | result.location = getToken().getLoc(); | |||
939 | if (parseToken(Token::percent_identifier, "expected SSA operand")) | |||
940 | return failure(); | |||
941 | ||||
942 | // If we have an attribute ID, it is a result number. | |||
943 | if (getToken().is(Token::hash_identifier)) { | |||
944 | if (!allowResultNumber) | |||
945 | return emitError("result number not allowed in argument list"); | |||
946 | ||||
947 | if (auto value = getToken().getHashIdentifierNumber()) | |||
948 | result.number = *value; | |||
949 | else | |||
950 | return emitError("invalid SSA value result number"); | |||
951 | consumeToken(Token::hash_identifier); | |||
952 | } | |||
953 | ||||
954 | return success(); | |||
955 | } | |||
956 | ||||
957 | /// Given an unbound reference to an SSA value and its type, return the value | |||
958 | /// it specifies. This returns null on failure. | |||
959 | Value OperationParser::resolveSSAUse(UnresolvedOperand useInfo, Type type) { | |||
960 | auto &entries = getSSAValueEntry(useInfo.name); | |||
961 | ||||
962 | // Functor used to record the use of the given value if the assembly state | |||
963 | // field is populated. | |||
964 | auto maybeRecordUse = [&](Value value) { | |||
965 | if (state.asmState) | |||
966 | state.asmState->addUses(value, useInfo.location); | |||
967 | return value; | |||
968 | }; | |||
969 | ||||
970 | // If we have already seen a value of this name, return it. | |||
971 | if (useInfo.number < entries.size() && entries[useInfo.number].value) { | |||
972 | Value result = entries[useInfo.number].value; | |||
973 | // Check that the type matches the other uses. | |||
974 | if (result.getType() == type) | |||
975 | return maybeRecordUse(result); | |||
976 | ||||
977 | emitError(useInfo.location, "use of value '") | |||
978 | .append(useInfo.name, | |||
979 | "' expects different type than prior uses: ", type, " vs ", | |||
980 | result.getType()) | |||
981 | .attachNote(getEncodedSourceLocation(entries[useInfo.number].loc)) | |||
982 | .append("prior use here"); | |||
983 | return nullptr; | |||
984 | } | |||
985 | ||||
986 | // Make sure we have enough slots for this. | |||
987 | if (entries.size() <= useInfo.number) | |||
988 | entries.resize(useInfo.number + 1); | |||
989 | ||||
990 | // If the value has already been defined and this is an overly large result | |||
991 | // number, diagnose that. | |||
992 | if (entries[0].value && !isForwardRefPlaceholder(entries[0].value)) | |||
993 | return (emitError(useInfo.location, "reference to invalid result number"), | |||
994 | nullptr); | |||
995 | ||||
996 | // Otherwise, this is a forward reference. Create a placeholder and remember | |||
997 | // that we did so. | |||
998 | Value result = createForwardRefPlaceholder(useInfo.location, type); | |||
999 | entries[useInfo.number] = {result, useInfo.location}; | |||
1000 | return maybeRecordUse(result); | |||
1001 | } | |||
1002 | ||||
1003 | /// Parse an SSA use with an associated type. | |||
1004 | /// | |||
1005 | /// ssa-use-and-type ::= ssa-use `:` type | |||
1006 | ParseResult OperationParser::parseSSADefOrUseAndType( | |||
1007 | function_ref<ParseResult(UnresolvedOperand, Type)> action) { | |||
1008 | UnresolvedOperand useInfo; | |||
1009 | if (parseSSAUse(useInfo) || | |||
1010 | parseToken(Token::colon, "expected ':' and type for SSA operand")) | |||
1011 | return failure(); | |||
1012 | ||||
1013 | auto type = parseType(); | |||
1014 | if (!type) | |||
1015 | return failure(); | |||
1016 | ||||
1017 | return action(useInfo, type); | |||
1018 | } | |||
1019 | ||||
1020 | /// Parse a (possibly empty) list of SSA operands, followed by a colon, then | |||
1021 | /// followed by a type list. | |||
1022 | /// | |||
1023 | /// ssa-use-and-type-list | |||
1024 | /// ::= ssa-use-list ':' type-list-no-parens | |||
1025 | /// | |||
1026 | ParseResult OperationParser::parseOptionalSSAUseAndTypeList( | |||
1027 | SmallVectorImpl<Value> &results) { | |||
1028 | SmallVector<UnresolvedOperand, 4> valueIDs; | |||
1029 | if (parseOptionalSSAUseList(valueIDs)) | |||
1030 | return failure(); | |||
1031 | ||||
1032 | // If there were no operands, then there is no colon or type lists. | |||
1033 | if (valueIDs.empty()) | |||
1034 | return success(); | |||
1035 | ||||
1036 | SmallVector<Type, 4> types; | |||
1037 | if (parseToken(Token::colon, "expected ':' in operand list") || | |||
1038 | parseTypeListNoParens(types)) | |||
1039 | return failure(); | |||
1040 | ||||
1041 | if (valueIDs.size() != types.size()) | |||
1042 | return emitError("expected ") | |||
1043 | << valueIDs.size() << " types to match operand list"; | |||
1044 | ||||
1045 | results.reserve(valueIDs.size()); | |||
1046 | for (unsigned i = 0, e = valueIDs.size(); i != e; ++i) { | |||
1047 | if (auto value = resolveSSAUse(valueIDs[i], types[i])) | |||
1048 | results.push_back(value); | |||
1049 | else | |||
1050 | return failure(); | |||
1051 | } | |||
1052 | ||||
1053 | return success(); | |||
1054 | } | |||
1055 | ||||
1056 | /// Record that a definition was added at the current scope. | |||
1057 | void OperationParser::recordDefinition(StringRef def) { | |||
1058 | isolatedNameScopes.back().recordDefinition(def); | |||
1059 | } | |||
1060 | ||||
1061 | /// Get the value entry for the given SSA name. | |||
1062 | auto OperationParser::getSSAValueEntry(StringRef name) | |||
1063 | -> SmallVectorImpl<ValueDefinition> & { | |||
1064 | return isolatedNameScopes.back().values[name]; | |||
1065 | } | |||
1066 | ||||
1067 | /// Create and remember a new placeholder for a forward reference. | |||
1068 | Value OperationParser::createForwardRefPlaceholder(SMLoc loc, Type type) { | |||
1069 | // Forward references are always created as operations, because we just need | |||
1070 | // something with a def/use chain. | |||
1071 | // | |||
1072 | // We create these placeholders as having an empty name, which we know | |||
1073 | // cannot be created through normal user input, allowing us to distinguish | |||
1074 | // them. | |||
1075 | auto name = OperationName("builtin.unrealized_conversion_cast", getContext()); | |||
1076 | auto *op = Operation::create( | |||
1077 | getEncodedSourceLocation(loc), name, type, /*operands=*/{}, | |||
1078 | /*attributes=*/std::nullopt, /*successors=*/{}, /*numRegions=*/0); | |||
1079 | forwardRefPlaceholders[op->getResult(0)] = loc; | |||
1080 | return op->getResult(0); | |||
1081 | } | |||
1082 | ||||
1083 | //===----------------------------------------------------------------------===// | |||
1084 | // Operation Parsing | |||
1085 | //===----------------------------------------------------------------------===// | |||
1086 | ||||
1087 | /// Parse an operation. | |||
1088 | /// | |||
1089 | /// operation ::= op-result-list? | |||
1090 | /// (generic-operation | custom-operation) | |||
1091 | /// trailing-location? | |||
1092 | /// generic-operation ::= string-literal `(` ssa-use-list? `)` | |||
1093 | /// successor-list? (`(` region-list `)`)? | |||
1094 | /// attribute-dict? `:` function-type | |||
1095 | /// custom-operation ::= bare-id custom-operation-format | |||
1096 | /// op-result-list ::= op-result (`,` op-result)* `=` | |||
1097 | /// op-result ::= ssa-id (`:` integer-literal) | |||
1098 | /// | |||
1099 | ParseResult OperationParser::parseOperation() { | |||
1100 | auto loc = getToken().getLoc(); | |||
1101 | SmallVector<ResultRecord, 1> resultIDs; | |||
1102 | size_t numExpectedResults = 0; | |||
1103 | if (getToken().is(Token::percent_identifier)) { | |||
1104 | // Parse the group of result ids. | |||
1105 | auto parseNextResult = [&]() -> ParseResult { | |||
1106 | // Parse the next result id. | |||
1107 | Token nameTok = getToken(); | |||
1108 | if (parseToken(Token::percent_identifier, | |||
1109 | "expected valid ssa identifier")) | |||
1110 | return failure(); | |||
1111 | ||||
1112 | // If the next token is a ':', we parse the expected result count. | |||
1113 | size_t expectedSubResults = 1; | |||
1114 | if (consumeIf(Token::colon)) { | |||
1115 | // Check that the next token is an integer. | |||
1116 | if (!getToken().is(Token::integer)) | |||
1117 | return emitWrongTokenError("expected integer number of results"); | |||
1118 | ||||
1119 | // Check that number of results is > 0. | |||
1120 | auto val = getToken().getUInt64IntegerValue(); | |||
1121 | if (!val || *val < 1) | |||
1122 | return emitError( | |||
1123 | "expected named operation to have at least 1 result"); | |||
1124 | consumeToken(Token::integer); | |||
1125 | expectedSubResults = *val; | |||
1126 | } | |||
1127 | ||||
1128 | resultIDs.emplace_back(nameTok.getSpelling(), expectedSubResults, | |||
1129 | nameTok.getLoc()); | |||
1130 | numExpectedResults += expectedSubResults; | |||
1131 | return success(); | |||
1132 | }; | |||
1133 | if (parseCommaSeparatedList(parseNextResult)) | |||
1134 | return failure(); | |||
1135 | ||||
1136 | if (parseToken(Token::equal, "expected '=' after SSA name")) | |||
1137 | return failure(); | |||
1138 | } | |||
1139 | ||||
1140 | Operation *op; | |||
1141 | Token nameTok = getToken(); | |||
1142 | if (nameTok.is(Token::bare_identifier) || nameTok.isKeyword()) | |||
1143 | op = parseCustomOperation(resultIDs); | |||
1144 | else if (nameTok.is(Token::string)) | |||
1145 | op = parseGenericOperation(); | |||
1146 | else if (nameTok.isCodeCompletionFor(Token::string)) | |||
1147 | return codeCompleteStringDialectOrOperationName(nameTok.getStringValue()); | |||
1148 | else if (nameTok.isCodeCompletion()) | |||
1149 | return codeCompleteDialectOrElidedOpName(loc); | |||
1150 | else | |||
1151 | return emitWrongTokenError("expected operation name in quotes"); | |||
1152 | ||||
1153 | // If parsing of the basic operation failed, then this whole thing fails. | |||
1154 | if (!op) | |||
1155 | return failure(); | |||
1156 | ||||
1157 | // If the operation had a name, register it. | |||
1158 | if (!resultIDs.empty()) { | |||
1159 | if (op->getNumResults() == 0) | |||
1160 | return emitError(loc, "cannot name an operation with no results"); | |||
1161 | if (numExpectedResults != op->getNumResults()) | |||
1162 | return emitError(loc, "operation defines ") | |||
1163 | << op->getNumResults() << " results but was provided " | |||
1164 | << numExpectedResults << " to bind"; | |||
1165 | ||||
1166 | // Add this operation to the assembly state if it was provided to populate. | |||
1167 | if (state.asmState) { | |||
1168 | unsigned resultIt = 0; | |||
1169 | SmallVector<std::pair<unsigned, SMLoc>> asmResultGroups; | |||
1170 | asmResultGroups.reserve(resultIDs.size()); | |||
1171 | for (ResultRecord &record : resultIDs) { | |||
1172 | asmResultGroups.emplace_back(resultIt, std::get<2>(record)); | |||
1173 | resultIt += std::get<1>(record); | |||
1174 | } | |||
1175 | state.asmState->finalizeOperationDefinition( | |||
1176 | op, nameTok.getLocRange(), /*endLoc=*/getToken().getLoc(), | |||
1177 | asmResultGroups); | |||
1178 | } | |||
1179 | ||||
1180 | // Add definitions for each of the result groups. | |||
1181 | unsigned opResI = 0; | |||
1182 | for (ResultRecord &resIt : resultIDs) { | |||
1183 | for (unsigned subRes : llvm::seq<unsigned>(0, std::get<1>(resIt))) { | |||
1184 | if (addDefinition({std::get<2>(resIt), std::get<0>(resIt), subRes}, | |||
1185 | op->getResult(opResI++))) | |||
1186 | return failure(); | |||
1187 | } | |||
1188 | } | |||
1189 | ||||
1190 | // Add this operation to the assembly state if it was provided to populate. | |||
1191 | } else if (state.asmState) { | |||
1192 | state.asmState->finalizeOperationDefinition(op, nameTok.getLocRange(), | |||
1193 | /*endLoc=*/getToken().getLoc()); | |||
1194 | } | |||
1195 | ||||
1196 | return success(); | |||
1197 | } | |||
1198 | ||||
1199 | /// Parse a single operation successor. | |||
1200 | /// | |||
1201 | /// successor ::= block-id | |||
1202 | /// | |||
1203 | ParseResult OperationParser::parseSuccessor(Block *&dest) { | |||
1204 | if (getToken().isCodeCompletion()) | |||
1205 | return codeCompleteBlock(); | |||
1206 | ||||
1207 | // Verify branch is identifier and get the matching block. | |||
1208 | if (!getToken().is(Token::caret_identifier)) | |||
1209 | return emitWrongTokenError("expected block name"); | |||
1210 | dest = getBlockNamed(getTokenSpelling(), getToken().getLoc()); | |||
1211 | consumeToken(); | |||
1212 | return success(); | |||
1213 | } | |||
1214 | ||||
1215 | /// Parse a comma-separated list of operation successors in brackets. | |||
1216 | /// | |||
1217 | /// successor-list ::= `[` successor (`,` successor )* `]` | |||
1218 | /// | |||
1219 | ParseResult | |||
1220 | OperationParser::parseSuccessors(SmallVectorImpl<Block *> &destinations) { | |||
1221 | if (parseToken(Token::l_square, "expected '['")) | |||
1222 | return failure(); | |||
1223 | ||||
1224 | auto parseElt = [this, &destinations] { | |||
1225 | Block *dest; | |||
| ||||
1226 | ParseResult res = parseSuccessor(dest); | |||
1227 | destinations.push_back(dest); | |||
| ||||
1228 | return res; | |||
1229 | }; | |||
1230 | return parseCommaSeparatedListUntil(Token::r_square, parseElt, | |||
1231 | /*allowEmptyList=*/false); | |||
1232 | } | |||
1233 | ||||
1234 | namespace { | |||
1235 | // RAII-style guard for cleaning up the regions in the operation state before | |||
1236 | // deleting them. Within the parser, regions may get deleted if parsing failed, | |||
1237 | // and other errors may be present, in particular undominated uses. This makes | |||
1238 | // sure such uses are deleted. | |||
1239 | struct CleanupOpStateRegions { | |||
1240 | ~CleanupOpStateRegions() { | |||
1241 | SmallVector<Region *, 4> regionsToClean; | |||
1242 | regionsToClean.reserve(state.regions.size()); | |||
1243 | for (auto ®ion : state.regions) | |||
1244 | if (region) | |||
1245 | for (auto &block : *region) | |||
1246 | block.dropAllDefinedValueUses(); | |||
1247 | } | |||
1248 | OperationState &state; | |||
1249 | }; | |||
1250 | } // namespace | |||
1251 | ||||
1252 | ParseResult OperationParser::parseGenericOperationAfterOpName( | |||
1253 | OperationState &result, | |||
1254 | std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo, | |||
1255 | std::optional<ArrayRef<Block *>> parsedSuccessors, | |||
1256 | std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions, | |||
1257 | std::optional<ArrayRef<NamedAttribute>> parsedAttributes, | |||
1258 | std::optional<FunctionType> parsedFnType) { | |||
1259 | ||||
1260 | // Parse the operand list, if not explicitly provided. | |||
1261 | SmallVector<UnresolvedOperand, 8> opInfo; | |||
1262 | if (!parsedOperandUseInfo) { | |||
1263 | if (parseToken(Token::l_paren, "expected '(' to start operand list") || | |||
1264 | parseOptionalSSAUseList(opInfo) || | |||
1265 | parseToken(Token::r_paren, "expected ')' to end operand list")) { | |||
1266 | return failure(); | |||
1267 | } | |||
1268 | parsedOperandUseInfo = opInfo; | |||
1269 | } | |||
1270 | ||||
1271 | // Parse the successor list, if not explicitly provided. | |||
1272 | if (!parsedSuccessors) { | |||
1273 | if (getToken().is(Token::l_square)) { | |||
1274 | // Check if the operation is not a known terminator. | |||
1275 | if (!result.name.mightHaveTrait<OpTrait::IsTerminator>()) | |||
1276 | return emitError("successors in non-terminator"); | |||
1277 | ||||
1278 | SmallVector<Block *, 2> successors; | |||
1279 | if (parseSuccessors(successors)) | |||
1280 | return failure(); | |||
1281 | result.addSuccessors(successors); | |||
1282 | } | |||
1283 | } else { | |||
1284 | result.addSuccessors(*parsedSuccessors); | |||
1285 | } | |||
1286 | ||||
1287 | // Parse the region list, if not explicitly provided. | |||
1288 | if (!parsedRegions) { | |||
1289 | if (consumeIf(Token::l_paren)) { | |||
1290 | do { | |||
1291 | // Create temporary regions with the top level region as parent. | |||
1292 | result.regions.emplace_back(new Region(topLevelOp)); | |||
1293 | if (parseRegion(*result.regions.back(), /*entryArguments=*/{})) | |||
1294 | return failure(); | |||
1295 | } while (consumeIf(Token::comma)); | |||
1296 | if (parseToken(Token::r_paren, "expected ')' to end region list")) | |||
1297 | return failure(); | |||
1298 | } | |||
1299 | } else { | |||
1300 | result.addRegions(*parsedRegions); | |||
1301 | } | |||
1302 | ||||
1303 | // Parse the attributes, if not explicitly provided. | |||
1304 | if (!parsedAttributes) { | |||
1305 | if (getToken().is(Token::l_brace)) { | |||
1306 | if (parseAttributeDict(result.attributes)) | |||
1307 | return failure(); | |||
1308 | } | |||
1309 | } else { | |||
1310 | result.addAttributes(*parsedAttributes); | |||
1311 | } | |||
1312 | ||||
1313 | // Parse the operation type, if not explicitly provided. | |||
1314 | Location typeLoc = result.location; | |||
1315 | if (!parsedFnType) { | |||
1316 | if (parseToken(Token::colon, "expected ':' followed by operation type")) | |||
1317 | return failure(); | |||
1318 | ||||
1319 | typeLoc = getEncodedSourceLocation(getToken().getLoc()); | |||
1320 | auto type = parseType(); | |||
1321 | if (!type) | |||
1322 | return failure(); | |||
1323 | auto fnType = type.dyn_cast<FunctionType>(); | |||
1324 | if (!fnType) | |||
1325 | return mlir::emitError(typeLoc, "expected function type"); | |||
1326 | ||||
1327 | parsedFnType = fnType; | |||
1328 | } | |||
1329 | ||||
1330 | result.addTypes(parsedFnType->getResults()); | |||
1331 | ||||
1332 | // Check that we have the right number of types for the operands. | |||
1333 | ArrayRef<Type> operandTypes = parsedFnType->getInputs(); | |||
1334 | if (operandTypes.size() != parsedOperandUseInfo->size()) { | |||
1335 | auto plural = "s"[parsedOperandUseInfo->size() == 1]; | |||
1336 | return mlir::emitError(typeLoc, "expected ") | |||
1337 | << parsedOperandUseInfo->size() << " operand type" << plural | |||
1338 | << " but had " << operandTypes.size(); | |||
1339 | } | |||
1340 | ||||
1341 | // Resolve all of the operands. | |||
1342 | for (unsigned i = 0, e = parsedOperandUseInfo->size(); i != e; ++i) { | |||
1343 | result.operands.push_back( | |||
1344 | resolveSSAUse((*parsedOperandUseInfo)[i], operandTypes[i])); | |||
1345 | if (!result.operands.back()) | |||
1346 | return failure(); | |||
1347 | } | |||
1348 | ||||
1349 | return success(); | |||
1350 | } | |||
1351 | ||||
1352 | Operation *OperationParser::parseGenericOperation() { | |||
1353 | // Get location information for the operation. | |||
1354 | auto srcLocation = getEncodedSourceLocation(getToken().getLoc()); | |||
1355 | ||||
1356 | std::string name = getToken().getStringValue(); | |||
1357 | if (name.empty()) | |||
1358 | return (emitError("empty operation name is invalid"), nullptr); | |||
1359 | if (name.find('\0') != StringRef::npos) | |||
1360 | return (emitError("null character not allowed in operation name"), nullptr); | |||
1361 | ||||
1362 | consumeToken(Token::string); | |||
1363 | ||||
1364 | OperationState result(srcLocation, name); | |||
1365 | CleanupOpStateRegions guard{result}; | |||
1366 | ||||
1367 | // Lazy load dialects in the context as needed. | |||
1368 | if (!result.name.isRegistered()) { | |||
1369 | StringRef dialectName = StringRef(name).split('.').first; | |||
1370 | if (!getContext()->getLoadedDialect(dialectName) && | |||
1371 | !getContext()->getOrLoadDialect(dialectName)) { | |||
1372 | if (!getContext()->allowsUnregisteredDialects()) { | |||
1373 | // Emit an error if the dialect couldn't be loaded (i.e., it was not | |||
1374 | // registered) and unregistered dialects aren't allowed. | |||
1375 | emitError("operation being parsed with an unregistered dialect. If " | |||
1376 | "this is intended, please use -allow-unregistered-dialect " | |||
1377 | "with the MLIR tool used"); | |||
1378 | return nullptr; | |||
1379 | } | |||
1380 | } else { | |||
1381 | // Reload the OperationName now that the dialect is loaded. | |||
1382 | result.name = OperationName(name, getContext()); | |||
1383 | } | |||
1384 | } | |||
1385 | ||||
1386 | // If we are populating the parser state, start a new operation definition. | |||
1387 | if (state.asmState) | |||
1388 | state.asmState->startOperationDefinition(result.name); | |||
1389 | ||||
1390 | if (parseGenericOperationAfterOpName(result)) | |||
1391 | return nullptr; | |||
1392 | ||||
1393 | // Create the operation and try to parse a location for it. | |||
1394 | Operation *op = opBuilder.create(result); | |||
1395 | if (parseTrailingLocationSpecifier(op)) | |||
1396 | return nullptr; | |||
1397 | return op; | |||
1398 | } | |||
1399 | ||||
1400 | Operation *OperationParser::parseGenericOperation(Block *insertBlock, | |||
1401 | Block::iterator insertPt) { | |||
1402 | Token nameToken = getToken(); | |||
1403 | ||||
1404 | OpBuilder::InsertionGuard restoreInsertionPoint(opBuilder); | |||
1405 | opBuilder.setInsertionPoint(insertBlock, insertPt); | |||
1406 | Operation *op = parseGenericOperation(); | |||
1407 | if (!op) | |||
1408 | return nullptr; | |||
1409 | ||||
1410 | // If we are populating the parser asm state, finalize this operation | |||
1411 | // definition. | |||
1412 | if (state.asmState) | |||
1413 | state.asmState->finalizeOperationDefinition(op, nameToken.getLocRange(), | |||
1414 | /*endLoc=*/getToken().getLoc()); | |||
1415 | return op; | |||
1416 | } | |||
1417 | ||||
1418 | namespace { | |||
1419 | class CustomOpAsmParser : public AsmParserImpl<OpAsmParser> { | |||
1420 | public: | |||
1421 | CustomOpAsmParser( | |||
1422 | SMLoc nameLoc, ArrayRef<OperationParser::ResultRecord> resultIDs, | |||
1423 | function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly, | |||
1424 | bool isIsolatedFromAbove, StringRef opName, OperationParser &parser) | |||
1425 | : AsmParserImpl<OpAsmParser>(nameLoc, parser), resultIDs(resultIDs), | |||
1426 | parseAssembly(parseAssembly), isIsolatedFromAbove(isIsolatedFromAbove), | |||
1427 | opName(opName), parser(parser) { | |||
1428 | (void)isIsolatedFromAbove; // Only used in assert, silence unused warning. | |||
1429 | } | |||
1430 | ||||
1431 | /// Parse an instance of the operation described by 'opDefinition' into the | |||
1432 | /// provided operation state. | |||
1433 | ParseResult parseOperation(OperationState &opState) { | |||
1434 | if (parseAssembly(*this, opState)) | |||
1435 | return failure(); | |||
1436 | // Verify that the parsed attributes does not have duplicate attributes. | |||
1437 | // This can happen if an attribute set during parsing is also specified in | |||
1438 | // the attribute dictionary in the assembly, or the attribute is set | |||
1439 | // multiple during parsing. | |||
1440 | std::optional<NamedAttribute> duplicate = | |||
1441 | opState.attributes.findDuplicate(); | |||
1442 | if (duplicate) | |||
1443 | return emitError(getNameLoc(), "attribute '") | |||
1444 | << duplicate->getName().getValue() | |||
1445 | << "' occurs more than once in the attribute list"; | |||
1446 | return success(); | |||
1447 | } | |||
1448 | ||||
1449 | Operation *parseGenericOperation(Block *insertBlock, | |||
1450 | Block::iterator insertPt) final { | |||
1451 | return parser.parseGenericOperation(insertBlock, insertPt); | |||
1452 | } | |||
1453 | ||||
1454 | FailureOr<OperationName> parseCustomOperationName() final { | |||
1455 | return parser.parseCustomOperationName(); | |||
1456 | } | |||
1457 | ||||
1458 | ParseResult parseGenericOperationAfterOpName( | |||
1459 | OperationState &result, | |||
1460 | std::optional<ArrayRef<UnresolvedOperand>> parsedUnresolvedOperands, | |||
1461 | std::optional<ArrayRef<Block *>> parsedSuccessors, | |||
1462 | std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions, | |||
1463 | std::optional<ArrayRef<NamedAttribute>> parsedAttributes, | |||
1464 | std::optional<FunctionType> parsedFnType) final { | |||
1465 | return parser.parseGenericOperationAfterOpName( | |||
1466 | result, parsedUnresolvedOperands, parsedSuccessors, parsedRegions, | |||
1467 | parsedAttributes, parsedFnType); | |||
1468 | } | |||
1469 | //===--------------------------------------------------------------------===// | |||
1470 | // Utilities | |||
1471 | //===--------------------------------------------------------------------===// | |||
1472 | ||||
1473 | /// Return the name of the specified result in the specified syntax, as well | |||
1474 | /// as the subelement in the name. For example, in this operation: | |||
1475 | /// | |||
1476 | /// %x, %y:2, %z = foo.op | |||
1477 | /// | |||
1478 | /// getResultName(0) == {"x", 0 } | |||
1479 | /// getResultName(1) == {"y", 0 } | |||
1480 | /// getResultName(2) == {"y", 1 } | |||
1481 | /// getResultName(3) == {"z", 0 } | |||
1482 | std::pair<StringRef, unsigned> | |||
1483 | getResultName(unsigned resultNo) const override { | |||
1484 | // Scan for the resultID that contains this result number. | |||
1485 | for (const auto &entry : resultIDs) { | |||
1486 | if (resultNo < std::get<1>(entry)) { | |||
1487 | // Don't pass on the leading %. | |||
1488 | StringRef name = std::get<0>(entry).drop_front(); | |||
1489 | return {name, resultNo}; | |||
1490 | } | |||
1491 | resultNo -= std::get<1>(entry); | |||
1492 | } | |||
1493 | ||||
1494 | // Invalid result number. | |||
1495 | return {"", ~0U}; | |||
1496 | } | |||
1497 | ||||
1498 | /// Return the number of declared SSA results. This returns 4 for the foo.op | |||
1499 | /// example in the comment for getResultName. | |||
1500 | size_t getNumResults() const override { | |||
1501 | size_t count = 0; | |||
1502 | for (auto &entry : resultIDs) | |||
1503 | count += std::get<1>(entry); | |||
1504 | return count; | |||
1505 | } | |||
1506 | ||||
1507 | /// Emit a diagnostic at the specified location and return failure. | |||
1508 | InFlightDiagnostic emitError(SMLoc loc, const Twine &message) override { | |||
1509 | return AsmParserImpl<OpAsmParser>::emitError(loc, "custom op '" + opName + | |||
1510 | "' " + message); | |||
1511 | } | |||
1512 | ||||
1513 | //===--------------------------------------------------------------------===// | |||
1514 | // Operand Parsing | |||
1515 | //===--------------------------------------------------------------------===// | |||
1516 | ||||
1517 | /// Parse a single operand. | |||
1518 | ParseResult parseOperand(UnresolvedOperand &result, | |||
1519 | bool allowResultNumber = true) override { | |||
1520 | OperationParser::UnresolvedOperand useInfo; | |||
1521 | if (parser.parseSSAUse(useInfo, allowResultNumber)) | |||
1522 | return failure(); | |||
1523 | ||||
1524 | result = {useInfo.location, useInfo.name, useInfo.number}; | |||
1525 | return success(); | |||
1526 | } | |||
1527 | ||||
1528 | /// Parse a single operand if present. | |||
1529 | OptionalParseResult | |||
1530 | parseOptionalOperand(UnresolvedOperand &result, | |||
1531 | bool allowResultNumber = true) override { | |||
1532 | if (parser.getToken().isOrIsCodeCompletionFor(Token::percent_identifier)) | |||
1533 | return parseOperand(result, allowResultNumber); | |||
1534 | return std::nullopt; | |||
1535 | } | |||
1536 | ||||
1537 | /// Parse zero or more SSA comma-separated operand references with a specified | |||
1538 | /// surrounding delimiter, and an optional required operand count. | |||
1539 | ParseResult parseOperandList(SmallVectorImpl<UnresolvedOperand> &result, | |||
1540 | Delimiter delimiter = Delimiter::None, | |||
1541 | bool allowResultNumber = true, | |||
1542 | int requiredOperandCount = -1) override { | |||
1543 | // The no-delimiter case has some special handling for better diagnostics. | |||
1544 | if (delimiter == Delimiter::None) { | |||
1545 | // parseCommaSeparatedList doesn't handle the missing case for "none", | |||
1546 | // so we handle it custom here. | |||
1547 | Token tok = parser.getToken(); | |||
1548 | if (!tok.isOrIsCodeCompletionFor(Token::percent_identifier)) { | |||
1549 | // If we didn't require any operands or required exactly zero (weird) | |||
1550 | // then this is success. | |||
1551 | if (requiredOperandCount == -1 || requiredOperandCount == 0) | |||
1552 | return success(); | |||
1553 | ||||
1554 | // Otherwise, try to produce a nice error message. | |||
1555 | if (tok.isAny(Token::l_paren, Token::l_square)) | |||
1556 | return parser.emitError("unexpected delimiter"); | |||
1557 | return parser.emitWrongTokenError("expected operand"); | |||
1558 | } | |||
1559 | } | |||
1560 | ||||
1561 | auto parseOneOperand = [&]() -> ParseResult { | |||
1562 | return parseOperand(result.emplace_back(), allowResultNumber); | |||
1563 | }; | |||
1564 | ||||
1565 | auto startLoc = parser.getToken().getLoc(); | |||
1566 | if (parseCommaSeparatedList(delimiter, parseOneOperand, " in operand list")) | |||
1567 | return failure(); | |||
1568 | ||||
1569 | // Check that we got the expected # of elements. | |||
1570 | if (requiredOperandCount != -1 && | |||
1571 | result.size() != static_cast<size_t>(requiredOperandCount)) | |||
1572 | return emitError(startLoc, "expected ") | |||
1573 | << requiredOperandCount << " operands"; | |||
1574 | return success(); | |||
1575 | } | |||
1576 | ||||
1577 | /// Resolve an operand to an SSA value, emitting an error on failure. | |||
1578 | ParseResult resolveOperand(const UnresolvedOperand &operand, Type type, | |||
1579 | SmallVectorImpl<Value> &result) override { | |||
1580 | if (auto value = parser.resolveSSAUse(operand, type)) { | |||
1581 | result.push_back(value); | |||
1582 | return success(); | |||
1583 | } | |||
1584 | return failure(); | |||
1585 | } | |||
1586 | ||||
1587 | /// Parse an AffineMap of SSA ids. | |||
1588 | ParseResult | |||
1589 | parseAffineMapOfSSAIds(SmallVectorImpl<UnresolvedOperand> &operands, | |||
1590 | Attribute &mapAttr, StringRef attrName, | |||
1591 | NamedAttrList &attrs, Delimiter delimiter) override { | |||
1592 | SmallVector<UnresolvedOperand, 2> dimOperands; | |||
1593 | SmallVector<UnresolvedOperand, 1> symOperands; | |||
1594 | ||||
1595 | auto parseElement = [&](bool isSymbol) -> ParseResult { | |||
1596 | UnresolvedOperand operand; | |||
1597 | if (parseOperand(operand)) | |||
1598 | return failure(); | |||
1599 | if (isSymbol) | |||
1600 | symOperands.push_back(operand); | |||
1601 | else | |||
1602 | dimOperands.push_back(operand); | |||
1603 | return success(); | |||
1604 | }; | |||
1605 | ||||
1606 | AffineMap map; | |||
1607 | if (parser.parseAffineMapOfSSAIds(map, parseElement, delimiter)) | |||
1608 | return failure(); | |||
1609 | // Add AffineMap attribute. | |||
1610 | if (map) { | |||
1611 | mapAttr = AffineMapAttr::get(map); | |||
1612 | attrs.push_back(parser.builder.getNamedAttr(attrName, mapAttr)); | |||
1613 | } | |||
1614 | ||||
1615 | // Add dim operands before symbol operands in 'operands'. | |||
1616 | operands.assign(dimOperands.begin(), dimOperands.end()); | |||
1617 | operands.append(symOperands.begin(), symOperands.end()); | |||
1618 | return success(); | |||
1619 | } | |||
1620 | ||||
1621 | /// Parse an AffineExpr of SSA ids. | |||
1622 | ParseResult | |||
1623 | parseAffineExprOfSSAIds(SmallVectorImpl<UnresolvedOperand> &dimOperands, | |||
1624 | SmallVectorImpl<UnresolvedOperand> &symbOperands, | |||
1625 | AffineExpr &expr) override { | |||
1626 | auto parseElement = [&](bool isSymbol) -> ParseResult { | |||
1627 | UnresolvedOperand operand; | |||
1628 | if (parseOperand(operand)) | |||
1629 | return failure(); | |||
1630 | if (isSymbol) | |||
1631 | symbOperands.push_back(operand); | |||
1632 | else | |||
1633 | dimOperands.push_back(operand); | |||
1634 | return success(); | |||
1635 | }; | |||
1636 | ||||
1637 | return parser.parseAffineExprOfSSAIds(expr, parseElement); | |||
1638 | } | |||
1639 | ||||
1640 | //===--------------------------------------------------------------------===// | |||
1641 | // Argument Parsing | |||
1642 | //===--------------------------------------------------------------------===// | |||
1643 | ||||
1644 | /// Parse a single argument with the following syntax: | |||
1645 | /// | |||
1646 | /// `%ssaname : !type { optionalAttrDict} loc(optionalSourceLoc)` | |||
1647 | /// | |||
1648 | /// If `allowType` is false or `allowAttrs` are false then the respective | |||
1649 | /// parts of the grammar are not parsed. | |||
1650 | ParseResult parseArgument(Argument &result, bool allowType = false, | |||
1651 | bool allowAttrs = false) override { | |||
1652 | NamedAttrList attrs; | |||
1653 | if (parseOperand(result.ssaName, /*allowResultNumber=*/false) || | |||
1654 | (allowType && parseColonType(result.type)) || | |||
1655 | (allowAttrs && parseOptionalAttrDict(attrs)) || | |||
1656 | parseOptionalLocationSpecifier(result.sourceLoc)) | |||
1657 | return failure(); | |||
1658 | result.attrs = attrs.getDictionary(getContext()); | |||
1659 | return success(); | |||
1660 | } | |||
1661 | ||||
1662 | /// Parse a single argument if present. | |||
1663 | OptionalParseResult parseOptionalArgument(Argument &result, bool allowType, | |||
1664 | bool allowAttrs) override { | |||
1665 | if (parser.getToken().is(Token::percent_identifier)) | |||
1666 | return parseArgument(result, allowType, allowAttrs); | |||
1667 | return std::nullopt; | |||
1668 | } | |||
1669 | ||||
1670 | ParseResult parseArgumentList(SmallVectorImpl<Argument> &result, | |||
1671 | Delimiter delimiter, bool allowType, | |||
1672 | bool allowAttrs) override { | |||
1673 | // The no-delimiter case has some special handling for the empty case. | |||
1674 | if (delimiter == Delimiter::None && | |||
1675 | parser.getToken().isNot(Token::percent_identifier)) | |||
1676 | return success(); | |||
1677 | ||||
1678 | auto parseOneArgument = [&]() -> ParseResult { | |||
1679 | return parseArgument(result.emplace_back(), allowType, allowAttrs); | |||
1680 | }; | |||
1681 | return parseCommaSeparatedList(delimiter, parseOneArgument, | |||
1682 | " in argument list"); | |||
1683 | } | |||
1684 | ||||
1685 | //===--------------------------------------------------------------------===// | |||
1686 | // Region Parsing | |||
1687 | //===--------------------------------------------------------------------===// | |||
1688 | ||||
1689 | /// Parse a region that takes `arguments` of `argTypes` types. This | |||
1690 | /// effectively defines the SSA values of `arguments` and assigns their type. | |||
1691 | ParseResult parseRegion(Region ®ion, ArrayRef<Argument> arguments, | |||
1692 | bool enableNameShadowing) override { | |||
1693 | // Try to parse the region. | |||
1694 | (void)isIsolatedFromAbove; | |||
1695 | assert((!enableNameShadowing || isIsolatedFromAbove) &&(static_cast <bool> ((!enableNameShadowing || isIsolatedFromAbove ) && "name shadowing is only allowed on isolated regions" ) ? void (0) : __assert_fail ("(!enableNameShadowing || isIsolatedFromAbove) && \"name shadowing is only allowed on isolated regions\"" , "mlir/lib/AsmParser/Parser.cpp", 1696, __extension__ __PRETTY_FUNCTION__ )) | |||
1696 | "name shadowing is only allowed on isolated regions")(static_cast <bool> ((!enableNameShadowing || isIsolatedFromAbove ) && "name shadowing is only allowed on isolated regions" ) ? void (0) : __assert_fail ("(!enableNameShadowing || isIsolatedFromAbove) && \"name shadowing is only allowed on isolated regions\"" , "mlir/lib/AsmParser/Parser.cpp", 1696, __extension__ __PRETTY_FUNCTION__ )); | |||
1697 | if (parser.parseRegion(region, arguments, enableNameShadowing)) | |||
1698 | return failure(); | |||
1699 | return success(); | |||
1700 | } | |||
1701 | ||||
1702 | /// Parses a region if present. | |||
1703 | OptionalParseResult parseOptionalRegion(Region ®ion, | |||
1704 | ArrayRef<Argument> arguments, | |||
1705 | bool enableNameShadowing) override { | |||
1706 | if (parser.getToken().isNot(Token::l_brace)) | |||
1707 | return std::nullopt; | |||
1708 | return parseRegion(region, arguments, enableNameShadowing); | |||
1709 | } | |||
1710 | ||||
1711 | /// Parses a region if present. If the region is present, a new region is | |||
1712 | /// allocated and placed in `region`. If no region is present, `region` | |||
1713 | /// remains untouched. | |||
1714 | OptionalParseResult | |||
1715 | parseOptionalRegion(std::unique_ptr<Region> ®ion, | |||
1716 | ArrayRef<Argument> arguments, | |||
1717 | bool enableNameShadowing = false) override { | |||
1718 | if (parser.getToken().isNot(Token::l_brace)) | |||
1719 | return std::nullopt; | |||
1720 | std::unique_ptr<Region> newRegion = std::make_unique<Region>(); | |||
1721 | if (parseRegion(*newRegion, arguments, enableNameShadowing)) | |||
1722 | return failure(); | |||
1723 | ||||
1724 | region = std::move(newRegion); | |||
1725 | return success(); | |||
1726 | } | |||
1727 | ||||
1728 | //===--------------------------------------------------------------------===// | |||
1729 | // Successor Parsing | |||
1730 | //===--------------------------------------------------------------------===// | |||
1731 | ||||
1732 | /// Parse a single operation successor. | |||
1733 | ParseResult parseSuccessor(Block *&dest) override { | |||
1734 | return parser.parseSuccessor(dest); | |||
1735 | } | |||
1736 | ||||
1737 | /// Parse an optional operation successor and its operand list. | |||
1738 | OptionalParseResult parseOptionalSuccessor(Block *&dest) override { | |||
1739 | if (!parser.getToken().isOrIsCodeCompletionFor(Token::caret_identifier)) | |||
1740 | return std::nullopt; | |||
1741 | return parseSuccessor(dest); | |||
1742 | } | |||
1743 | ||||
1744 | /// Parse a single operation successor and its operand list. | |||
1745 | ParseResult | |||
1746 | parseSuccessorAndUseList(Block *&dest, | |||
1747 | SmallVectorImpl<Value> &operands) override { | |||
1748 | if (parseSuccessor(dest)) | |||
1749 | return failure(); | |||
1750 | ||||
1751 | // Handle optional arguments. | |||
1752 | if (succeeded(parseOptionalLParen()) && | |||
1753 | (parser.parseOptionalSSAUseAndTypeList(operands) || parseRParen())) { | |||
1754 | return failure(); | |||
1755 | } | |||
1756 | return success(); | |||
1757 | } | |||
1758 | ||||
1759 | //===--------------------------------------------------------------------===// | |||
1760 | // Type Parsing | |||
1761 | //===--------------------------------------------------------------------===// | |||
1762 | ||||
1763 | /// Parse a list of assignments of the form | |||
1764 | /// (%x1 = %y1, %x2 = %y2, ...). | |||
1765 | OptionalParseResult parseOptionalAssignmentList( | |||
1766 | SmallVectorImpl<Argument> &lhs, | |||
1767 | SmallVectorImpl<UnresolvedOperand> &rhs) override { | |||
1768 | if (failed(parseOptionalLParen())) | |||
1769 | return std::nullopt; | |||
1770 | ||||
1771 | auto parseElt = [&]() -> ParseResult { | |||
1772 | if (parseArgument(lhs.emplace_back()) || parseEqual() || | |||
1773 | parseOperand(rhs.emplace_back())) | |||
1774 | return failure(); | |||
1775 | return success(); | |||
1776 | }; | |||
1777 | return parser.parseCommaSeparatedListUntil(Token::r_paren, parseElt); | |||
1778 | } | |||
1779 | ||||
1780 | /// Parse a loc(...) specifier if present, filling in result if so. | |||
1781 | ParseResult | |||
1782 | parseOptionalLocationSpecifier(std::optional<Location> &result) override { | |||
1783 | // If there is a 'loc' we parse a trailing location. | |||
1784 | if (!parser.consumeIf(Token::kw_loc)) | |||
1785 | return success(); | |||
1786 | LocationAttr directLoc; | |||
1787 | if (parser.parseToken(Token::l_paren, "expected '(' in location")) | |||
1788 | return failure(); | |||
1789 | ||||
1790 | Token tok = parser.getToken(); | |||
1791 | ||||
1792 | // Check to see if we are parsing a location alias. | |||
1793 | // Otherwise, we parse the location directly. | |||
1794 | if (tok.is(Token::hash_identifier)) { | |||
1795 | if (parser.parseLocationAlias(directLoc)) | |||
1796 | return failure(); | |||
1797 | } else if (parser.parseLocationInstance(directLoc)) { | |||
1798 | return failure(); | |||
1799 | } | |||
1800 | ||||
1801 | if (parser.parseToken(Token::r_paren, "expected ')' in location")) | |||
1802 | return failure(); | |||
1803 | ||||
1804 | result = directLoc; | |||
1805 | return success(); | |||
1806 | } | |||
1807 | ||||
1808 | private: | |||
1809 | /// Information about the result name specifiers. | |||
1810 | ArrayRef<OperationParser::ResultRecord> resultIDs; | |||
1811 | ||||
1812 | /// The abstract information of the operation. | |||
1813 | function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly; | |||
1814 | bool isIsolatedFromAbove; | |||
1815 | StringRef opName; | |||
1816 | ||||
1817 | /// The backing operation parser. | |||
1818 | OperationParser &parser; | |||
1819 | }; | |||
1820 | } // namespace | |||
1821 | ||||
1822 | FailureOr<OperationName> OperationParser::parseCustomOperationName() { | |||
1823 | Token nameTok = getToken(); | |||
1824 | StringRef opName = nameTok.getSpelling(); | |||
1825 | if (opName.empty()) | |||
1826 | return (emitError("empty operation name is invalid"), failure()); | |||
1827 | consumeToken(); | |||
1828 | ||||
1829 | // Check to see if this operation name is already registered. | |||
1830 | std::optional<RegisteredOperationName> opInfo = | |||
1831 | RegisteredOperationName::lookup(opName, getContext()); | |||
1832 | if (opInfo) | |||
1833 | return *opInfo; | |||
1834 | ||||
1835 | // If the operation doesn't have a dialect prefix try using the default | |||
1836 | // dialect. | |||
1837 | auto opNameSplit = opName.split('.'); | |||
1838 | StringRef dialectName = opNameSplit.first; | |||
1839 | std::string opNameStorage; | |||
1840 | if (opNameSplit.second.empty()) { | |||
1841 | // If the name didn't have a prefix, check for a code completion request. | |||
1842 | if (getToken().isCodeCompletion() && opName.back() == '.') | |||
1843 | return codeCompleteOperationName(dialectName); | |||
1844 | ||||
1845 | dialectName = getState().defaultDialectStack.back(); | |||
1846 | opNameStorage = (dialectName + "." + opName).str(); | |||
1847 | opName = opNameStorage; | |||
1848 | } | |||
1849 | ||||
1850 | // Try to load the dialect before returning the operation name to make sure | |||
1851 | // the operation has a chance to be registered. | |||
1852 | getContext()->getOrLoadDialect(dialectName); | |||
1853 | return OperationName(opName, getContext()); | |||
1854 | } | |||
1855 | ||||
1856 | Operation * | |||
1857 | OperationParser::parseCustomOperation(ArrayRef<ResultRecord> resultIDs) { | |||
1858 | SMLoc opLoc = getToken().getLoc(); | |||
1859 | StringRef originalOpName = getTokenSpelling(); | |||
1860 | ||||
1861 | FailureOr<OperationName> opNameInfo = parseCustomOperationName(); | |||
1862 | if (failed(opNameInfo)) | |||
1863 | return nullptr; | |||
1864 | StringRef opName = opNameInfo->getStringRef(); | |||
1865 | ||||
1866 | // This is the actual hook for the custom op parsing, usually implemented by | |||
1867 | // the op itself (`Op::parse()`). We retrieve it either from the | |||
1868 | // RegisteredOperationName or from the Dialect. | |||
1869 | OperationName::ParseAssemblyFn parseAssemblyFn; | |||
1870 | bool isIsolatedFromAbove = false; | |||
1871 | ||||
1872 | StringRef defaultDialect = ""; | |||
1873 | if (auto opInfo = opNameInfo->getRegisteredInfo()) { | |||
1874 | parseAssemblyFn = opInfo->getParseAssemblyFn(); | |||
1875 | isIsolatedFromAbove = opInfo->hasTrait<OpTrait::IsIsolatedFromAbove>(); | |||
1876 | auto *iface = opInfo->getInterface<OpAsmOpInterface>(); | |||
1877 | if (iface && !iface->getDefaultDialect().empty()) | |||
1878 | defaultDialect = iface->getDefaultDialect(); | |||
1879 | } else { | |||
1880 | std::optional<Dialect::ParseOpHook> dialectHook; | |||
1881 | Dialect *dialect = opNameInfo->getDialect(); | |||
1882 | if (!dialect) { | |||
1883 | InFlightDiagnostic diag = | |||
1884 | emitError(opLoc) << "Dialect `" << opNameInfo->getDialectNamespace() | |||
1885 | << "' not found for custom op '" << originalOpName | |||
1886 | << "' "; | |||
1887 | if (originalOpName != opName) | |||
1888 | diag << " (tried '" << opName << "' as well)"; | |||
1889 | auto ¬e = diag.attachNote(); | |||
1890 | note << "Registered dialects: "; | |||
1891 | llvm::interleaveComma(getContext()->getAvailableDialects(), note, | |||
1892 | [&](StringRef dialect) { note << dialect; }); | |||
1893 | note << " ; for more info on dialect registration see " | |||
1894 | "https://mlir.llvm.org/getting_started/Faq/" | |||
1895 | "#registered-loaded-dependent-whats-up-with-dialects-management"; | |||
1896 | return nullptr; | |||
1897 | } | |||
1898 | dialectHook = dialect->getParseOperationHook(opName); | |||
1899 | if (!dialectHook) { | |||
1900 | InFlightDiagnostic diag = | |||
1901 | emitError(opLoc) << "custom op '" << originalOpName << "' is unknown"; | |||
1902 | if (originalOpName != opName) | |||
1903 | diag << " (tried '" << opName << "' as well)"; | |||
1904 | return nullptr; | |||
1905 | } | |||
1906 | parseAssemblyFn = *dialectHook; | |||
1907 | } | |||
1908 | getState().defaultDialectStack.push_back(defaultDialect); | |||
1909 | auto restoreDefaultDialect = llvm::make_scope_exit( | |||
1910 | [&]() { getState().defaultDialectStack.pop_back(); }); | |||
1911 | ||||
1912 | // If the custom op parser crashes, produce some indication to help | |||
1913 | // debugging. | |||
1914 | llvm::PrettyStackTraceFormat fmt("MLIR Parser: custom op parser '%s'", | |||
1915 | opNameInfo->getIdentifier().data()); | |||
1916 | ||||
1917 | // Get location information for the operation. | |||
1918 | auto srcLocation = getEncodedSourceLocation(opLoc); | |||
1919 | OperationState opState(srcLocation, *opNameInfo); | |||
1920 | ||||
1921 | // If we are populating the parser state, start a new operation definition. | |||
1922 | if (state.asmState) | |||
1923 | state.asmState->startOperationDefinition(opState.name); | |||
1924 | ||||
1925 | // Have the op implementation take a crack and parsing this. | |||
1926 | CleanupOpStateRegions guard{opState}; | |||
1927 | CustomOpAsmParser opAsmParser(opLoc, resultIDs, parseAssemblyFn, | |||
1928 | isIsolatedFromAbove, opName, *this); | |||
1929 | if (opAsmParser.parseOperation(opState)) | |||
1930 | return nullptr; | |||
1931 | ||||
1932 | // If it emitted an error, we failed. | |||
1933 | if (opAsmParser.didEmitError()) | |||
1934 | return nullptr; | |||
1935 | ||||
1936 | // Otherwise, create the operation and try to parse a location for it. | |||
1937 | Operation *op = opBuilder.create(opState); | |||
1938 | if (parseTrailingLocationSpecifier(op)) | |||
1939 | return nullptr; | |||
1940 | return op; | |||
1941 | } | |||
1942 | ||||
1943 | ParseResult OperationParser::parseLocationAlias(LocationAttr &loc) { | |||
1944 | Token tok = getToken(); | |||
1945 | consumeToken(Token::hash_identifier); | |||
1946 | StringRef identifier = tok.getSpelling().drop_front(); | |||
1947 | if (identifier.contains('.')) { | |||
1948 | return emitError(tok.getLoc()) | |||
1949 | << "expected location, but found dialect attribute: '#" << identifier | |||
1950 | << "'"; | |||
1951 | } | |||
1952 | ||||
1953 | // If this alias can be resolved, do it now. | |||
1954 | Attribute attr = state.symbols.attributeAliasDefinitions.lookup(identifier); | |||
1955 | if (attr) { | |||
1956 | if (!(loc = dyn_cast<LocationAttr>(attr))) | |||
1957 | return emitError(tok.getLoc()) | |||
1958 | << "expected location, but found '" << attr << "'"; | |||
1959 | } else { | |||
1960 | // Otherwise, remember this operation and resolve its location later. | |||
1961 | // In the meantime, use a special OpaqueLoc as a marker. | |||
1962 | loc = OpaqueLoc::get(deferredLocsReferences.size(), | |||
1963 | TypeID::get<DeferredLocInfo *>(), | |||
1964 | UnknownLoc::get(getContext())); | |||
1965 | deferredLocsReferences.push_back(DeferredLocInfo{tok.getLoc(), identifier}); | |||
1966 | } | |||
1967 | return success(); | |||
1968 | } | |||
1969 | ||||
1970 | ParseResult | |||
1971 | OperationParser::parseTrailingLocationSpecifier(OpOrArgument opOrArgument) { | |||
1972 | // If there is a 'loc' we parse a trailing location. | |||
1973 | if (!consumeIf(Token::kw_loc)) | |||
1974 | return success(); | |||
1975 | if (parseToken(Token::l_paren, "expected '(' in location")) | |||
1976 | return failure(); | |||
1977 | Token tok = getToken(); | |||
1978 | ||||
1979 | // Check to see if we are parsing a location alias. | |||
1980 | // Otherwise, we parse the location directly. | |||
1981 | LocationAttr directLoc; | |||
1982 | if (tok.is(Token::hash_identifier)) { | |||
1983 | if (parseLocationAlias(directLoc)) | |||
1984 | return failure(); | |||
1985 | } else if (parseLocationInstance(directLoc)) { | |||
1986 | return failure(); | |||
1987 | } | |||
1988 | ||||
1989 | if (parseToken(Token::r_paren, "expected ')' in location")) | |||
1990 | return failure(); | |||
1991 | ||||
1992 | if (auto *op = opOrArgument.dyn_cast<Operation *>()) | |||
1993 | op->setLoc(directLoc); | |||
1994 | else | |||
1995 | opOrArgument.get<BlockArgument>().setLoc(directLoc); | |||
1996 | return success(); | |||
1997 | } | |||
1998 | ||||
1999 | //===----------------------------------------------------------------------===// | |||
2000 | // Region Parsing | |||
2001 | //===----------------------------------------------------------------------===// | |||
2002 | ||||
2003 | ParseResult OperationParser::parseRegion(Region ®ion, | |||
2004 | ArrayRef<Argument> entryArguments, | |||
2005 | bool isIsolatedNameScope) { | |||
2006 | // Parse the '{'. | |||
2007 | Token lBraceTok = getToken(); | |||
2008 | if (parseToken(Token::l_brace, "expected '{' to begin a region")) | |||
2009 | return failure(); | |||
2010 | ||||
2011 | // If we are populating the parser state, start a new region definition. | |||
2012 | if (state.asmState) | |||
2013 | state.asmState->startRegionDefinition(); | |||
2014 | ||||
2015 | // Parse the region body. | |||
2016 | if ((!entryArguments.empty() || getToken().isNot(Token::r_brace)) && | |||
2017 | parseRegionBody(region, lBraceTok.getLoc(), entryArguments, | |||
2018 | isIsolatedNameScope)) { | |||
2019 | return failure(); | |||
2020 | } | |||
2021 | consumeToken(Token::r_brace); | |||
2022 | ||||
2023 | // If we are populating the parser state, finalize this region. | |||
2024 | if (state.asmState) | |||
2025 | state.asmState->finalizeRegionDefinition(); | |||
2026 | ||||
2027 | return success(); | |||
2028 | } | |||
2029 | ||||
2030 | ParseResult OperationParser::parseRegionBody(Region ®ion, SMLoc startLoc, | |||
2031 | ArrayRef<Argument> entryArguments, | |||
2032 | bool isIsolatedNameScope) { | |||
2033 | auto currentPt = opBuilder.saveInsertionPoint(); | |||
2034 | ||||
2035 | // Push a new named value scope. | |||
2036 | pushSSANameScope(isIsolatedNameScope); | |||
2037 | ||||
2038 | // Parse the first block directly to allow for it to be unnamed. | |||
2039 | auto owningBlock = std::make_unique<Block>(); | |||
2040 | Block *block = owningBlock.get(); | |||
2041 | ||||
2042 | // If this block is not defined in the source file, add a definition for it | |||
2043 | // now in the assembly state. Blocks with a name will be defined when the name | |||
2044 | // is parsed. | |||
2045 | if (state.asmState && getToken().isNot(Token::caret_identifier)) | |||
2046 | state.asmState->addDefinition(block, startLoc); | |||
2047 | ||||
2048 | // Add arguments to the entry block if we had the form with explicit names. | |||
2049 | if (!entryArguments.empty() && !entryArguments[0].ssaName.name.empty()) { | |||
2050 | // If we had named arguments, then don't allow a block name. | |||
2051 | if (getToken().is(Token::caret_identifier)) | |||
2052 | return emitError("invalid block name in region with named arguments"); | |||
2053 | ||||
2054 | for (auto &entryArg : entryArguments) { | |||
2055 | auto &argInfo = entryArg.ssaName; | |||
2056 | ||||
2057 | // Ensure that the argument was not already defined. | |||
2058 | if (auto defLoc = getReferenceLoc(argInfo.name, argInfo.number)) { | |||
2059 | return emitError(argInfo.location, "region entry argument '" + | |||
2060 | argInfo.name + | |||
2061 | "' is already in use") | |||
2062 | .attachNote(getEncodedSourceLocation(*defLoc)) | |||
2063 | << "previously referenced here"; | |||
2064 | } | |||
2065 | Location loc = entryArg.sourceLoc.has_value() | |||
2066 | ? *entryArg.sourceLoc | |||
2067 | : getEncodedSourceLocation(argInfo.location); | |||
2068 | BlockArgument arg = block->addArgument(entryArg.type, loc); | |||
2069 | ||||
2070 | // Add a definition of this arg to the assembly state if provided. | |||
2071 | if (state.asmState) | |||
2072 | state.asmState->addDefinition(arg, argInfo.location); | |||
2073 | ||||
2074 | // Record the definition for this argument. | |||
2075 | if (addDefinition(argInfo, arg)) | |||
2076 | return failure(); | |||
2077 | } | |||
2078 | } | |||
2079 | ||||
2080 | if (parseBlock(block)) | |||
2081 | return failure(); | |||
2082 | ||||
2083 | // Verify that no other arguments were parsed. | |||
2084 | if (!entryArguments.empty() && | |||
2085 | block->getNumArguments() > entryArguments.size()) { | |||
2086 | return emitError("entry block arguments were already defined"); | |||
2087 | } | |||
2088 | ||||
2089 | // Parse the rest of the region. | |||
2090 | region.push_back(owningBlock.release()); | |||
2091 | while (getToken().isNot(Token::r_brace)) { | |||
2092 | Block *newBlock = nullptr; | |||
2093 | if (parseBlock(newBlock)) | |||
2094 | return failure(); | |||
2095 | region.push_back(newBlock); | |||
2096 | } | |||
2097 | ||||
2098 | // Pop the SSA value scope for this region. | |||
2099 | if (popSSANameScope()) | |||
2100 | return failure(); | |||
2101 | ||||
2102 | // Reset the original insertion point. | |||
2103 | opBuilder.restoreInsertionPoint(currentPt); | |||
2104 | return success(); | |||
2105 | } | |||
2106 | ||||
2107 | //===----------------------------------------------------------------------===// | |||
2108 | // Block Parsing | |||
2109 | //===----------------------------------------------------------------------===// | |||
2110 | ||||
2111 | /// Block declaration. | |||
2112 | /// | |||
2113 | /// block ::= block-label? operation* | |||
2114 | /// block-label ::= block-id block-arg-list? `:` | |||
2115 | /// block-id ::= caret-id | |||
2116 | /// block-arg-list ::= `(` ssa-id-and-type-list? `)` | |||
2117 | /// | |||
2118 | ParseResult OperationParser::parseBlock(Block *&block) { | |||
2119 | // The first block of a region may already exist, if it does the caret | |||
2120 | // identifier is optional. | |||
2121 | if (block && getToken().isNot(Token::caret_identifier)) | |||
2122 | return parseBlockBody(block); | |||
2123 | ||||
2124 | SMLoc nameLoc = getToken().getLoc(); | |||
2125 | auto name = getTokenSpelling(); | |||
2126 | if (parseToken(Token::caret_identifier, "expected block name")) | |||
2127 | return failure(); | |||
2128 | ||||
2129 | // Define the block with the specified name. | |||
2130 | auto &blockAndLoc = getBlockInfoByName(name); | |||
2131 | blockAndLoc.loc = nameLoc; | |||
2132 | ||||
2133 | // Use a unique pointer for in-flight block being parsed. Release ownership | |||
2134 | // only in the case of a successful parse. This ensures that the Block | |||
2135 | // allocated is released if the parse fails and control returns early. | |||
2136 | std::unique_ptr<Block> inflightBlock; | |||
2137 | auto cleanupOnFailure = llvm::make_scope_exit([&] { | |||
2138 | if (inflightBlock) | |||
2139 | inflightBlock->dropAllDefinedValueUses(); | |||
2140 | }); | |||
2141 | ||||
2142 | // If a block has yet to be set, this is a new definition. If the caller | |||
2143 | // provided a block, use it. Otherwise create a new one. | |||
2144 | if (!blockAndLoc.block) { | |||
2145 | if (block) { | |||
2146 | blockAndLoc.block = block; | |||
2147 | } else { | |||
2148 | inflightBlock = std::make_unique<Block>(); | |||
2149 | blockAndLoc.block = inflightBlock.get(); | |||
2150 | } | |||
2151 | ||||
2152 | // Otherwise, the block has a forward declaration. Forward declarations are | |||
2153 | // removed once defined, so if we are defining a existing block and it is | |||
2154 | // not a forward declaration, then it is a redeclaration. Fail if the block | |||
2155 | // was already defined. | |||
2156 | } else if (!eraseForwardRef(blockAndLoc.block)) { | |||
2157 | return emitError(nameLoc, "redefinition of block '") << name << "'"; | |||
2158 | } else { | |||
2159 | // This was a forward reference block that is now floating. Keep track of it | |||
2160 | // as inflight in case of error, so that it gets cleaned up properly. | |||
2161 | inflightBlock.reset(blockAndLoc.block); | |||
2162 | } | |||
2163 | ||||
2164 | // Populate the high level assembly state if necessary. | |||
2165 | if (state.asmState) | |||
2166 | state.asmState->addDefinition(blockAndLoc.block, nameLoc); | |||
2167 | block = blockAndLoc.block; | |||
2168 | ||||
2169 | // If an argument list is present, parse it. | |||
2170 | if (getToken().is(Token::l_paren)) | |||
2171 | if (parseOptionalBlockArgList(block)) | |||
2172 | return failure(); | |||
2173 | if (parseToken(Token::colon, "expected ':' after block name")) | |||
2174 | return failure(); | |||
2175 | ||||
2176 | // Parse the body of the block. | |||
2177 | ParseResult res = parseBlockBody(block); | |||
2178 | ||||
2179 | // If parsing was successful, drop the inflight block. We relinquish ownership | |||
2180 | // back up to the caller. | |||
2181 | if (succeeded(res)) | |||
2182 | (void)inflightBlock.release(); | |||
2183 | return res; | |||
2184 | } | |||
2185 | ||||
2186 | ParseResult OperationParser::parseBlockBody(Block *block) { | |||
2187 | // Set the insertion point to the end of the block to parse. | |||
2188 | opBuilder.setInsertionPointToEnd(block); | |||
2189 | ||||
2190 | // Parse the list of operations that make up the body of the block. | |||
2191 | while (getToken().isNot(Token::caret_identifier, Token::r_brace)) | |||
2192 | if (parseOperation()) | |||
2193 | return failure(); | |||
2194 | ||||
2195 | return success(); | |||
2196 | } | |||
2197 | ||||
2198 | /// Get the block with the specified name, creating it if it doesn't already | |||
2199 | /// exist. The location specified is the point of use, which allows | |||
2200 | /// us to diagnose references to blocks that are not defined precisely. | |||
2201 | Block *OperationParser::getBlockNamed(StringRef name, SMLoc loc) { | |||
2202 | BlockDefinition &blockDef = getBlockInfoByName(name); | |||
2203 | if (!blockDef.block) { | |||
2204 | blockDef = {new Block(), loc}; | |||
2205 | insertForwardRef(blockDef.block, blockDef.loc); | |||
2206 | } | |||
2207 | ||||
2208 | // Populate the high level assembly state if necessary. | |||
2209 | if (state.asmState) | |||
2210 | state.asmState->addUses(blockDef.block, loc); | |||
2211 | ||||
2212 | return blockDef.block; | |||
2213 | } | |||
2214 | ||||
2215 | /// Parse a (possibly empty) list of SSA operands with types as block arguments | |||
2216 | /// enclosed in parentheses. | |||
2217 | /// | |||
2218 | /// value-id-and-type-list ::= value-id-and-type (`,` ssa-id-and-type)* | |||
2219 | /// block-arg-list ::= `(` value-id-and-type-list? `)` | |||
2220 | /// | |||
2221 | ParseResult OperationParser::parseOptionalBlockArgList(Block *owner) { | |||
2222 | if (getToken().is(Token::r_brace)) | |||
2223 | return success(); | |||
2224 | ||||
2225 | // If the block already has arguments, then we're handling the entry block. | |||
2226 | // Parse and register the names for the arguments, but do not add them. | |||
2227 | bool definingExistingArgs = owner->getNumArguments() != 0; | |||
2228 | unsigned nextArgument = 0; | |||
2229 | ||||
2230 | return parseCommaSeparatedList(Delimiter::Paren, [&]() -> ParseResult { | |||
2231 | return parseSSADefOrUseAndType( | |||
2232 | [&](UnresolvedOperand useInfo, Type type) -> ParseResult { | |||
2233 | BlockArgument arg; | |||
2234 | ||||
2235 | // If we are defining existing arguments, ensure that the argument | |||
2236 | // has already been created with the right type. | |||
2237 | if (definingExistingArgs) { | |||
2238 | // Otherwise, ensure that this argument has already been created. | |||
2239 | if (nextArgument >= owner->getNumArguments()) | |||
2240 | return emitError("too many arguments specified in argument list"); | |||
2241 | ||||
2242 | // Finally, make sure the existing argument has the correct type. | |||
2243 | arg = owner->getArgument(nextArgument++); | |||
2244 | if (arg.getType() != type) | |||
2245 | return emitError("argument and block argument type mismatch"); | |||
2246 | } else { | |||
2247 | auto loc = getEncodedSourceLocation(useInfo.location); | |||
2248 | arg = owner->addArgument(type, loc); | |||
2249 | } | |||
2250 | ||||
2251 | // If the argument has an explicit loc(...) specifier, parse and apply | |||
2252 | // it. | |||
2253 | if (parseTrailingLocationSpecifier(arg)) | |||
2254 | return failure(); | |||
2255 | ||||
2256 | // Mark this block argument definition in the parser state if it was | |||
2257 | // provided. | |||
2258 | if (state.asmState) | |||
2259 | state.asmState->addDefinition(arg, useInfo.location); | |||
2260 | ||||
2261 | return addDefinition(useInfo, arg); | |||
2262 | }); | |||
2263 | }); | |||
2264 | } | |||
2265 | ||||
2266 | //===----------------------------------------------------------------------===// | |||
2267 | // Code Completion | |||
2268 | //===----------------------------------------------------------------------===// | |||
2269 | ||||
2270 | ParseResult OperationParser::codeCompleteSSAUse() { | |||
2271 | std::string detailData; | |||
2272 | llvm::raw_string_ostream detailOS(detailData); | |||
2273 | for (IsolatedSSANameScope &scope : isolatedNameScopes) { | |||
2274 | for (auto &it : scope.values) { | |||
2275 | if (it.second.empty()) | |||
2276 | continue; | |||
2277 | Value frontValue = it.second.front().value; | |||
2278 | ||||
2279 | // If the value isn't a forward reference, we also add the name of the op | |||
2280 | // to the detail. | |||
2281 | if (auto result = dyn_cast<OpResult>(frontValue)) { | |||
2282 | if (!forwardRefPlaceholders.count(result)) | |||
2283 | detailOS << result.getOwner()->getName() << ": "; | |||
2284 | } else { | |||
2285 | detailOS << "arg #" << frontValue.cast<BlockArgument>().getArgNumber() | |||
2286 | << ": "; | |||
2287 | } | |||
2288 | ||||
2289 | // Emit the type of the values to aid with completion selection. | |||
2290 | detailOS << frontValue.getType(); | |||
2291 | ||||
2292 | // FIXME: We should define a policy for packed values, e.g. with a limit | |||
2293 | // on the detail size, but it isn't clear what would be useful right now. | |||
2294 | // For now we just only emit the first type. | |||
2295 | if (it.second.size() > 1) | |||
2296 | detailOS << ", ..."; | |||
2297 | ||||
2298 | state.codeCompleteContext->appendSSAValueCompletion( | |||
2299 | it.getKey(), std::move(detailOS.str())); | |||
2300 | } | |||
2301 | } | |||
2302 | ||||
2303 | return failure(); | |||
2304 | } | |||
2305 | ||||
2306 | ParseResult OperationParser::codeCompleteBlock() { | |||
2307 | // Don't provide completions if the token isn't empty, e.g. this avoids | |||
2308 | // weirdness when we encounter a `.` within the identifier. | |||
2309 | StringRef spelling = getTokenSpelling(); | |||
2310 | if (!(spelling.empty() || spelling == "^")) | |||
2311 | return failure(); | |||
2312 | ||||
2313 | for (const auto &it : blocksByName.back()) | |||
2314 | state.codeCompleteContext->appendBlockCompletion(it.getFirst()); | |||
2315 | return failure(); | |||
2316 | } | |||
2317 | ||||
2318 | //===----------------------------------------------------------------------===// | |||
2319 | // Top-level entity parsing. | |||
2320 | //===----------------------------------------------------------------------===// | |||
2321 | ||||
2322 | namespace { | |||
2323 | /// This parser handles entities that are only valid at the top level of the | |||
2324 | /// file. | |||
2325 | class TopLevelOperationParser : public Parser { | |||
2326 | public: | |||
2327 | explicit TopLevelOperationParser(ParserState &state) : Parser(state) {} | |||
2328 | ||||
2329 | /// Parse a set of operations into the end of the given Block. | |||
2330 | ParseResult parse(Block *topLevelBlock, Location parserLoc); | |||
2331 | ||||
2332 | private: | |||
2333 | /// Parse an attribute alias declaration. | |||
2334 | /// | |||
2335 | /// attribute-alias-def ::= '#' alias-name `=` attribute-value | |||
2336 | /// | |||
2337 | ParseResult parseAttributeAliasDef(); | |||
2338 | ||||
2339 | /// Parse a type alias declaration. | |||
2340 | /// | |||
2341 | /// type-alias-def ::= '!' alias-name `=` type | |||
2342 | /// | |||
2343 | ParseResult parseTypeAliasDef(); | |||
2344 | ||||
2345 | /// Parse a top-level file metadata dictionary. | |||
2346 | /// | |||
2347 | /// file-metadata-dict ::= '{-#' file-metadata-entry* `#-}' | |||
2348 | /// | |||
2349 | ParseResult parseFileMetadataDictionary(); | |||
2350 | ||||
2351 | /// Parse a resource metadata dictionary. | |||
2352 | ParseResult parseResourceFileMetadata( | |||
2353 | function_ref<ParseResult(StringRef, SMLoc)> parseBody); | |||
2354 | ParseResult parseDialectResourceFileMetadata(); | |||
2355 | ParseResult parseExternalResourceFileMetadata(); | |||
2356 | }; | |||
2357 | ||||
2358 | /// This class represents an implementation of a resource entry for the MLIR | |||
2359 | /// textual format. | |||
2360 | class ParsedResourceEntry : public AsmParsedResourceEntry { | |||
2361 | public: | |||
2362 | ParsedResourceEntry(StringRef key, SMLoc keyLoc, Token value, Parser &p) | |||
2363 | : key(key), keyLoc(keyLoc), value(value), p(p) {} | |||
2364 | ~ParsedResourceEntry() override = default; | |||
2365 | ||||
2366 | StringRef getKey() const final { return key; } | |||
2367 | ||||
2368 | InFlightDiagnostic emitError() const final { return p.emitError(keyLoc); } | |||
2369 | ||||
2370 | AsmResourceEntryKind getKind() const final { | |||
2371 | if (value.isAny(Token::kw_true, Token::kw_false)) | |||
2372 | return AsmResourceEntryKind::Bool; | |||
2373 | return value.getSpelling().startswith("\"0x") | |||
2374 | ? AsmResourceEntryKind::Blob | |||
2375 | : AsmResourceEntryKind::String; | |||
2376 | } | |||
2377 | ||||
2378 | FailureOr<bool> parseAsBool() const final { | |||
2379 | if (value.is(Token::kw_true)) | |||
2380 | return true; | |||
2381 | if (value.is(Token::kw_false)) | |||
2382 | return false; | |||
2383 | return p.emitError(value.getLoc(), | |||
2384 | "expected 'true' or 'false' value for key '" + key + | |||
2385 | "'"); | |||
2386 | } | |||
2387 | ||||
2388 | FailureOr<std::string> parseAsString() const final { | |||
2389 | if (value.isNot(Token::string)) | |||
2390 | return p.emitError(value.getLoc(), | |||
2391 | "expected string value for key '" + key + "'"); | |||
2392 | return value.getStringValue(); | |||
2393 | } | |||
2394 | ||||
2395 | FailureOr<AsmResourceBlob> | |||
2396 | parseAsBlob(BlobAllocatorFn allocator) const final { | |||
2397 | // Blob data within then textual format is represented as a hex string. | |||
2398 | // TODO: We could avoid an additional alloc+copy here if we pre-allocated | |||
2399 | // the buffer to use during hex processing. | |||
2400 | std::optional<std::string> blobData = | |||
2401 | value.is(Token::string) ? value.getHexStringValue() : std::nullopt; | |||
2402 | if (!blobData) | |||
2403 | return p.emitError(value.getLoc(), | |||
2404 | "expected hex string blob for key '" + key + "'"); | |||
2405 | ||||
2406 | // Extract the alignment of the blob data, which gets stored at the | |||
2407 | // beginning of the string. | |||
2408 | if (blobData->size() < sizeof(uint32_t)) { | |||
2409 | return p.emitError(value.getLoc(), | |||
2410 | "expected hex string blob for key '" + key + | |||
2411 | "' to encode alignment in first 4 bytes"); | |||
2412 | } | |||
2413 | llvm::support::ulittle32_t align; | |||
2414 | memcpy(&align, blobData->data(), sizeof(uint32_t)); | |||
2415 | ||||
2416 | // Get the data portion of the blob. | |||
2417 | StringRef data = StringRef(*blobData).drop_front(sizeof(uint32_t)); | |||
2418 | if (data.empty()) | |||
2419 | return AsmResourceBlob(); | |||
2420 | ||||
2421 | // Allocate memory for the blob using the provided allocator and copy the | |||
2422 | // data into it. | |||
2423 | AsmResourceBlob blob = allocator(data.size(), align); | |||
2424 | assert(llvm::isAddrAligned(llvm::Align(align), blob.getData().data()) &&(static_cast <bool> (llvm::isAddrAligned(llvm::Align(align ), blob.getData().data()) && blob.isMutable() && "blob allocator did not return a properly aligned address") ? void (0) : __assert_fail ("llvm::isAddrAligned(llvm::Align(align), blob.getData().data()) && blob.isMutable() && \"blob allocator did not return a properly aligned address\"" , "mlir/lib/AsmParser/Parser.cpp", 2426, __extension__ __PRETTY_FUNCTION__ )) | |||
2425 | blob.isMutable() &&(static_cast <bool> (llvm::isAddrAligned(llvm::Align(align ), blob.getData().data()) && blob.isMutable() && "blob allocator did not return a properly aligned address") ? void (0) : __assert_fail ("llvm::isAddrAligned(llvm::Align(align), blob.getData().data()) && blob.isMutable() && \"blob allocator did not return a properly aligned address\"" , "mlir/lib/AsmParser/Parser.cpp", 2426, __extension__ __PRETTY_FUNCTION__ )) | |||
2426 | "blob allocator did not return a properly aligned address")(static_cast <bool> (llvm::isAddrAligned(llvm::Align(align ), blob.getData().data()) && blob.isMutable() && "blob allocator did not return a properly aligned address") ? void (0) : __assert_fail ("llvm::isAddrAligned(llvm::Align(align), blob.getData().data()) && blob.isMutable() && \"blob allocator did not return a properly aligned address\"" , "mlir/lib/AsmParser/Parser.cpp", 2426, __extension__ __PRETTY_FUNCTION__ )); | |||
2427 | memcpy(blob.getMutableData().data(), data.data(), data.size()); | |||
2428 | return blob; | |||
2429 | } | |||
2430 | ||||
2431 | private: | |||
2432 | StringRef key; | |||
2433 | SMLoc keyLoc; | |||
2434 | Token value; | |||
2435 | Parser &p; | |||
2436 | }; | |||
2437 | } // namespace | |||
2438 | ||||
2439 | ParseResult TopLevelOperationParser::parseAttributeAliasDef() { | |||
2440 | assert(getToken().is(Token::hash_identifier))(static_cast <bool> (getToken().is(Token::hash_identifier )) ? void (0) : __assert_fail ("getToken().is(Token::hash_identifier)" , "mlir/lib/AsmParser/Parser.cpp", 2440, __extension__ __PRETTY_FUNCTION__ )); | |||
2441 | StringRef aliasName = getTokenSpelling().drop_front(); | |||
2442 | ||||
2443 | // Check for redefinitions. | |||
2444 | if (state.symbols.attributeAliasDefinitions.count(aliasName) > 0) | |||
2445 | return emitError("redefinition of attribute alias id '" + aliasName + "'"); | |||
2446 | ||||
2447 | // Make sure this isn't invading the dialect attribute namespace. | |||
2448 | if (aliasName.contains('.')) | |||
2449 | return emitError("attribute names with a '.' are reserved for " | |||
2450 | "dialect-defined names"); | |||
2451 | ||||
2452 | consumeToken(Token::hash_identifier); | |||
2453 | ||||
2454 | // Parse the '='. | |||
2455 | if (parseToken(Token::equal, "expected '=' in attribute alias definition")) | |||
2456 | return failure(); | |||
2457 | ||||
2458 | // Parse the attribute value. | |||
2459 | Attribute attr = parseAttribute(); | |||
2460 | if (!attr) | |||
2461 | return failure(); | |||
2462 | ||||
2463 | state.symbols.attributeAliasDefinitions[aliasName] = attr; | |||
2464 | return success(); | |||
2465 | } | |||
2466 | ||||
2467 | ParseResult TopLevelOperationParser::parseTypeAliasDef() { | |||
2468 | assert(getToken().is(Token::exclamation_identifier))(static_cast <bool> (getToken().is(Token::exclamation_identifier )) ? void (0) : __assert_fail ("getToken().is(Token::exclamation_identifier)" , "mlir/lib/AsmParser/Parser.cpp", 2468, __extension__ __PRETTY_FUNCTION__ )); | |||
2469 | StringRef aliasName = getTokenSpelling().drop_front(); | |||
2470 | ||||
2471 | // Check for redefinitions. | |||
2472 | if (state.symbols.typeAliasDefinitions.count(aliasName) > 0) | |||
2473 | return emitError("redefinition of type alias id '" + aliasName + "'"); | |||
2474 | ||||
2475 | // Make sure this isn't invading the dialect type namespace. | |||
2476 | if (aliasName.contains('.')) | |||
2477 | return emitError("type names with a '.' are reserved for " | |||
2478 | "dialect-defined names"); | |||
2479 | consumeToken(Token::exclamation_identifier); | |||
2480 | ||||
2481 | // Parse the '='. | |||
2482 | if (parseToken(Token::equal, "expected '=' in type alias definition")) | |||
2483 | return failure(); | |||
2484 | ||||
2485 | // Parse the type. | |||
2486 | Type aliasedType = parseType(); | |||
2487 | if (!aliasedType) | |||
2488 | return failure(); | |||
2489 | ||||
2490 | // Register this alias with the parser state. | |||
2491 | state.symbols.typeAliasDefinitions.try_emplace(aliasName, aliasedType); | |||
2492 | return success(); | |||
2493 | } | |||
2494 | ||||
2495 | ParseResult TopLevelOperationParser::parseFileMetadataDictionary() { | |||
2496 | consumeToken(Token::file_metadata_begin); | |||
2497 | return parseCommaSeparatedListUntil( | |||
2498 | Token::file_metadata_end, [&]() -> ParseResult { | |||
2499 | // Parse the key of the metadata dictionary. | |||
2500 | SMLoc keyLoc = getToken().getLoc(); | |||
2501 | StringRef key; | |||
2502 | if (failed(parseOptionalKeyword(&key))) | |||
2503 | return emitError("expected identifier key in file " | |||
2504 | "metadata dictionary"); | |||
2505 | if (parseToken(Token::colon, "expected ':'")) | |||
2506 | return failure(); | |||
2507 | ||||
2508 | // Process the metadata entry. | |||
2509 | if (key == "dialect_resources") | |||
2510 | return parseDialectResourceFileMetadata(); | |||
2511 | if (key == "external_resources") | |||
2512 | return parseExternalResourceFileMetadata(); | |||
2513 | return emitError(keyLoc, "unknown key '" + key + | |||
2514 | "' in file metadata dictionary"); | |||
2515 | }); | |||
2516 | } | |||
2517 | ||||
2518 | ParseResult TopLevelOperationParser::parseResourceFileMetadata( | |||
2519 | function_ref<ParseResult(StringRef, SMLoc)> parseBody) { | |||
2520 | if (parseToken(Token::l_brace, "expected '{'")) | |||
2521 | return failure(); | |||
2522 | ||||
2523 | return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult { | |||
2524 | // Parse the top-level name entry. | |||
2525 | SMLoc nameLoc = getToken().getLoc(); | |||
2526 | StringRef name; | |||
2527 | if (failed(parseOptionalKeyword(&name))) | |||
2528 | return emitError("expected identifier key for 'resource' entry"); | |||
2529 | ||||
2530 | if (parseToken(Token::colon, "expected ':'") || | |||
2531 | parseToken(Token::l_brace, "expected '{'")) | |||
2532 | return failure(); | |||
2533 | return parseBody(name, nameLoc); | |||
2534 | }); | |||
2535 | } | |||
2536 | ||||
2537 | ParseResult TopLevelOperationParser::parseDialectResourceFileMetadata() { | |||
2538 | return parseResourceFileMetadata([&](StringRef name, | |||
2539 | SMLoc nameLoc) -> ParseResult { | |||
2540 | // Lookup the dialect and check that it can handle a resource entry. | |||
2541 | Dialect *dialect = getContext()->getOrLoadDialect(name); | |||
2542 | if (!dialect) | |||
2543 | return emitError(nameLoc, "dialect '" + name + "' is unknown"); | |||
2544 | const auto *handler = dyn_cast<OpAsmDialectInterface>(dialect); | |||
2545 | if (!handler) { | |||
2546 | return emitError() << "unexpected 'resource' section for dialect '" | |||
2547 | << dialect->getNamespace() << "'"; | |||
2548 | } | |||
2549 | ||||
2550 | return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult { | |||
2551 | // Parse the name of the resource entry. | |||
2552 | SMLoc keyLoc = getToken().getLoc(); | |||
2553 | StringRef key; | |||
2554 | if (failed(parseResourceHandle(handler, key)) || | |||
2555 | parseToken(Token::colon, "expected ':'")) | |||
2556 | return failure(); | |||
2557 | Token valueTok = getToken(); | |||
2558 | consumeToken(); | |||
2559 | ||||
2560 | ParsedResourceEntry entry(key, keyLoc, valueTok, *this); | |||
2561 | return handler->parseResource(entry); | |||
2562 | }); | |||
2563 | }); | |||
2564 | } | |||
2565 | ||||
2566 | ParseResult TopLevelOperationParser::parseExternalResourceFileMetadata() { | |||
2567 | return parseResourceFileMetadata([&](StringRef name, | |||
2568 | SMLoc nameLoc) -> ParseResult { | |||
2569 | AsmResourceParser *handler = state.config.getResourceParser(name); | |||
2570 | ||||
2571 | // TODO: Should we require handling external resources in some scenarios? | |||
2572 | if (!handler) { | |||
2573 | emitWarning(getEncodedSourceLocation(nameLoc)) | |||
2574 | << "ignoring unknown external resources for '" << name << "'"; | |||
2575 | } | |||
2576 | ||||
2577 | return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult { | |||
2578 | // Parse the name of the resource entry. | |||
2579 | SMLoc keyLoc = getToken().getLoc(); | |||
2580 | StringRef key; | |||
2581 | if (failed(parseOptionalKeyword(&key))) | |||
2582 | return emitError( | |||
2583 | "expected identifier key for 'external_resources' entry"); | |||
2584 | if (parseToken(Token::colon, "expected ':'")) | |||
2585 | return failure(); | |||
2586 | Token valueTok = getToken(); | |||
2587 | consumeToken(); | |||
2588 | ||||
2589 | if (!handler) | |||
2590 | return success(); | |||
2591 | ParsedResourceEntry entry(key, keyLoc, valueTok, *this); | |||
2592 | return handler->parseResource(entry); | |||
2593 | }); | |||
2594 | }); | |||
2595 | } | |||
2596 | ||||
2597 | ParseResult TopLevelOperationParser::parse(Block *topLevelBlock, | |||
2598 | Location parserLoc) { | |||
2599 | // Create a top-level operation to contain the parsed state. | |||
2600 | OwningOpRef<ModuleOp> topLevelOp(ModuleOp::create(parserLoc)); | |||
2601 | OperationParser opParser(state, topLevelOp.get()); | |||
2602 | while (true) { | |||
2603 | switch (getToken().getKind()) { | |||
2604 | default: | |||
2605 | // Parse a top-level operation. | |||
2606 | if (opParser.parseOperation()) | |||
2607 | return failure(); | |||
2608 | break; | |||
2609 | ||||
2610 | // If we got to the end of the file, then we're done. | |||
2611 | case Token::eof: { | |||
2612 | if (opParser.finalize()) | |||
2613 | return failure(); | |||
2614 | ||||
2615 | // Splice the blocks of the parsed operation over to the provided | |||
2616 | // top-level block. | |||
2617 | auto &parsedOps = topLevelOp->getBody()->getOperations(); | |||
2618 | auto &destOps = topLevelBlock->getOperations(); | |||
2619 | destOps.splice(destOps.end(), parsedOps, parsedOps.begin(), | |||
2620 | parsedOps.end()); | |||
2621 | return success(); | |||
2622 | } | |||
2623 | ||||
2624 | // If we got an error token, then the lexer already emitted an error, just | |||
2625 | // stop. Someday we could introduce error recovery if there was demand | |||
2626 | // for it. | |||
2627 | case Token::error: | |||
2628 | return failure(); | |||
2629 | ||||
2630 | // Parse an attribute alias. | |||
2631 | case Token::hash_identifier: | |||
2632 | if (parseAttributeAliasDef()) | |||
2633 | return failure(); | |||
2634 | break; | |||
2635 | ||||
2636 | // Parse a type alias. | |||
2637 | case Token::exclamation_identifier: | |||
2638 | if (parseTypeAliasDef()) | |||
2639 | return failure(); | |||
2640 | break; | |||
2641 | ||||
2642 | // Parse a file-level metadata dictionary. | |||
2643 | case Token::file_metadata_begin: | |||
2644 | if (parseFileMetadataDictionary()) | |||
2645 | return failure(); | |||
2646 | break; | |||
2647 | } | |||
2648 | } | |||
2649 | } | |||
2650 | ||||
2651 | //===----------------------------------------------------------------------===// | |||
2652 | ||||
2653 | LogicalResult | |||
2654 | mlir::parseAsmSourceFile(const llvm::SourceMgr &sourceMgr, Block *block, | |||
2655 | const ParserConfig &config, AsmParserState *asmState, | |||
2656 | AsmParserCodeCompleteContext *codeCompleteContext) { | |||
2657 | const auto *sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID()); | |||
2658 | ||||
2659 | Location parserLoc = | |||
2660 | FileLineColLoc::get(config.getContext(), sourceBuf->getBufferIdentifier(), | |||
2661 | /*line=*/0, /*column=*/0); | |||
2662 | ||||
2663 | SymbolState aliasState; | |||
2664 | ParserState state(sourceMgr, config, aliasState, asmState, | |||
2665 | codeCompleteContext); | |||
2666 | return TopLevelOperationParser(state).parse(block, parserLoc); | |||
2667 | } |