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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of mlir/lib/AsmParser/Parser.cpp