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