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