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 = [&]() -> FailureOr<UnresolvedOperand> {
1824 UnresolvedOperand operand;
1825 if (parseOperand(operand))
1826 return {};
1827 return operand;
1828 };
1829 auto addOperand = [&](bool isSymbol, UnresolvedOperand operand) {
1830 if (isSymbol)
1831 symOperands.push_back(operand);
1832 else
1833 dimOperands.push_back(operand);
1834 };
1835
1836 AffineMap map;
1837 if (parser.parseAffineMapOfSSAIds(map, parseElement, addOperand, delimiter))
1838 return failure();
1839 // Add AffineMap attribute.
1840 if (map) {
1841 mapAttr = AffineMapAttr::get(map);
1842 attrs.push_back(parser.builder.getNamedAttr(attrName, mapAttr));
1843 }
1844
1845 // Add dim operands before symbol operands in 'operands'.
1846 operands.assign(dimOperands.begin(), dimOperands.end());
1847 operands.append(symOperands.begin(), symOperands.end());
1848 return success();
1849 }
1850
1851 /// Parse an AffineExpr of SSA ids.
1852 ParseResult
1853 parseAffineExprOfSSAIds(SmallVectorImpl<UnresolvedOperand> &dimOperands,
1854 SmallVectorImpl<UnresolvedOperand> &symOperands,
1855 AffineExpr &expr) override {
1856 auto parseElement = [&]() -> FailureOr<UnresolvedOperand> {
1857 UnresolvedOperand operand;
1858 if (parseOperand(operand))
1859 return {};
1860 return operand;
1861 };
1862 auto addOperand = [&](bool isSymbol, UnresolvedOperand operand) {
1863 if (isSymbol)
1864 symOperands.push_back(operand);
1865 else
1866 dimOperands.push_back(operand);
1867 };
1868
1869 return parser.parseAffineExprOfSSAIds(expr, parseElement, addOperand);
1870 }
1871
1872 //===--------------------------------------------------------------------===//
1873 // Argument Parsing
1874 //===--------------------------------------------------------------------===//
1875
1876 /// Parse a single argument with the following syntax:
1877 ///
1878 /// `%ssaname : !type { optionalAttrDict} loc(optionalSourceLoc)`
1879 ///
1880 /// If `allowType` is false or `allowAttrs` are false then the respective
1881 /// parts of the grammar are not parsed.
1882 ParseResult parseArgument(Argument &result, bool allowType = false,
1883 bool allowAttrs = false) override {
1884 NamedAttrList attrs;
1885 if (parseOperand(result.ssaName, /*allowResultNumber=*/false) ||
1886 (allowType && parseColonType(result.type)) ||
1887 (allowAttrs && parseOptionalAttrDict(attrs)) ||
1888 parseOptionalLocationSpecifier(result.sourceLoc))
1889 return failure();
1890 result.attrs = attrs.getDictionary(getContext());
1891 return success();
1892 }
1893
1894 /// Parse a single argument if present.
1895 OptionalParseResult parseOptionalArgument(Argument &result, bool allowType,
1896 bool allowAttrs) override {
1897 if (parser.getToken().is(Token::percent_identifier))
1898 return parseArgument(result, allowType, allowAttrs);
1899 return std::nullopt;
1900 }
1901
1902 ParseResult parseArgumentList(SmallVectorImpl<Argument> &result,
1903 Delimiter delimiter, bool allowType,
1904 bool allowAttrs) override {
1905 // The no-delimiter case has some special handling for the empty case.
1906 if (delimiter == Delimiter::None &&
1907 parser.getToken().isNot(Token::percent_identifier))
1908 return success();
1909
1910 auto parseOneArgument = [&]() -> ParseResult {
1911 return parseArgument(result.emplace_back(), allowType, allowAttrs);
1912 };
1913 return parseCommaSeparatedList(delimiter, parseOneArgument,
1914 " in argument list");
1915 }
1916
1917 //===--------------------------------------------------------------------===//
1918 // Region Parsing
1919 //===--------------------------------------------------------------------===//
1920
1921 /// Parse a region that takes `arguments` of `argTypes` types. This
1922 /// effectively defines the SSA values of `arguments` and assigns their type.
1923 ParseResult parseRegion(Region &region, ArrayRef<Argument> arguments,
1924 bool enableNameShadowing) override {
1925 // Try to parse the region.
1926 (void)isIsolatedFromAbove;
1927 assert((!enableNameShadowing || isIsolatedFromAbove) &&
1928 "name shadowing is only allowed on isolated regions");
1929 if (parser.parseRegion(region, arguments, enableNameShadowing))
1930 return failure();
1931 return success();
1932 }
1933
1934 /// Parses a region if present.
1935 OptionalParseResult parseOptionalRegion(Region &region,
1936 ArrayRef<Argument> arguments,
1937 bool enableNameShadowing) override {
1938 if (parser.getToken().isNot(Token::l_brace))
1939 return std::nullopt;
1940 return parseRegion(region, arguments, enableNameShadowing);
1941 }
1942
1943 /// Parses a region if present. If the region is present, a new region is
1944 /// allocated and placed in `region`. If no region is present, `region`
1945 /// remains untouched.
1946 OptionalParseResult
1947 parseOptionalRegion(std::unique_ptr<Region> &region,
1948 ArrayRef<Argument> arguments,
1949 bool enableNameShadowing = false) override {
1950 if (parser.getToken().isNot(Token::l_brace))
1951 return std::nullopt;
1952 std::unique_ptr<Region> newRegion = std::make_unique<Region>();
1953 if (parseRegion(*newRegion, arguments, enableNameShadowing))
1954 return failure();
1955
1956 region = std::move(newRegion);
1957 return success();
1958 }
1959
1960 //===--------------------------------------------------------------------===//
1961 // Successor Parsing
1962 //===--------------------------------------------------------------------===//
1963
1964 /// Parse a single operation successor.
1965 ParseResult parseSuccessor(Block *&dest) override {
1966 return parser.parseSuccessor(dest);
1967 }
1968
1969 /// Parse an optional operation successor and its operand list.
1970 OptionalParseResult parseOptionalSuccessor(Block *&dest) override {
1971 if (!parser.getToken().isOrIsCodeCompletionFor(Token::caret_identifier))
1972 return std::nullopt;
1973 return parseSuccessor(dest);
1974 }
1975
1976 /// Parse a single operation successor and its operand list.
1977 ParseResult
1978 parseSuccessorAndUseList(Block *&dest,
1979 SmallVectorImpl<Value> &operands) override {
1980 if (parseSuccessor(dest))
1981 return failure();
1982
1983 // Handle optional arguments.
1984 if (succeeded(parseOptionalLParen()) &&
1985 (parser.parseOptionalSSAUseAndTypeList(operands) || parseRParen())) {
1986 return failure();
1987 }
1988 return success();
1989 }
1990
1991 //===--------------------------------------------------------------------===//
1992 // Type Parsing
1993 //===--------------------------------------------------------------------===//
1994
1995 /// Parse a list of assignments of the form
1996 /// (%x1 = %y1, %x2 = %y2, ...).
1997 OptionalParseResult parseOptionalAssignmentList(
1998 SmallVectorImpl<Argument> &lhs,
1999 SmallVectorImpl<UnresolvedOperand> &rhs) override {
2000 if (failed(parseOptionalLParen()))
2001 return std::nullopt;
2002
2003 auto parseElt = [&]() -> ParseResult {
2004 if (parseArgument(lhs.emplace_back()) || parseEqual() ||
2005 parseOperand(rhs.emplace_back()))
2006 return failure();
2007 return success();
2008 };
2009 return parser.parseCommaSeparatedListUntil(Token::r_paren, parseElt);
2010 }
2011
2012 /// Parse a loc(...) specifier if present, filling in result if so.
2013 ParseResult
2014 parseOptionalLocationSpecifier(std::optional<Location> &result) override {
2015 // If there is a 'loc' we parse a trailing location.
2016 if (!parser.consumeIf(Token::kw_loc))
2017 return success();
2018 LocationAttr directLoc;
2019 if (parser.parseToken(Token::l_paren, "expected '(' in location"))
2020 return failure();
2021
2022 Token tok = parser.getToken();
2023
2024 // Check to see if we are parsing a location alias. We are parsing a
2025 // location alias if the token is a hash identifier *without* a dot in it -
2026 // the dot signifies a dialect attribute. Otherwise, we parse the location
2027 // directly.
2028 if (tok.is(Token::hash_identifier) && !tok.getSpelling().contains('.')) {
2029 if (parser.parseLocationAlias(directLoc))
2030 return failure();
2031 } else if (parser.parseLocationInstance(directLoc)) {
2032 return failure();
2033 }
2034
2035 if (parser.parseToken(Token::r_paren, "expected ')' in location"))
2036 return failure();
2037
2038 result = directLoc;
2039 return success();
2040 }
2041
2042private:
2043 /// Information about the result name specifiers.
2044 ArrayRef<OperationParser::ResultRecord> resultIDs;
2045
2046 /// The abstract information of the operation.
2047 function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly;
2048 bool isIsolatedFromAbove;
2049 StringRef opName;
2050
2051 /// The backing operation parser.
2052 OperationParser &parser;
2053};
2054} // namespace
2055
2056FailureOr<OperationName> OperationParser::parseCustomOperationName() {
2057 Token nameTok = getToken();
2058 // Accept keywords here as they may be interpreted as a shortened operation
2059 // name, e.g., `dialect.keyword` can be spelled as just `keyword` within a
2060 // region of an operation from `dialect`.
2061 if (nameTok.getKind() != Token::bare_identifier && !nameTok.isKeyword())
2062 return emitError("expected bare identifier or keyword");
2063 StringRef opName = nameTok.getSpelling();
2064 if (opName.empty())
2065 return (emitError("empty operation name is invalid"), failure());
2066 consumeToken();
2067
2068 // Check to see if this operation name is already registered.
2069 std::optional<RegisteredOperationName> opInfo =
2071 if (opInfo)
2072 return *opInfo;
2073
2074 // If the operation doesn't have a dialect prefix try using the default
2075 // dialect.
2076 auto opNameSplit = opName.split('.');
2077 StringRef dialectName = opNameSplit.first;
2078 std::string opNameStorage;
2079 if (opNameSplit.second.empty()) {
2080 // If the name didn't have a prefix, check for a code completion request.
2081 if (getToken().isCodeCompletion() && opName.back() == '.')
2082 return codeCompleteOperationName(dialectName);
2083
2084 dialectName = getState().defaultDialectStack.back();
2085 opNameStorage = (dialectName + "." + opName).str();
2086 opName = opNameStorage;
2087 }
2088
2089 // Try to load the dialect before returning the operation name to make sure
2090 // the operation has a chance to be registered.
2091 getContext()->getOrLoadDialect(dialectName);
2092 return OperationName(opName, getContext());
2093}
2094
2095Operation *
2096OperationParser::parseCustomOperation(ArrayRef<ResultRecord> resultIDs) {
2097 SMLoc opLoc = getToken().getLoc();
2098 StringRef originalOpName = getTokenSpelling();
2099
2100 FailureOr<OperationName> opNameInfo = parseCustomOperationName();
2101 if (failed(opNameInfo))
2102 return nullptr;
2103 StringRef opName = opNameInfo->getStringRef();
2104
2105 // This is the actual hook for the custom op parsing, usually implemented by
2106 // the op itself (`Op::parse()`). We retrieve it either from the
2107 // RegisteredOperationName or from the Dialect.
2108 OperationName::ParseAssemblyFn parseAssemblyFn;
2109 bool isIsolatedFromAbove = false;
2110
2111 StringRef defaultDialect = "";
2112 if (auto opInfo = opNameInfo->getRegisteredInfo()) {
2113 parseAssemblyFn = opInfo->getParseAssemblyFn();
2114 isIsolatedFromAbove = opInfo->hasTrait<OpTrait::IsIsolatedFromAbove>();
2115 auto *iface = opInfo->getInterface<OpAsmOpInterface>();
2116 if (iface && !iface->getDefaultDialect().empty())
2117 defaultDialect = iface->getDefaultDialect();
2118 } else {
2119 std::optional<Dialect::ParseOpHook> dialectHook;
2120 Dialect *dialect = opNameInfo->getDialect();
2121 if (!dialect) {
2122 InFlightDiagnostic diag =
2123 emitError(opLoc) << "Dialect `" << opNameInfo->getDialectNamespace()
2124 << "' not found for custom op '" << originalOpName
2125 << "' ";
2126 if (originalOpName != opName)
2127 diag << " (tried '" << opName << "' as well)";
2128 auto &note = diag.attachNote();
2129 note << "Available dialects: ";
2130 std::vector<StringRef> registered = getContext()->getAvailableDialects();
2131 auto loaded = getContext()->getLoadedDialects();
2132
2133 // Merge the sorted lists of registered and loaded dialects.
2134 SmallVector<std::pair<StringRef, bool>> mergedDialects;
2135 auto regIt = registered.begin(), regEnd = registered.end();
2136 auto loadIt = loaded.rbegin(), loadEnd = loaded.rend();
2137 bool isRegistered = false;
2138 bool isOnlyLoaded = true;
2139 while (regIt != regEnd && loadIt != loadEnd) {
2140 StringRef reg = *regIt;
2141 StringRef load = (*loadIt)->getNamespace();
2142 if (load < reg) {
2143 mergedDialects.emplace_back(load, isOnlyLoaded);
2144 ++loadIt;
2145 } else {
2146 mergedDialects.emplace_back(reg, isRegistered);
2147 ++regIt;
2148 if (reg == load)
2149 ++loadIt;
2150 }
2151 }
2152 for (; regIt != regEnd; ++regIt)
2153 mergedDialects.emplace_back(*regIt, isRegistered);
2154 for (; loadIt != loadEnd; ++loadIt)
2155 mergedDialects.emplace_back((*loadIt)->getNamespace(), isOnlyLoaded);
2156
2157 bool loadedUnregistered = false;
2158 llvm::interleaveComma(mergedDialects, note, [&](auto &pair) {
2159 note << pair.first;
2160 if (pair.second) {
2161 loadedUnregistered = true;
2162 note << " (*)";
2163 }
2164 });
2165 note << " ";
2166 if (loadedUnregistered)
2167 note << "(* corresponding to loaded but unregistered dialects)";
2168 note << "; for more info on dialect registration see "
2169 "https://mlir.llvm.org/getting_started/Faq/"
2170 "#registered-loaded-dependent-whats-up-with-dialects-management";
2171 return nullptr;
2172 }
2173 dialectHook = dialect->getParseOperationHook(opName);
2174 if (!dialectHook) {
2175 InFlightDiagnostic diag =
2176 emitError(opLoc) << "custom op '" << originalOpName << "' is unknown";
2177 if (originalOpName != opName)
2178 diag << " (tried '" << opName << "' as well)";
2179 return nullptr;
2180 }
2181 parseAssemblyFn = *dialectHook;
2182 }
2183 getState().defaultDialectStack.push_back(defaultDialect);
2184 llvm::scope_exit restoreDefaultDialect(
2185 [&]() { getState().defaultDialectStack.pop_back(); });
2186
2187 // If the custom op parser crashes, produce some indication to help
2188 // debugging.
2189 llvm::PrettyStackTraceFormat fmt("MLIR Parser: custom op parser '%s'",
2190 opNameInfo->getIdentifier().data());
2191
2192 // Get location information for the operation.
2193 auto srcLocation = getEncodedSourceLocation(opLoc);
2194 OperationState opState(srcLocation, *opNameInfo);
2195
2196 // If we are populating the parser state, start a new operation definition.
2197 if (state.asmState)
2198 state.asmState->startOperationDefinition(opState.name);
2199
2200 // Have the op implementation take a crack and parsing this.
2201 CleanupOpStateRegions guard{opState};
2202 CustomOpAsmParser opAsmParser(opLoc, resultIDs, parseAssemblyFn,
2203 isIsolatedFromAbove, opName, *this);
2204 if (opAsmParser.parseOperation(opState))
2205 return nullptr;
2206
2207 // If it emitted an error, we failed.
2208 if (opAsmParser.didEmitError())
2209 return nullptr;
2210
2211 Attribute properties = opState.propertiesAttr;
2212 opState.propertiesAttr = Attribute{};
2213
2214 // Otherwise, create the operation and try to parse a location for it.
2215 Operation *op = opBuilder.create(opState);
2216 if (parseTrailingLocationSpecifier(op))
2217 return nullptr;
2218
2219 // Try setting the properties for the operation.
2220 if (properties) {
2221 auto emitError = [&]() {
2222 return mlir::emitError(srcLocation, "invalid properties ")
2223 << properties << " for op " << op->getName().getStringRef()
2224 << ": ";
2225 };
2226 if (failed(op->setPropertiesFromAttribute(properties, emitError)))
2227 return nullptr;
2228 }
2229 return op;
2230}
2231
2232ParseResult OperationParser::parseLocationAlias(LocationAttr &loc) {
2233 Token tok = getToken();
2234 consumeToken(Token::hash_identifier);
2235 StringRef identifier = tok.getSpelling().drop_front();
2236 assert(!identifier.contains('.') &&
2237 "unexpected dialect attribute token, expected alias");
2238
2239 if (state.asmState)
2240 state.asmState->addAttrAliasUses(identifier, tok.getLocRange());
2241
2242 // If this alias can be resolved, do it now.
2243 Attribute attr = state.symbols.attributeAliasDefinitions.lookup(identifier);
2244 if (attr) {
2245 if (!(loc = dyn_cast<LocationAttr>(attr)))
2246 return emitError(tok.getLoc())
2247 << "expected location, but found '" << attr << "'";
2248 } else {
2249 // Otherwise, remember this operation and resolve its location later.
2250 // In the meantime, use a special OpaqueLoc as a marker.
2251 loc = OpaqueLoc::get(deferredLocsReferences.size(),
2253 UnknownLoc::get(getContext()));
2254 deferredLocsReferences.push_back(DeferredLocInfo{tok.getLoc(), identifier});
2255 }
2256 return success();
2257}
2258
2259ParseResult
2260OperationParser::parseTrailingLocationSpecifier(OpOrArgument opOrArgument) {
2261 // If there is a 'loc' we parse a trailing location.
2262 if (!consumeIf(Token::kw_loc))
2263 return success();
2264 if (parseToken(Token::l_paren, "expected '(' in location"))
2265 return failure();
2266 Token tok = getToken();
2267
2268 // Check to see if we are parsing a location alias. We are parsing a location
2269 // alias if the token is a hash identifier *without* a dot in it - the dot
2270 // signifies a dialect attribute. Otherwise, we parse the location directly.
2271 LocationAttr directLoc;
2272 if (tok.is(Token::hash_identifier) && !tok.getSpelling().contains('.')) {
2273 if (parseLocationAlias(directLoc))
2274 return failure();
2275 } else if (parseLocationInstance(directLoc)) {
2276 return failure();
2277 }
2278
2279 if (parseToken(Token::r_paren, "expected ')' in location"))
2280 return failure();
2281
2282 if (auto *op = llvm::dyn_cast_if_present<Operation *>(opOrArgument))
2283 op->setLoc(directLoc);
2284 else
2285 cast<BlockArgument>(opOrArgument).setLoc(directLoc);
2286 return success();
2287}
2288
2289//===----------------------------------------------------------------------===//
2290// Region Parsing
2291//===----------------------------------------------------------------------===//
2292
2293ParseResult OperationParser::parseRegion(Region &region,
2294 ArrayRef<Argument> entryArguments,
2295 bool isIsolatedNameScope) {
2296 // Parse the '{'.
2297 Token lBraceTok = getToken();
2298 if (parseToken(Token::l_brace, "expected '{' to begin a region"))
2299 return failure();
2300
2301 // If we are populating the parser state, start a new region definition.
2302 if (state.asmState)
2304
2305 // Parse the region body.
2306 if ((!entryArguments.empty() || getToken().isNot(Token::r_brace)) &&
2307 parseRegionBody(region, lBraceTok.getLoc(), entryArguments,
2308 isIsolatedNameScope)) {
2309 return failure();
2310 }
2311 consumeToken(Token::r_brace);
2312
2313 // If we are populating the parser state, finalize this region.
2314 if (state.asmState)
2316
2317 return success();
2318}
2319
2320ParseResult OperationParser::parseRegionBody(Region &region, SMLoc startLoc,
2321 ArrayRef<Argument> entryArguments,
2322 bool isIsolatedNameScope) {
2323 auto currentPt = opBuilder.saveInsertionPoint();
2324
2325 // Push a new named value scope.
2326 pushSSANameScope(isIsolatedNameScope);
2327
2328 // Parse the first block directly to allow for it to be unnamed.
2329 auto owningBlock = std::make_unique<Block>();
2330 llvm::scope_exit failureCleanup([&] {
2331 if (owningBlock) {
2332 // If parsing failed, as indicated by the fact that `owningBlock` still
2333 // owns the block, drop all forward references from preceding operations
2334 // to definitions within the parsed block.
2335 owningBlock->dropAllDefinedValueUses();
2336 }
2337 });
2338 Block *block = owningBlock.get();
2339
2340 // If this block is not defined in the source file, add a definition for it
2341 // now in the assembly state. Blocks with a name will be defined when the name
2342 // is parsed.
2343 if (state.asmState && getToken().isNot(Token::caret_identifier))
2344 state.asmState->addDefinition(block, startLoc);
2345
2346 // Add arguments to the entry block if we had the form with explicit names.
2347 if (!entryArguments.empty() && !entryArguments[0].ssaName.name.empty()) {
2348 // If we had named arguments, then don't allow a block name.
2349 if (getToken().is(Token::caret_identifier))
2350 return emitError("invalid block name in region with named arguments");
2351
2352 for (auto &entryArg : entryArguments) {
2353 auto &argInfo = entryArg.ssaName;
2354
2355 // Ensure that the argument was not already defined.
2356 if (auto defLoc = getReferenceLoc(argInfo.name, argInfo.number)) {
2357 return emitError(argInfo.location, "region entry argument '" +
2358 argInfo.name +
2359 "' is already in use")
2360 .attachNote(getEncodedSourceLocation(*defLoc))
2361 << "previously referenced here";
2362 }
2363 Location loc = entryArg.sourceLoc.has_value()
2364 ? *entryArg.sourceLoc
2365 : getEncodedSourceLocation(argInfo.location);
2366 BlockArgument arg = block->addArgument(entryArg.type, loc);
2367
2368 // Add a definition of this arg to the assembly state if provided.
2369 if (state.asmState)
2370 state.asmState->addDefinition(arg, argInfo.location);
2371
2372 // Record the definition for this argument.
2373 if (addDefinition(argInfo, arg))
2374 return failure();
2375 }
2376 }
2377
2378 if (parseBlock(block))
2379 return failure();
2380
2381 // Verify that no other arguments were parsed.
2382 if (!entryArguments.empty() &&
2383 block->getNumArguments() > entryArguments.size()) {
2384 return emitError("entry block arguments were already defined");
2385 }
2386
2387 // Parse the rest of the region.
2388 region.push_back(owningBlock.release());
2389 while (getToken().isNot(Token::r_brace)) {
2390 Block *newBlock = nullptr;
2391 if (parseBlock(newBlock))
2392 return failure();
2393 region.push_back(newBlock);
2394 }
2395
2396 // Pop the SSA value scope for this region.
2397 if (popSSANameScope())
2398 return failure();
2399
2400 // Reset the original insertion point.
2401 opBuilder.restoreInsertionPoint(currentPt);
2402 return success();
2403}
2404
2405//===----------------------------------------------------------------------===//
2406// Block Parsing
2407//===----------------------------------------------------------------------===//
2408
2409/// Block declaration.
2410///
2411/// block ::= block-label? operation*
2412/// block-label ::= block-id block-arg-list? `:`
2413/// block-id ::= caret-id
2414/// block-arg-list ::= `(` ssa-id-and-type-list? `)`
2415///
2416ParseResult OperationParser::parseBlock(Block *&block) {
2417 // The first block of a region may already exist, if it does the caret
2418 // identifier is optional.
2419 if (block && getToken().isNot(Token::caret_identifier))
2420 return parseBlockBody(block);
2421
2422 SMLoc nameLoc = getToken().getLoc();
2423 auto name = getTokenSpelling();
2424 if (parseToken(Token::caret_identifier, "expected block name"))
2425 return failure();
2426
2427 // Define the block with the specified name.
2428 auto &blockAndLoc = getBlockInfoByName(name);
2429 blockAndLoc.loc = nameLoc;
2430
2431 // Use a unique pointer for in-flight block being parsed. Release ownership
2432 // only in the case of a successful parse. This ensures that the Block
2433 // allocated is released if the parse fails and control returns early.
2434 std::unique_ptr<Block> inflightBlock;
2435 llvm::scope_exit cleanupOnFailure([&] {
2436 if (inflightBlock)
2437 inflightBlock->dropAllDefinedValueUses();
2438 });
2439
2440 // If a block has yet to be set, this is a new definition. If the caller
2441 // provided a block, use it. Otherwise create a new one.
2442 if (!blockAndLoc.block) {
2443 if (block) {
2444 blockAndLoc.block = block;
2445 } else {
2446 inflightBlock = std::make_unique<Block>();
2447 blockAndLoc.block = inflightBlock.get();
2448 }
2449
2450 // Otherwise, the block has a forward declaration. Forward declarations are
2451 // removed once defined, so if we are defining a existing block and it is
2452 // not a forward declaration, then it is a redeclaration. Fail if the block
2453 // was already defined.
2454 } else if (!eraseForwardRef(blockAndLoc.block)) {
2455 return emitError(nameLoc, "redefinition of block '") << name << "'";
2456 } else {
2457 // This was a forward reference block that is now floating. Keep track of it
2458 // as inflight in case of error, so that it gets cleaned up properly.
2459 inflightBlock.reset(blockAndLoc.block);
2460 }
2461
2462 // Populate the high level assembly state if necessary.
2463 if (state.asmState)
2464 state.asmState->addDefinition(blockAndLoc.block, nameLoc);
2465 block = blockAndLoc.block;
2466
2467 // If an argument list is present, parse it.
2468 if (getToken().is(Token::l_paren))
2469 if (parseOptionalBlockArgList(block))
2470 return failure();
2471 if (parseToken(Token::colon, "expected ':' after block name"))
2472 return failure();
2473
2474 // Parse the body of the block.
2475 ParseResult res = parseBlockBody(block);
2476
2477 // If parsing was successful, drop the inflight block. We relinquish ownership
2478 // back up to the caller.
2479 if (succeeded(res))
2480 (void)inflightBlock.release();
2481 return res;
2482}
2483
2484ParseResult OperationParser::parseBlockBody(Block *block) {
2485 // Set the insertion point to the end of the block to parse.
2486 opBuilder.setInsertionPointToEnd(block);
2487
2488 // Parse the list of operations that make up the body of the block.
2489 while (getToken().isNot(Token::caret_identifier, Token::r_brace))
2490 if (parseOperation())
2491 return failure();
2492
2493 return success();
2494}
2495
2496/// Get the block with the specified name, creating it if it doesn't already
2497/// exist. The location specified is the point of use, which allows
2498/// us to diagnose references to blocks that are not defined precisely.
2499Block *OperationParser::getBlockNamed(StringRef name, SMLoc loc) {
2500 BlockDefinition &blockDef = getBlockInfoByName(name);
2501 if (!blockDef.block) {
2502 blockDef = {new Block(), loc};
2503 insertForwardRef(blockDef.block, blockDef.loc);
2504 }
2505
2506 // Populate the high level assembly state if necessary.
2507 if (state.asmState)
2508 state.asmState->addUses(blockDef.block, loc);
2509
2510 return blockDef.block;
2511}
2512
2513/// Parse a (possibly empty) list of SSA operands with types as block arguments
2514/// enclosed in parentheses.
2515///
2516/// value-id-and-type-list ::= value-id-and-type (`,` ssa-id-and-type)*
2517/// block-arg-list ::= `(` value-id-and-type-list? `)`
2518///
2519ParseResult OperationParser::parseOptionalBlockArgList(Block *owner) {
2520 if (getToken().is(Token::r_brace))
2521 return success();
2522
2523 // If the block already has arguments, then we're handling the entry block.
2524 // Parse and register the names for the arguments, but do not add them.
2525 bool definingExistingArgs = owner->getNumArguments() != 0;
2526 unsigned nextArgument = 0;
2527
2528 return parseCommaSeparatedList(Delimiter::Paren, [&]() -> ParseResult {
2529 return parseSSADefOrUseAndType(
2530 [&](UnresolvedOperand useInfo, Type type) -> ParseResult {
2531 BlockArgument arg;
2532
2533 // If we are defining existing arguments, ensure that the argument
2534 // has already been created with the right type.
2535 if (definingExistingArgs) {
2536 // Otherwise, ensure that this argument has already been created.
2537 if (nextArgument >= owner->getNumArguments())
2538 return emitError("too many arguments specified in argument list");
2539
2540 // Finally, make sure the existing argument has the correct type.
2541 arg = owner->getArgument(nextArgument++);
2542 if (arg.getType() != type)
2543 return emitError("argument and block argument type mismatch");
2544 } else {
2545 auto loc = getEncodedSourceLocation(useInfo.location);
2546 arg = owner->addArgument(type, loc);
2547 }
2548
2549 // If the argument has an explicit loc(...) specifier, parse and apply
2550 // it.
2551 if (parseTrailingLocationSpecifier(arg))
2552 return failure();
2553
2554 // Mark this block argument definition in the parser state if it was
2555 // provided.
2556 if (state.asmState)
2557 state.asmState->addDefinition(arg, useInfo.location);
2558
2559 return addDefinition(useInfo, arg);
2560 });
2561 });
2562}
2563
2564//===----------------------------------------------------------------------===//
2565// Code Completion
2566//===----------------------------------------------------------------------===//
2567
2568ParseResult OperationParser::codeCompleteSSAUse() {
2569 for (IsolatedSSANameScope &scope : isolatedNameScopes) {
2570 // Collect and sort SSA value names for deterministic completion ordering.
2571 SmallVector<StringRef> sortedNames;
2572 for (auto &it : scope.values)
2573 if (!it.second.empty())
2574 sortedNames.push_back(it.getKey());
2575 llvm::sort(sortedNames);
2576
2577 for (StringRef name : sortedNames) {
2578 Value frontValue = scope.values[name].front().value;
2579
2580 std::string detailData;
2581 llvm::raw_string_ostream detailOS(detailData);
2582
2583 // If the value isn't a forward reference, we also add the name of the op
2584 // to the detail.
2585 if (auto result = dyn_cast<OpResult>(frontValue)) {
2586 if (!forwardRefPlaceholders.count(result))
2587 detailOS << result.getOwner()->getName() << ": ";
2588 } else {
2589 detailOS << "arg #" << cast<BlockArgument>(frontValue).getArgNumber()
2590 << ": ";
2591 }
2592
2593 // Emit the type of the values to aid with completion selection.
2594 detailOS << frontValue.getType();
2595
2596 // FIXME: We should define a policy for packed values, e.g. with a limit
2597 // on the detail size, but it isn't clear what would be useful right now.
2598 // For now we just only emit the first type.
2599 if (scope.values[name].size() > 1)
2600 detailOS << ", ...";
2601
2603 name, std::move(detailData));
2604 }
2605 }
2606
2607 return failure();
2608}
2609
2610ParseResult OperationParser::codeCompleteBlock() {
2611 // Don't provide completions if the token isn't empty, e.g. this avoids
2612 // weirdness when we encounter a `.` within the identifier.
2613 StringRef spelling = getTokenSpelling();
2614 if (!(spelling.empty() || spelling == "^"))
2615 return failure();
2616
2617 for (const auto &it : blocksByName.back())
2618 state.codeCompleteContext->appendBlockCompletion(it.getFirst());
2619 return failure();
2620}
2621
2622//===----------------------------------------------------------------------===//
2623// Top-level entity parsing.
2624//===----------------------------------------------------------------------===//
2625
2626namespace {
2627/// This parser handles entities that are only valid at the top level of the
2628/// file.
2629class TopLevelOperationParser : public Parser {
2630public:
2631 explicit TopLevelOperationParser(ParserState &state) : Parser(state) {}
2632
2633 /// Parse a set of operations into the end of the given Block.
2634 ParseResult parse(Block *topLevelBlock, Location parserLoc);
2635
2636private:
2637 /// Parse an attribute alias declaration.
2638 ///
2639 /// attribute-alias-def ::= '#' alias-name `=` attribute-value
2640 ///
2641 ParseResult parseAttributeAliasDef();
2642
2643 /// Parse a type alias declaration.
2644 ///
2645 /// type-alias-def ::= '!' alias-name `=` type
2646 ///
2647 ParseResult parseTypeAliasDef();
2648
2649 /// Parse a top-level file metadata dictionary.
2650 ///
2651 /// file-metadata-dict ::= '{-#' file-metadata-entry* `#-}'
2652 ///
2653 ParseResult parseFileMetadataDictionary();
2654
2655 /// Parse a resource metadata dictionary.
2656 ParseResult parseResourceFileMetadata(
2657 function_ref<ParseResult(StringRef, SMLoc)> parseBody);
2658 ParseResult parseDialectResourceFileMetadata();
2659 ParseResult parseExternalResourceFileMetadata();
2660};
2661
2662/// This class represents an implementation of a resource entry for the MLIR
2663/// textual format.
2664class ParsedResourceEntry : public AsmParsedResourceEntry {
2665public:
2666 ParsedResourceEntry(std::string key, SMLoc keyLoc, Token value, Parser &p)
2667 : key(std::move(key)), keyLoc(keyLoc), value(value), p(p) {}
2668 ~ParsedResourceEntry() override = default;
2669
2670 StringRef getKey() const final { return key; }
2671
2672 InFlightDiagnostic emitError() const final { return p.emitError(keyLoc); }
2673
2674 AsmResourceEntryKind getKind() const final {
2675 if (value.isAny(Token::kw_true, Token::kw_false))
2676 return AsmResourceEntryKind::Bool;
2677 return value.getSpelling().starts_with("\"0x")
2678 ? AsmResourceEntryKind::Blob
2679 : AsmResourceEntryKind::String;
2680 }
2681
2682 FailureOr<bool> parseAsBool() const final {
2683 if (value.is(Token::kw_true))
2684 return true;
2685 if (value.is(Token::kw_false))
2686 return false;
2687 return p.emitError(value.getLoc(),
2688 "expected 'true' or 'false' value for key '" + key +
2689 "'");
2690 }
2691
2692 FailureOr<std::string> parseAsString() const final {
2693 if (value.isNot(Token::string))
2694 return p.emitError(value.getLoc(),
2695 "expected string value for key '" + key + "'");
2696 return value.getStringValue();
2697 }
2698
2699 FailureOr<AsmResourceBlob>
2700 parseAsBlob(BlobAllocatorFn allocator) const final {
2701 // Blob data within then textual format is represented as a hex string.
2702 // TODO: We could avoid an additional alloc+copy here if we pre-allocated
2703 // the buffer to use during hex processing.
2704 std::optional<std::string> blobData =
2705 value.is(Token::string) ? value.getHexStringValue() : std::nullopt;
2706 if (!blobData)
2707 return p.emitError(value.getLoc(),
2708 "expected hex string blob for key '" + key + "'");
2709
2710 // Extract the alignment of the blob data, which gets stored at the
2711 // beginning of the string.
2712 if (blobData->size() < sizeof(uint32_t)) {
2713 return p.emitError(value.getLoc(),
2714 "expected hex string blob for key '" + key +
2715 "' to encode alignment in first 4 bytes");
2716 }
2717 llvm::support::ulittle32_t align;
2718 memcpy(&align, blobData->data(), sizeof(uint32_t));
2719 if (align && !llvm::isPowerOf2_32(align)) {
2720 return p.emitError(value.getLoc(),
2721 "expected hex string blob for key '" + key +
2722 "' to encode alignment in first 4 bytes, but got "
2723 "non-power-of-2 value: " +
2724 Twine(align));
2725 }
2726
2727 // Get the data portion of the blob.
2728 StringRef data = StringRef(*blobData).drop_front(sizeof(uint32_t));
2729 if (data.empty())
2730 return AsmResourceBlob();
2731
2732 // Allocate memory for the blob using the provided allocator and copy the
2733 // data into it.
2734 AsmResourceBlob blob = allocator(data.size(), align);
2735 assert(llvm::isAddrAligned(llvm::Align(align), blob.getData().data()) &&
2736 blob.isMutable() &&
2737 "blob allocator did not return a properly aligned address");
2738 memcpy(blob.getMutableData().data(), data.data(), data.size());
2739 return blob;
2740 }
2741
2742private:
2743 std::string key;
2744 SMLoc keyLoc;
2745 Token value;
2746 Parser &p;
2747};
2748} // namespace
2749
2750ParseResult TopLevelOperationParser::parseAttributeAliasDef() {
2751 assert(getToken().is(Token::hash_identifier));
2752 StringRef aliasName = getTokenSpelling().drop_front();
2753
2754 // Check for redefinitions.
2755 if (state.symbols.attributeAliasDefinitions.count(aliasName) > 0)
2756 return emitError("redefinition of attribute alias id '" + aliasName + "'");
2757
2758 // Make sure this isn't invading the dialect attribute namespace.
2759 if (aliasName.contains('.'))
2760 return emitError("attribute names with a '.' are reserved for "
2761 "dialect-defined names");
2762
2763 SMRange location = getToken().getLocRange();
2764 consumeToken(Token::hash_identifier);
2765
2766 // Parse the '='.
2767 if (parseToken(Token::equal, "expected '=' in attribute alias definition"))
2768 return failure();
2769
2770 // Parse the attribute value.
2771 Attribute attr = parseAttribute();
2772 if (!attr)
2773 return failure();
2774
2775 // Register this alias with the parser state.
2776 if (state.asmState)
2777 state.asmState->addAttrAliasDefinition(aliasName, location, attr);
2778 state.symbols.attributeAliasDefinitions[aliasName] = attr;
2779 return success();
2780}
2781
2782ParseResult TopLevelOperationParser::parseTypeAliasDef() {
2783 assert(getToken().is(Token::exclamation_identifier));
2784 StringRef aliasName = getTokenSpelling().drop_front();
2785
2786 // Check for redefinitions.
2787 if (state.symbols.typeAliasDefinitions.count(aliasName) > 0)
2788 return emitError("redefinition of type alias id '" + aliasName + "'");
2789
2790 // Make sure this isn't invading the dialect type namespace.
2791 if (aliasName.contains('.'))
2792 return emitError("type names with a '.' are reserved for "
2793 "dialect-defined names");
2794
2795 SMRange location = getToken().getLocRange();
2796 consumeToken(Token::exclamation_identifier);
2797
2798 // Parse the '='.
2799 if (parseToken(Token::equal, "expected '=' in type alias definition"))
2800 return failure();
2801
2802 // Parse the type.
2803 Type aliasedType = parseType();
2804 if (!aliasedType)
2805 return failure();
2806
2807 // Register this alias with the parser state.
2808 if (state.asmState)
2809 state.asmState->addTypeAliasDefinition(aliasName, location, aliasedType);
2810 state.symbols.typeAliasDefinitions.try_emplace(aliasName, aliasedType);
2811 return success();
2812}
2813
2814ParseResult TopLevelOperationParser::parseFileMetadataDictionary() {
2815 consumeToken(Token::file_metadata_begin);
2816 return parseCommaSeparatedListUntil(
2817 Token::file_metadata_end, [&]() -> ParseResult {
2818 // Parse the key of the metadata dictionary.
2819 SMLoc keyLoc = getToken().getLoc();
2820 StringRef key;
2821 if (failed(parseOptionalKeyword(&key)))
2822 return emitError("expected identifier key in file "
2823 "metadata dictionary");
2824 if (parseToken(Token::colon, "expected ':'"))
2825 return failure();
2826
2827 // Process the metadata entry.
2828 if (key == "dialect_resources")
2829 return parseDialectResourceFileMetadata();
2830 if (key == "external_resources")
2831 return parseExternalResourceFileMetadata();
2832 return emitError(keyLoc, "unknown key '" + key +
2833 "' in file metadata dictionary");
2834 });
2835}
2836
2837ParseResult TopLevelOperationParser::parseResourceFileMetadata(
2838 function_ref<ParseResult(StringRef, SMLoc)> parseBody) {
2839 if (parseToken(Token::l_brace, "expected '{'"))
2840 return failure();
2841
2842 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2843 // Parse the top-level name entry.
2844 SMLoc nameLoc = getToken().getLoc();
2845 StringRef name;
2846 if (failed(parseOptionalKeyword(&name)))
2847 return emitError("expected identifier key for 'resource' entry");
2848
2849 if (parseToken(Token::colon, "expected ':'") ||
2850 parseToken(Token::l_brace, "expected '{'"))
2851 return failure();
2852 return parseBody(name, nameLoc);
2853 });
2854}
2855
2856ParseResult TopLevelOperationParser::parseDialectResourceFileMetadata() {
2857 return parseResourceFileMetadata([&](StringRef name,
2858 SMLoc nameLoc) -> ParseResult {
2859 // Lookup the dialect and check that it can handle a resource entry.
2860 Dialect *dialect = getContext()->getOrLoadDialect(name);
2861 if (!dialect)
2862 return emitError(nameLoc, "dialect '" + name + "' is unknown");
2863 const auto *handler = dyn_cast<OpAsmDialectInterface>(dialect);
2864 if (!handler) {
2865 return emitError() << "unexpected 'resource' section for dialect '"
2866 << dialect->getNamespace() << "'";
2867 }
2868
2869 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2870 // Parse the name of the resource entry.
2871 SMLoc keyLoc = getToken().getLoc();
2872 std::string key;
2873 if (failed(parseResourceHandle(handler, key)) ||
2874 parseToken(Token::colon, "expected ':'"))
2875 return failure();
2876 Token valueTok = getToken();
2877 consumeToken();
2878
2879 ParsedResourceEntry entry(key, keyLoc, valueTok, *this);
2880 return handler->parseResource(entry);
2881 });
2882 });
2883}
2884
2885ParseResult TopLevelOperationParser::parseExternalResourceFileMetadata() {
2886 return parseResourceFileMetadata([&](StringRef name,
2887 SMLoc nameLoc) -> ParseResult {
2888 AsmResourceParser *handler = state.config.getResourceParser(name);
2889
2890 // TODO: Should we require handling external resources in some scenarios?
2891 if (!handler) {
2892 emitWarning(getEncodedSourceLocation(nameLoc))
2893 << "ignoring unknown external resources for '" << name << "'";
2894 }
2895
2896 return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2897 // Parse the name of the resource entry.
2898 SMLoc keyLoc = getToken().getLoc();
2899 std::string key;
2900 if (failed(parseOptionalKeywordOrString(&key)))
2901 return emitError(
2902 "expected identifier key for 'external_resources' entry");
2903 if (parseToken(Token::colon, "expected ':'"))
2904 return failure();
2905 Token valueTok = getToken();
2906 consumeToken();
2907
2908 if (!handler)
2909 return success();
2910 ParsedResourceEntry entry(key, keyLoc, valueTok, *this);
2911 return handler->parseResource(entry);
2912 });
2913 });
2914}
2915
2916ParseResult TopLevelOperationParser::parse(Block *topLevelBlock,
2917 Location parserLoc) {
2918 // Create a top-level operation to contain the parsed state.
2919 OwningOpRef<ModuleOp> topLevelOp(ModuleOp::create(parserLoc));
2920 OperationParser opParser(state, topLevelOp.get());
2921 while (true) {
2922 switch (getToken().getKind()) {
2923 default:
2924 // Parse a top-level operation.
2925 if (opParser.parseOperation())
2926 return failure();
2927 break;
2928
2929 // If we got to the end of the file, then we're done.
2930 case Token::eof: {
2931 if (opParser.finalize())
2932 return failure();
2933
2934 // Splice the blocks of the parsed operation over to the provided
2935 // top-level block.
2936 auto &parsedOps = topLevelOp->getBody()->getOperations();
2937 auto &destOps = topLevelBlock->getOperations();
2938 destOps.splice(destOps.end(), parsedOps, parsedOps.begin(),
2939 parsedOps.end());
2940 return success();
2941 }
2942
2943 // If we got an error token, then the lexer already emitted an error, just
2944 // stop. Someday we could introduce error recovery if there was demand
2945 // for it.
2946 case Token::error:
2947 return failure();
2948
2949 // Parse an attribute alias.
2950 case Token::hash_identifier:
2951 if (parseAttributeAliasDef())
2952 return failure();
2953 break;
2954
2955 // Parse a type alias.
2956 case Token::exclamation_identifier:
2957 if (parseTypeAliasDef())
2958 return failure();
2959 break;
2960
2961 // Parse a file-level metadata dictionary.
2962 case Token::file_metadata_begin:
2963 if (parseFileMetadataDictionary())
2964 return failure();
2965 break;
2966 }
2967 }
2968}
2969
2970//===----------------------------------------------------------------------===//
2971
2972LogicalResult
2973mlir::parseAsmSourceFile(const llvm::SourceMgr &sourceMgr, Block *block,
2974 const ParserConfig &config, AsmParserState *asmState,
2975 AsmParserCodeCompleteContext *codeCompleteContext) {
2976 const auto *sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
2977
2978 Location parserLoc =
2979 FileLineColLoc::get(config.getContext(), sourceBuf->getBufferIdentifier(),
2980 /*line=*/0, /*column=*/0);
2981
2982 SymbolState aliasState;
2983 ParserState state(sourceMgr, config, aliasState, asmState,
2984 codeCompleteContext);
2985 return TopLevelOperationParser(state).parse(block, parserLoc);
2986}
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
static Location resolveLocation(Operation *anchor, llvm::StringMap< Location > &cache, StringRef file, unsigned line, unsigned column, StringRef functionName)
b getContext())
auto load
static bool contains(SMRange range, SMLoc loc)
Returns true if the given range contains the given source location.
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:729
static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, NamedAttrList &&attributes, PropertyRef properties, BlockRange successors, unsigned numRegions)
Create a new Operation with the specific fields.
Definition Operation.cpp:65
unsigned getNumResults()
Return the number of results held by this operation.
Definition Operation.h:429
This class implements Optional functionality for ParseResult.
This class represents a configuration for the MLIR assembly parser.
Definition AsmState.h:469
MLIRContext * getContext() const
Return the MLIRContext to be used when parsing.
Definition AsmState.h:483
bool shouldVerifyAfterParse() const
Returns if the parser should verify the IR after parsing.
Definition AsmState.h:486
AsmResourceParser * getResourceParser(StringRef name) const
Return the resource parser registered to the given name, or nullptr if no parser with name is registe...
Definition AsmState.h:495
void push_back(Block *block)
Definition Region.h:61
static std::optional< RegisteredOperationName > lookup(StringRef name, MLIRContext *ctx)
Lookup the registered operation information for the given operation.
This represents a token in the MLIR syntax.
Definition Token.h:20
bool isCodeCompletionFor(Kind kind) const
Returns true if the current token represents a code completion for the "normal" token type.
Definition Token.cpp: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:372
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:732
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:2973
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