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