brintos

brintos / llvm-project-archived public Read only

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