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