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