MLIR  21.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();
445  if (failed(parseOptionalKeywordOrString(&name)))
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=*/std::nullopt, /*properties=*/nullptr, /*successors=*/{},
1202  /*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 << "Registered dialects: ";
2080  llvm::interleaveComma(getContext()->getAvailableDialects(), note,
2081  [&](StringRef dialect) { note << dialect; });
2082  note << " ; for more info on dialect registration see "
2083  "https://mlir.llvm.org/getting_started/Faq/"
2084  "#registered-loaded-dependent-whats-up-with-dialects-management";
2085  return nullptr;
2086  }
2087  dialectHook = dialect->getParseOperationHook(opName);
2088  if (!dialectHook) {
2090  emitError(opLoc) << "custom op '" << originalOpName << "' is unknown";
2091  if (originalOpName != opName)
2092  diag << " (tried '" << opName << "' as well)";
2093  return nullptr;
2094  }
2095  parseAssemblyFn = *dialectHook;
2096  }
2097  getState().defaultDialectStack.push_back(defaultDialect);
2098  auto restoreDefaultDialect = llvm::make_scope_exit(
2099  [&]() { getState().defaultDialectStack.pop_back(); });
2100 
2101  // If the custom op parser crashes, produce some indication to help
2102  // debugging.
2103  llvm::PrettyStackTraceFormat fmt("MLIR Parser: custom op parser '%s'",
2104  opNameInfo->getIdentifier().data());
2105 
2106  // Get location information for the operation.
2107  auto srcLocation = getEncodedSourceLocation(opLoc);
2108  OperationState opState(srcLocation, *opNameInfo);
2109 
2110  // If we are populating the parser state, start a new operation definition.
2111  if (state.asmState)
2112  state.asmState->startOperationDefinition(opState.name);
2113 
2114  // Have the op implementation take a crack and parsing this.
2115  CleanupOpStateRegions guard{opState};
2116  CustomOpAsmParser opAsmParser(opLoc, resultIDs, parseAssemblyFn,
2117  isIsolatedFromAbove, opName, *this);
2118  if (opAsmParser.parseOperation(opState))
2119  return nullptr;
2120 
2121  // If it emitted an error, we failed.
2122  if (opAsmParser.didEmitError())
2123  return nullptr;
2124 
2125  Attribute properties = opState.propertiesAttr;
2126  opState.propertiesAttr = Attribute{};
2127 
2128  // Otherwise, create the operation and try to parse a location for it.
2129  Operation *op = opBuilder.create(opState);
2130  if (parseTrailingLocationSpecifier(op))
2131  return nullptr;
2132 
2133  // Try setting the properties for the operation.
2134  if (properties) {
2135  auto emitError = [&]() {
2136  return mlir::emitError(srcLocation, "invalid properties ")
2137  << properties << " for op " << op->getName().getStringRef()
2138  << ": ";
2139  };
2140  if (failed(op->setPropertiesFromAttribute(properties, emitError)))
2141  return nullptr;
2142  }
2143  return op;
2144 }
2145 
2146 ParseResult OperationParser::parseLocationAlias(LocationAttr &loc) {
2147  Token tok = getToken();
2148  consumeToken(Token::hash_identifier);
2149  StringRef identifier = tok.getSpelling().drop_front();
2150  assert(!identifier.contains('.') &&
2151  "unexpected dialect attribute token, expected alias");
2152 
2153  if (state.asmState)
2154  state.asmState->addAttrAliasUses(identifier, tok.getLocRange());
2155 
2156  // If this alias can be resolved, do it now.
2157  Attribute attr = state.symbols.attributeAliasDefinitions.lookup(identifier);
2158  if (attr) {
2159  if (!(loc = dyn_cast<LocationAttr>(attr)))
2160  return emitError(tok.getLoc())
2161  << "expected location, but found '" << attr << "'";
2162  } else {
2163  // Otherwise, remember this operation and resolve its location later.
2164  // In the meantime, use a special OpaqueLoc as a marker.
2165  loc = OpaqueLoc::get(deferredLocsReferences.size(),
2166  TypeID::get<DeferredLocInfo *>(),
2168  deferredLocsReferences.push_back(DeferredLocInfo{tok.getLoc(), identifier});
2169  }
2170  return success();
2171 }
2172 
2173 ParseResult
2174 OperationParser::parseTrailingLocationSpecifier(OpOrArgument opOrArgument) {
2175  // If there is a 'loc' we parse a trailing location.
2176  if (!consumeIf(Token::kw_loc))
2177  return success();
2178  if (parseToken(Token::l_paren, "expected '(' in location"))
2179  return failure();
2180  Token tok = getToken();
2181 
2182  // Check to see if we are parsing a location alias. We are parsing a location
2183  // alias if the token is a hash identifier *without* a dot in it - the dot
2184  // signifies a dialect attribute. Otherwise, we parse the location directly.
2185  LocationAttr directLoc;
2186  if (tok.is(Token::hash_identifier) && !tok.getSpelling().contains('.')) {
2187  if (parseLocationAlias(directLoc))
2188  return failure();
2189  } else if (parseLocationInstance(directLoc)) {
2190  return failure();
2191  }
2192 
2193  if (parseToken(Token::r_paren, "expected ')' in location"))
2194  return failure();
2195 
2196  if (auto *op = llvm::dyn_cast_if_present<Operation *>(opOrArgument))
2197  op->setLoc(directLoc);
2198  else
2199  cast<BlockArgument>(opOrArgument).setLoc(directLoc);
2200  return success();
2201 }
2202 
2203 //===----------------------------------------------------------------------===//
2204 // Region Parsing
2205 //===----------------------------------------------------------------------===//
2206 
2207 ParseResult OperationParser::parseRegion(Region &region,
2208  ArrayRef<Argument> entryArguments,
2209  bool isIsolatedNameScope) {
2210  // Parse the '{'.
2211  Token lBraceTok = getToken();
2212  if (parseToken(Token::l_brace, "expected '{' to begin a region"))
2213  return failure();
2214 
2215  // If we are populating the parser state, start a new region definition.
2216  if (state.asmState)
2217  state.asmState->startRegionDefinition();
2218 
2219  // Parse the region body.
2220  if ((!entryArguments.empty() || getToken().isNot(Token::r_brace)) &&
2221  parseRegionBody(region, lBraceTok.getLoc(), entryArguments,
2222  isIsolatedNameScope)) {
2223  return failure();
2224  }
2225  consumeToken(Token::r_brace);
2226 
2227  // If we are populating the parser state, finalize this region.
2228  if (state.asmState)
2229  state.asmState->finalizeRegionDefinition();
2230 
2231  return success();
2232 }
2233 
2234 ParseResult OperationParser::parseRegionBody(Region &region, SMLoc startLoc,
2235  ArrayRef<Argument> entryArguments,
2236  bool isIsolatedNameScope) {
2237  auto currentPt = opBuilder.saveInsertionPoint();
2238 
2239  // Push a new named value scope.
2240  pushSSANameScope(isIsolatedNameScope);
2241 
2242  // Parse the first block directly to allow for it to be unnamed.
2243  auto owningBlock = std::make_unique<Block>();
2244  auto failureCleanup = llvm::make_scope_exit([&] {
2245  if (owningBlock) {
2246  // If parsing failed, as indicated by the fact that `owningBlock` still
2247  // owns the block, drop all forward references from preceding operations
2248  // to definitions within the parsed block.
2249  owningBlock->dropAllDefinedValueUses();
2250  }
2251  });
2252  Block *block = owningBlock.get();
2253 
2254  // If this block is not defined in the source file, add a definition for it
2255  // now in the assembly state. Blocks with a name will be defined when the name
2256  // is parsed.
2257  if (state.asmState && getToken().isNot(Token::caret_identifier))
2258  state.asmState->addDefinition(block, startLoc);
2259 
2260  // Add arguments to the entry block if we had the form with explicit names.
2261  if (!entryArguments.empty() && !entryArguments[0].ssaName.name.empty()) {
2262  // If we had named arguments, then don't allow a block name.
2263  if (getToken().is(Token::caret_identifier))
2264  return emitError("invalid block name in region with named arguments");
2265 
2266  for (auto &entryArg : entryArguments) {
2267  auto &argInfo = entryArg.ssaName;
2268 
2269  // Ensure that the argument was not already defined.
2270  if (auto defLoc = getReferenceLoc(argInfo.name, argInfo.number)) {
2271  return emitError(argInfo.location, "region entry argument '" +
2272  argInfo.name +
2273  "' is already in use")
2274  .attachNote(getEncodedSourceLocation(*defLoc))
2275  << "previously referenced here";
2276  }
2277  Location loc = entryArg.sourceLoc.has_value()
2278  ? *entryArg.sourceLoc
2279  : getEncodedSourceLocation(argInfo.location);
2280  BlockArgument arg = block->addArgument(entryArg.type, loc);
2281 
2282  // Add a definition of this arg to the assembly state if provided.
2283  if (state.asmState)
2284  state.asmState->addDefinition(arg, argInfo.location);
2285 
2286  // Record the definition for this argument.
2287  if (addDefinition(argInfo, arg))
2288  return failure();
2289  }
2290  }
2291 
2292  if (parseBlock(block))
2293  return failure();
2294 
2295  // Verify that no other arguments were parsed.
2296  if (!entryArguments.empty() &&
2297  block->getNumArguments() > entryArguments.size()) {
2298  return emitError("entry block arguments were already defined");
2299  }
2300 
2301  // Parse the rest of the region.
2302  region.push_back(owningBlock.release());
2303  while (getToken().isNot(Token::r_brace)) {
2304  Block *newBlock = nullptr;
2305  if (parseBlock(newBlock))
2306  return failure();
2307  region.push_back(newBlock);
2308  }
2309 
2310  // Pop the SSA value scope for this region.
2311  if (popSSANameScope())
2312  return failure();
2313 
2314  // Reset the original insertion point.
2315  opBuilder.restoreInsertionPoint(currentPt);
2316  return success();
2317 }
2318 
2319 //===----------------------------------------------------------------------===//
2320 // Block Parsing
2321 //===----------------------------------------------------------------------===//
2322 
2323 /// Block declaration.
2324 ///
2325 /// block ::= block-label? operation*
2326 /// block-label ::= block-id block-arg-list? `:`
2327 /// block-id ::= caret-id
2328 /// block-arg-list ::= `(` ssa-id-and-type-list? `)`
2329 ///
2330 ParseResult OperationParser::parseBlock(Block *&block) {
2331  // The first block of a region may already exist, if it does the caret
2332  // identifier is optional.
2333  if (block && getToken().isNot(Token::caret_identifier))
2334  return parseBlockBody(block);
2335 
2336  SMLoc nameLoc = getToken().getLoc();
2337  auto name = getTokenSpelling();
2338  if (parseToken(Token::caret_identifier, "expected block name"))
2339  return failure();
2340 
2341  // Define the block with the specified name.
2342  auto &blockAndLoc = getBlockInfoByName(name);
2343  blockAndLoc.loc = nameLoc;
2344 
2345  // Use a unique pointer for in-flight block being parsed. Release ownership
2346  // only in the case of a successful parse. This ensures that the Block
2347  // allocated is released if the parse fails and control returns early.
2348  std::unique_ptr<Block> inflightBlock;
2349  auto cleanupOnFailure = llvm::make_scope_exit([&] {
2350  if (inflightBlock)
2351  inflightBlock->dropAllDefinedValueUses();
2352  });
2353 
2354  // If a block has yet to be set, this is a new definition. If the caller
2355  // provided a block, use it. Otherwise create a new one.
2356  if (!blockAndLoc.block) {
2357  if (block) {
2358  blockAndLoc.block = block;
2359  } else {
2360  inflightBlock = std::make_unique<Block>();
2361  blockAndLoc.block = inflightBlock.get();
2362  }
2363 
2364  // Otherwise, the block has a forward declaration. Forward declarations are
2365  // removed once defined, so if we are defining a existing block and it is
2366  // not a forward declaration, then it is a redeclaration. Fail if the block
2367  // was already defined.
2368  } else if (!eraseForwardRef(blockAndLoc.block)) {
2369  return emitError(nameLoc, "redefinition of block '") << name << "'";
2370  } else {
2371  // This was a forward reference block that is now floating. Keep track of it
2372  // as inflight in case of error, so that it gets cleaned up properly.
2373  inflightBlock.reset(blockAndLoc.block);
2374  }
2375 
2376  // Populate the high level assembly state if necessary.
2377  if (state.asmState)
2378  state.asmState->addDefinition(blockAndLoc.block, nameLoc);
2379  block = blockAndLoc.block;
2380 
2381  // If an argument list is present, parse it.
2382  if (getToken().is(Token::l_paren))
2383  if (parseOptionalBlockArgList(block))
2384  return failure();
2385  if (parseToken(Token::colon, "expected ':' after block name"))
2386  return failure();
2387 
2388  // Parse the body of the block.
2389  ParseResult res = parseBlockBody(block);
2390 
2391  // If parsing was successful, drop the inflight block. We relinquish ownership
2392  // back up to the caller.
2393  if (succeeded(res))
2394  (void)inflightBlock.release();
2395  return res;
2396 }
2397 
2398 ParseResult OperationParser::parseBlockBody(Block *block) {
2399  // Set the insertion point to the end of the block to parse.
2400  opBuilder.setInsertionPointToEnd(block);
2401 
2402  // Parse the list of operations that make up the body of the block.
2403  while (getToken().isNot(Token::caret_identifier, Token::r_brace))
2404  if (parseOperation())
2405  return failure();
2406 
2407  return success();
2408 }
2409 
2410 /// Get the block with the specified name, creating it if it doesn't already
2411 /// exist. The location specified is the point of use, which allows
2412 /// us to diagnose references to blocks that are not defined precisely.
2413 Block *OperationParser::getBlockNamed(StringRef name, SMLoc loc) {
2414  BlockDefinition &blockDef = getBlockInfoByName(name);
2415  if (!blockDef.block) {
2416  blockDef = {new Block(), loc};
2417  insertForwardRef(blockDef.block, blockDef.loc);
2418  }
2419 
2420  // Populate the high level assembly state if necessary.
2421  if (state.asmState)
2422  state.asmState->addUses(blockDef.block, loc);
2423 
2424  return blockDef.block;
2425 }
2426 
2427 /// Parse a (possibly empty) list of SSA operands with types as block arguments
2428 /// enclosed in parentheses.
2429 ///
2430 /// value-id-and-type-list ::= value-id-and-type (`,` ssa-id-and-type)*
2431 /// block-arg-list ::= `(` value-id-and-type-list? `)`
2432 ///
2433 ParseResult OperationParser::parseOptionalBlockArgList(Block *owner) {
2434  if (getToken().is(Token::r_brace))
2435  return success();
2436 
2437  // If the block already has arguments, then we're handling the entry block.
2438  // Parse and register the names for the arguments, but do not add them.
2439  bool definingExistingArgs = owner->getNumArguments() != 0;
2440  unsigned nextArgument = 0;
2441 
2442  return parseCommaSeparatedList(Delimiter::Paren, [&]() -> ParseResult {
2443  return parseSSADefOrUseAndType(
2444  [&](UnresolvedOperand useInfo, Type type) -> ParseResult {
2445  BlockArgument arg;
2446 
2447  // If we are defining existing arguments, ensure that the argument
2448  // has already been created with the right type.
2449  if (definingExistingArgs) {
2450  // Otherwise, ensure that this argument has already been created.
2451  if (nextArgument >= owner->getNumArguments())
2452  return emitError("too many arguments specified in argument list");
2453 
2454  // Finally, make sure the existing argument has the correct type.
2455  arg = owner->getArgument(nextArgument++);
2456  if (arg.getType() != type)
2457  return emitError("argument and block argument type mismatch");
2458  } else {
2459  auto loc = getEncodedSourceLocation(useInfo.location);
2460  arg = owner->addArgument(type, loc);
2461  }
2462 
2463  // If the argument has an explicit loc(...) specifier, parse and apply
2464  // it.
2465  if (parseTrailingLocationSpecifier(arg))
2466  return failure();
2467 
2468  // Mark this block argument definition in the parser state if it was
2469  // provided.
2470  if (state.asmState)
2471  state.asmState->addDefinition(arg, useInfo.location);
2472 
2473  return addDefinition(useInfo, arg);
2474  });
2475  });
2476 }
2477 
2478 //===----------------------------------------------------------------------===//
2479 // Code Completion
2480 //===----------------------------------------------------------------------===//
2481 
2482 ParseResult OperationParser::codeCompleteSSAUse() {
2483  for (IsolatedSSANameScope &scope : isolatedNameScopes) {
2484  for (auto &it : scope.values) {
2485  if (it.second.empty())
2486  continue;
2487  Value frontValue = it.second.front().value;
2488 
2489  std::string detailData;
2490  llvm::raw_string_ostream detailOS(detailData);
2491 
2492  // If the value isn't a forward reference, we also add the name of the op
2493  // to the detail.
2494  if (auto result = dyn_cast<OpResult>(frontValue)) {
2495  if (!forwardRefPlaceholders.count(result))
2496  detailOS << result.getOwner()->getName() << ": ";
2497  } else {
2498  detailOS << "arg #" << cast<BlockArgument>(frontValue).getArgNumber()
2499  << ": ";
2500  }
2501 
2502  // Emit the type of the values to aid with completion selection.
2503  detailOS << frontValue.getType();
2504 
2505  // FIXME: We should define a policy for packed values, e.g. with a limit
2506  // on the detail size, but it isn't clear what would be useful right now.
2507  // For now we just only emit the first type.
2508  if (it.second.size() > 1)
2509  detailOS << ", ...";
2510 
2511  state.codeCompleteContext->appendSSAValueCompletion(
2512  it.getKey(), std::move(detailData));
2513  }
2514  }
2515 
2516  return failure();
2517 }
2518 
2519 ParseResult OperationParser::codeCompleteBlock() {
2520  // Don't provide completions if the token isn't empty, e.g. this avoids
2521  // weirdness when we encounter a `.` within the identifier.
2522  StringRef spelling = getTokenSpelling();
2523  if (!(spelling.empty() || spelling == "^"))
2524  return failure();
2525 
2526  for (const auto &it : blocksByName.back())
2527  state.codeCompleteContext->appendBlockCompletion(it.getFirst());
2528  return failure();
2529 }
2530 
2531 //===----------------------------------------------------------------------===//
2532 // Top-level entity parsing.
2533 //===----------------------------------------------------------------------===//
2534 
2535 namespace {
2536 /// This parser handles entities that are only valid at the top level of the
2537 /// file.
2538 class TopLevelOperationParser : public Parser {
2539 public:
2540  explicit TopLevelOperationParser(ParserState &state) : Parser(state) {}
2541 
2542  /// Parse a set of operations into the end of the given Block.
2543  ParseResult parse(Block *topLevelBlock, Location parserLoc);
2544 
2545 private:
2546  /// Parse an attribute alias declaration.
2547  ///
2548  /// attribute-alias-def ::= '#' alias-name `=` attribute-value
2549  ///
2550  ParseResult parseAttributeAliasDef();
2551 
2552  /// Parse a type alias declaration.
2553  ///
2554  /// type-alias-def ::= '!' alias-name `=` type
2555  ///
2556  ParseResult parseTypeAliasDef();
2557 
2558  /// Parse a top-level file metadata dictionary.
2559  ///
2560  /// file-metadata-dict ::= '{-#' file-metadata-entry* `#-}'
2561  ///
2562  ParseResult parseFileMetadataDictionary();
2563 
2564  /// Parse a resource metadata dictionary.
2565  ParseResult parseResourceFileMetadata(
2566  function_ref<ParseResult(StringRef, SMLoc)> parseBody);
2567  ParseResult parseDialectResourceFileMetadata();
2568  ParseResult parseExternalResourceFileMetadata();
2569 };
2570 
2571 /// This class represents an implementation of a resource entry for the MLIR
2572 /// textual format.
2573 class ParsedResourceEntry : public AsmParsedResourceEntry {
2574 public:
2575  ParsedResourceEntry(std::string key, SMLoc keyLoc, Token value, Parser &p)
2576  : key(std::move(key)), keyLoc(keyLoc), value(value), p(p) {}
2577  ~ParsedResourceEntry() override = default;
2578 
2579  StringRef getKey() const final { return key; }
2580 
2581  InFlightDiagnostic emitError() const final { return p.emitError(keyLoc); }
2582 
2583  AsmResourceEntryKind getKind() const final {
2584  if (value.isAny(Token::kw_true, Token::kw_false))
2586  return value.getSpelling().starts_with("\"0x")
2589  }
2590 
2591  FailureOr<bool> parseAsBool() const final {
2592  if (value.is(Token::kw_true))
2593  return true;
2594  if (value.is(Token::kw_false))
2595  return false;
2596  return p.emitError(value.getLoc(),
2597  "expected 'true' or 'false' value for key '" + key +
2598  "'");
2599  }
2600 
2601  FailureOr<std::string> parseAsString() const final {
2602  if (value.isNot(Token::string))
2603  return p.emitError(value.getLoc(),
2604  "expected string value for key '" + key + "'");
2605  return value.getStringValue();
2606  }
2607 
2608  FailureOr<AsmResourceBlob>
2609  parseAsBlob(BlobAllocatorFn allocator) const final {
2610  // Blob data within then textual format is represented as a hex string.
2611  // TODO: We could avoid an additional alloc+copy here if we pre-allocated
2612  // the buffer to use during hex processing.
2613  std::optional<std::string> blobData =
2614  value.is(Token::string) ? value.getHexStringValue() : std::nullopt;
2615  if (!blobData)
2616  return p.emitError(value.getLoc(),
2617  "expected hex string blob for key '" + key + "'");
2618 
2619  // Extract the alignment of the blob data, which gets stored at the
2620  // beginning of the string.
2621  if (blobData->size() < sizeof(uint32_t)) {
2622  return p.emitError(value.getLoc(),
2623  "expected hex string blob for key '" + key +
2624  "' to encode alignment in first 4 bytes");
2625  }
2626  llvm::support::ulittle32_t align;
2627  memcpy(&align, blobData->data(), sizeof(uint32_t));
2628  if (align && !llvm::isPowerOf2_32(align)) {
2629  return p.emitError(value.getLoc(),
2630  "expected hex string blob for key '" + key +
2631  "' to encode alignment in first 4 bytes, but got "
2632  "non-power-of-2 value: " +
2633  Twine(align));
2634  }
2635 
2636  // Get the data portion of the blob.
2637  StringRef data = StringRef(*blobData).drop_front(sizeof(uint32_t));
2638  if (data.empty())
2639  return AsmResourceBlob();
2640 
2641  // Allocate memory for the blob using the provided allocator and copy the
2642  // data into it.
2643  AsmResourceBlob blob = allocator(data.size(), align);
2644  assert(llvm::isAddrAligned(llvm::Align(align), blob.getData().data()) &&
2645  blob.isMutable() &&
2646  "blob allocator did not return a properly aligned address");
2647  memcpy(blob.getMutableData().data(), data.data(), data.size());
2648  return blob;
2649  }
2650 
2651 private:
2652  std::string key;
2653  SMLoc keyLoc;
2654  Token value;
2655  Parser &p;
2656 };
2657 } // namespace
2658 
2659 ParseResult TopLevelOperationParser::parseAttributeAliasDef() {
2660  assert(getToken().is(Token::hash_identifier));
2661  StringRef aliasName = getTokenSpelling().drop_front();
2662 
2663  // Check for redefinitions.
2664  if (state.symbols.attributeAliasDefinitions.count(aliasName) > 0)
2665  return emitError("redefinition of attribute alias id '" + aliasName + "'");
2666 
2667  // Make sure this isn't invading the dialect attribute namespace.
2668  if (aliasName.contains('.'))
2669  return emitError("attribute names with a '.' are reserved for "
2670  "dialect-defined names");
2671 
2672  SMRange location = getToken().getLocRange();
2673  consumeToken(Token::hash_identifier);
2674 
2675  // Parse the '='.
2676  if (parseToken(Token::equal, "expected '=' in attribute alias definition"))
2677  return failure();
2678 
2679  // Parse the attribute value.
2680  Attribute attr = parseAttribute();
2681  if (!attr)
2682  return failure();
2683 
2684  // Register this alias with the parser state.
2685  if (state.asmState)
2686  state.asmState->addAttrAliasDefinition(aliasName, location, attr);
2687  state.symbols.attributeAliasDefinitions[aliasName] = attr;
2688  return success();
2689 }
2690 
2691 ParseResult TopLevelOperationParser::parseTypeAliasDef() {
2692  assert(getToken().is(Token::exclamation_identifier));
2693  StringRef aliasName = getTokenSpelling().drop_front();
2694 
2695  // Check for redefinitions.
2696  if (state.symbols.typeAliasDefinitions.count(aliasName) > 0)
2697  return emitError("redefinition of type alias id '" + aliasName + "'");
2698 
2699  // Make sure this isn't invading the dialect type namespace.
2700  if (aliasName.contains('.'))
2701  return emitError("type names with a '.' are reserved for "
2702  "dialect-defined names");
2703 
2704  SMRange location = getToken().getLocRange();
2705  consumeToken(Token::exclamation_identifier);
2706 
2707  // Parse the '='.
2708  if (parseToken(Token::equal, "expected '=' in type alias definition"))
2709  return failure();
2710 
2711  // Parse the type.
2712  Type aliasedType = parseType();
2713  if (!aliasedType)
2714  return failure();
2715 
2716  // Register this alias with the parser state.
2717  if (state.asmState)
2718  state.asmState->addTypeAliasDefinition(aliasName, location, aliasedType);
2719  state.symbols.typeAliasDefinitions.try_emplace(aliasName, aliasedType);
2720  return success();
2721 }
2722 
2723 ParseResult TopLevelOperationParser::parseFileMetadataDictionary() {
2724  consumeToken(Token::file_metadata_begin);
2725  return parseCommaSeparatedListUntil(
2726  Token::file_metadata_end, [&]() -> ParseResult {
2727  // Parse the key of the metadata dictionary.
2728  SMLoc keyLoc = getToken().getLoc();
2729  StringRef key;
2730  if (failed(parseOptionalKeyword(&key)))
2731  return emitError("expected identifier key in file "
2732  "metadata dictionary");
2733  if (parseToken(Token::colon, "expected ':'"))
2734  return failure();
2735 
2736  // Process the metadata entry.
2737  if (key == "dialect_resources")
2738  return parseDialectResourceFileMetadata();
2739  if (key == "external_resources")
2740  return parseExternalResourceFileMetadata();
2741  return emitError(keyLoc, "unknown key '" + key +
2742  "' in file metadata dictionary");
2743  });
2744 }
2745 
2746 ParseResult TopLevelOperationParser::parseResourceFileMetadata(
2747  function_ref<ParseResult(StringRef, SMLoc)> parseBody) {
2748  if (parseToken(Token::l_brace, "expected '{'"))
2749  return failure();
2750 
2751  return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2752  // Parse the top-level name entry.
2753  SMLoc nameLoc = getToken().getLoc();
2754  StringRef name;
2755  if (failed(parseOptionalKeyword(&name)))
2756  return emitError("expected identifier key for 'resource' entry");
2757 
2758  if (parseToken(Token::colon, "expected ':'") ||
2759  parseToken(Token::l_brace, "expected '{'"))
2760  return failure();
2761  return parseBody(name, nameLoc);
2762  });
2763 }
2764 
2765 ParseResult TopLevelOperationParser::parseDialectResourceFileMetadata() {
2766  return parseResourceFileMetadata([&](StringRef name,
2767  SMLoc nameLoc) -> ParseResult {
2768  // Lookup the dialect and check that it can handle a resource entry.
2769  Dialect *dialect = getContext()->getOrLoadDialect(name);
2770  if (!dialect)
2771  return emitError(nameLoc, "dialect '" + name + "' is unknown");
2772  const auto *handler = dyn_cast<OpAsmDialectInterface>(dialect);
2773  if (!handler) {
2774  return emitError() << "unexpected 'resource' section for dialect '"
2775  << dialect->getNamespace() << "'";
2776  }
2777 
2778  return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2779  // Parse the name of the resource entry.
2780  SMLoc keyLoc = getToken().getLoc();
2781  std::string key;
2782  if (failed(parseResourceHandle(handler, key)) ||
2783  parseToken(Token::colon, "expected ':'"))
2784  return failure();
2785  Token valueTok = getToken();
2786  consumeToken();
2787 
2788  ParsedResourceEntry entry(key, keyLoc, valueTok, *this);
2789  return handler->parseResource(entry);
2790  });
2791  });
2792 }
2793 
2794 ParseResult TopLevelOperationParser::parseExternalResourceFileMetadata() {
2795  return parseResourceFileMetadata([&](StringRef name,
2796  SMLoc nameLoc) -> ParseResult {
2797  AsmResourceParser *handler = state.config.getResourceParser(name);
2798 
2799  // TODO: Should we require handling external resources in some scenarios?
2800  if (!handler) {
2801  emitWarning(getEncodedSourceLocation(nameLoc))
2802  << "ignoring unknown external resources for '" << name << "'";
2803  }
2804 
2805  return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2806  // Parse the name of the resource entry.
2807  SMLoc keyLoc = getToken().getLoc();
2808  std::string key;
2809  if (failed(parseOptionalKeywordOrString(&key)))
2810  return emitError(
2811  "expected identifier key for 'external_resources' entry");
2812  if (parseToken(Token::colon, "expected ':'"))
2813  return failure();
2814  Token valueTok = getToken();
2815  consumeToken();
2816 
2817  if (!handler)
2818  return success();
2819  ParsedResourceEntry entry(key, keyLoc, valueTok, *this);
2820  return handler->parseResource(entry);
2821  });
2822  });
2823 }
2824 
2825 ParseResult TopLevelOperationParser::parse(Block *topLevelBlock,
2826  Location parserLoc) {
2827  // Create a top-level operation to contain the parsed state.
2828  OwningOpRef<ModuleOp> topLevelOp(ModuleOp::create(parserLoc));
2829  OperationParser opParser(state, topLevelOp.get());
2830  while (true) {
2831  switch (getToken().getKind()) {
2832  default:
2833  // Parse a top-level operation.
2834  if (opParser.parseOperation())
2835  return failure();
2836  break;
2837 
2838  // If we got to the end of the file, then we're done.
2839  case Token::eof: {
2840  if (opParser.finalize())
2841  return failure();
2842 
2843  // Splice the blocks of the parsed operation over to the provided
2844  // top-level block.
2845  auto &parsedOps = topLevelOp->getBody()->getOperations();
2846  auto &destOps = topLevelBlock->getOperations();
2847  destOps.splice(destOps.end(), parsedOps, parsedOps.begin(),
2848  parsedOps.end());
2849  return success();
2850  }
2851 
2852  // If we got an error token, then the lexer already emitted an error, just
2853  // stop. Someday we could introduce error recovery if there was demand
2854  // for it.
2855  case Token::error:
2856  return failure();
2857 
2858  // Parse an attribute alias.
2859  case Token::hash_identifier:
2860  if (parseAttributeAliasDef())
2861  return failure();
2862  break;
2863 
2864  // Parse a type alias.
2865  case Token::exclamation_identifier:
2866  if (parseTypeAliasDef())
2867  return failure();
2868  break;
2869 
2870  // Parse a file-level metadata dictionary.
2871  case Token::file_metadata_begin:
2872  if (parseFileMetadataDictionary())
2873  return failure();
2874  break;
2875  }
2876  }
2877 }
2878 
2879 //===----------------------------------------------------------------------===//
2880 
2881 LogicalResult
2882 mlir::parseAsmSourceFile(const llvm::SourceMgr &sourceMgr, Block *block,
2883  const ParserConfig &config, AsmParserState *asmState,
2884  AsmParserCodeCompleteContext *codeCompleteContext) {
2885  const auto *sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
2886 
2887  Location parserLoc =
2888  FileLineColLoc::get(config.getContext(), sourceBuf->getBufferIdentifier(),
2889  /*line=*/0, /*column=*/0);
2890 
2891  SymbolState aliasState;
2892  ParserState state(sourceMgr, config, aliasState, asmState,
2893  codeCompleteContext);
2894  return TopLevelOperationParser(state).parse(block, parserLoc);
2895 }
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:295
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:96
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
Definition: Block.cpp:155
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:85
StringRef getNamespace() const
Definition: Dialect.h:54
static FileLineColLoc get(StringAttr filename, unsigned line, unsigned column)
Definition: Location.cpp:160
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:31
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:66
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
Definition: MLIRContext.h:97
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
DictionaryAttr getDictionary(MLIRContext *context) const
Return a dictionary attribute for the underlying dictionary.
void push_back(NamedAttribute newAttribute)
Add an attribute with the specified name.
std::optional< NamedAttribute > findDuplicate() const
Returns an entry with a duplicate name the list, if it exists, else returns std::nullopt.
virtual std::string getResourceKey(const AsmDialectResourceHandle &handle) const
Return a key to use for the given resource.
virtual FailureOr< AsmDialectResourceHandle > declareResource(StringRef key) const
Declare a resource with the given key, returning a handle to use for any references of this resource ...
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
RAII guard to reset the insertion point of the builder when destroyed.
Definition: Builders.h:346
This class helps build Operations.
Definition: Builders.h:205
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:772
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:67
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:355
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:39
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:26
static WalkResult advance()
Definition: Visitors.h:51
static WalkResult interrupt()
Definition: Visitors.h:50
This class provides the implementation of the generic parser methods within AsmParser.
Definition: AsmParserImpl.h:28
InFlightDiagnostic emitError(SMLoc loc, const Twine &message) override
Emit a diagnostic at the specified location and return failure.
Definition: AsmParserImpl.h:45
This class implement support for parsing global entities like attributes and types.
Definition: Parser.h: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:20
llvm::PointerUnion< NamedAttribute *, NamedProperty *, NamedTypeConstraint * > Argument
Definition: Argument.h:64
Include the generated interface declarations.
InFlightDiagnostic emitWarning(Location loc)
Utility method to emit a warning message using this location.
LogicalResult parseAsmSourceFile(const llvm::SourceMgr &sourceMgr, Block *block, const ParserConfig &config, AsmParserState *asmState=nullptr, AsmParserCodeCompleteContext *codeCompleteContext=nullptr)
This parses the file specified by the indicated SourceMgr and appends parsed operations to the given ...
Definition: Parser.cpp:2882
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