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