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