brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.1 KiB · a461ebe Raw
620 lines · cpp
1//===- TypeParser.cpp - MLIR Type 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 Types.10//11//===----------------------------------------------------------------------===//12 13#include "Parser.h"14#include "mlir/IR/AffineMap.h"15#include "mlir/IR/BuiltinAttributeInterfaces.h"16#include "mlir/IR/BuiltinTypeInterfaces.h"17#include "mlir/IR/BuiltinTypes.h"18#include "mlir/IR/OpDefinition.h"19#include "mlir/IR/TensorEncoding.h"20#include "mlir/IR/Types.h"21#include "mlir/Support/LLVM.h"22#include <cassert>23#include <cstdint>24#include <limits>25#include <optional>26 27using namespace mlir;28using namespace mlir::detail;29 30/// Optionally parse a type.31OptionalParseResult Parser::parseOptionalType(Type &type) {32  // There are many different starting tokens for a type, check them here.33  switch (getToken().getKind()) {34  case Token::l_paren:35  case Token::kw_memref:36  case Token::kw_tensor:37  case Token::kw_complex:38  case Token::kw_tuple:39  case Token::kw_vector:40  case Token::inttype:41  case Token::kw_f4E2M1FN:42  case Token::kw_f6E2M3FN:43  case Token::kw_f6E3M2FN:44  case Token::kw_f8E5M2:45  case Token::kw_f8E4M3:46  case Token::kw_f8E4M3FN:47  case Token::kw_f8E5M2FNUZ:48  case Token::kw_f8E4M3FNUZ:49  case Token::kw_f8E4M3B11FNUZ:50  case Token::kw_f8E3M4:51  case Token::kw_f8E8M0FNU:52  case Token::kw_bf16:53  case Token::kw_f16:54  case Token::kw_tf32:55  case Token::kw_f32:56  case Token::kw_f64:57  case Token::kw_f80:58  case Token::kw_f128:59  case Token::kw_index:60  case Token::kw_none:61  case Token::exclamation_identifier:62    return failure(!(type = parseType()));63 64  default:65    return std::nullopt;66  }67}68 69/// Parse an arbitrary type.70///71///   type ::= function-type72///          | non-function-type73///74Type Parser::parseType() {75  if (getToken().is(Token::l_paren))76    return parseFunctionType();77  return parseNonFunctionType();78}79 80/// Parse a function result type.81///82///   function-result-type ::= type-list-parens83///                          | non-function-type84///85ParseResult Parser::parseFunctionResultTypes(SmallVectorImpl<Type> &elements) {86  if (getToken().is(Token::l_paren))87    return parseTypeListParens(elements);88 89  Type t = parseNonFunctionType();90  if (!t)91    return failure();92  elements.push_back(t);93  return success();94}95 96/// Parse a list of types without an enclosing parenthesis.  The list must have97/// at least one member.98///99///   type-list-no-parens ::=  type (`,` type)*100///101ParseResult Parser::parseTypeListNoParens(SmallVectorImpl<Type> &elements) {102  auto parseElt = [&]() -> ParseResult {103    auto elt = parseType();104    elements.push_back(elt);105    return elt ? success() : failure();106  };107 108  return parseCommaSeparatedList(parseElt);109}110 111/// Parse a parenthesized list of types.112///113///   type-list-parens ::= `(` `)`114///                      | `(` type-list-no-parens `)`115///116ParseResult Parser::parseTypeListParens(SmallVectorImpl<Type> &elements) {117  if (parseToken(Token::l_paren, "expected '('"))118    return failure();119 120  // Handle empty lists.121  if (getToken().is(Token::r_paren))122    return consumeToken(), success();123 124  if (parseTypeListNoParens(elements) ||125      parseToken(Token::r_paren, "expected ')'"))126    return failure();127  return success();128}129 130/// Parse a complex type.131///132///   complex-type ::= `complex` `<` type `>`133///134Type Parser::parseComplexType() {135  consumeToken(Token::kw_complex);136 137  // Parse the '<'.138  if (parseToken(Token::less, "expected '<' in complex type"))139    return nullptr;140 141  SMLoc elementTypeLoc = getToken().getLoc();142  auto elementType = parseType();143  if (!elementType ||144      parseToken(Token::greater, "expected '>' in complex type"))145    return nullptr;146  if (!isa<FloatType>(elementType) && !isa<IntegerType>(elementType))147    return emitError(elementTypeLoc, "invalid element type for complex"),148           nullptr;149 150  return ComplexType::get(elementType);151}152 153/// Parse a function type.154///155///   function-type ::= type-list-parens `->` function-result-type156///157Type Parser::parseFunctionType() {158  assert(getToken().is(Token::l_paren));159 160  SmallVector<Type, 4> arguments, results;161  if (parseTypeListParens(arguments) ||162      parseToken(Token::arrow, "expected '->' in function type") ||163      parseFunctionResultTypes(results))164    return nullptr;165 166  return builder.getFunctionType(arguments, results);167}168 169/// Parse a memref type.170///171///   memref-type ::= ranked-memref-type | unranked-memref-type172///173///   ranked-memref-type ::= `memref` `<` dimension-list-ranked type174///                          (`,` layout-specification)? (`,` memory-space)? `>`175///176///   unranked-memref-type ::= `memref` `<*x` type (`,` memory-space)? `>`177///178///   stride-list ::= `[` (dimension (`,` dimension)*)? `]`179///   strided-layout ::= `offset:` dimension `,` `strides: ` stride-list180///   layout-specification ::= semi-affine-map | strided-layout | attribute181///   memory-space ::= integer-literal | attribute182///183Type Parser::parseMemRefType() {184  SMLoc loc = getToken().getLoc();185  consumeToken(Token::kw_memref);186 187  if (parseToken(Token::less, "expected '<' in memref type"))188    return nullptr;189 190  bool isUnranked;191  SmallVector<int64_t, 4> dimensions;192 193  if (consumeIf(Token::star)) {194    // This is an unranked memref type.195    isUnranked = true;196    if (parseXInDimensionList())197      return nullptr;198 199  } else {200    isUnranked = false;201    if (parseDimensionListRanked(dimensions))202      return nullptr;203  }204 205  // Parse the element type.206  auto typeLoc = getToken().getLoc();207  auto elementType = parseType();208  if (!elementType)209    return nullptr;210 211  // Check that memref is formed from allowed types.212  if (!BaseMemRefType::isValidElementType(elementType))213    return emitError(typeLoc, "invalid memref element type"), nullptr;214 215  MemRefLayoutAttrInterface layout;216  Attribute memorySpace;217 218  auto parseElt = [&]() -> ParseResult {219    // Either it is MemRefLayoutAttrInterface or memory space attribute.220    Attribute attr = parseAttribute();221    if (!attr)222      return failure();223 224    if (isa<MemRefLayoutAttrInterface>(attr)) {225      layout = cast<MemRefLayoutAttrInterface>(attr);226    } else if (memorySpace) {227      return emitError("multiple memory spaces specified in memref type");228    } else {229      memorySpace = attr;230      return success();231    }232 233    if (isUnranked)234      return emitError("cannot have affine map for unranked memref type");235    if (memorySpace)236      return emitError("expected memory space to be last in memref type");237 238    return success();239  };240 241  // Parse a list of mappings and address space if present.242  if (!consumeIf(Token::greater)) {243    // Parse comma separated list of affine maps, followed by memory space.244    if (parseToken(Token::comma, "expected ',' or '>' in memref type") ||245        parseCommaSeparatedListUntil(Token::greater, parseElt,246                                     /*allowEmptyList=*/false)) {247      return nullptr;248    }249  }250 251  if (isUnranked)252    return getChecked<UnrankedMemRefType>(loc, elementType, memorySpace);253 254  return getChecked<MemRefType>(loc, dimensions, elementType, layout,255                                memorySpace);256}257 258/// Parse any type except the function type.259///260///   non-function-type ::= integer-type261///                       | index-type262///                       | float-type263///                       | extended-type264///                       | vector-type265///                       | tensor-type266///                       | memref-type267///                       | complex-type268///                       | tuple-type269///                       | none-type270///271///   index-type ::= `index`272///   float-type ::= `f16` | `bf16` | `f32` | `f64` | `f80` | `f128`273///   none-type ::= `none`274///275Type Parser::parseNonFunctionType() {276  switch (getToken().getKind()) {277  default:278    return (emitWrongTokenError("expected non-function type"), nullptr);279  case Token::kw_memref:280    return parseMemRefType();281  case Token::kw_tensor:282    return parseTensorType();283  case Token::kw_complex:284    return parseComplexType();285  case Token::kw_tuple:286    return parseTupleType();287  case Token::kw_vector:288    return parseVectorType();289  // integer-type290  case Token::inttype: {291    auto width = getToken().getIntTypeBitwidth();292    if (!width.has_value())293      return (emitError("invalid integer width"), nullptr);294    if (*width > IntegerType::kMaxWidth) {295      emitError(getToken().getLoc(), "integer bitwidth is limited to ")296          << IntegerType::kMaxWidth << " bits";297      return nullptr;298    }299 300    IntegerType::SignednessSemantics signSemantics = IntegerType::Signless;301    if (std::optional<bool> signedness = getToken().getIntTypeSignedness())302      signSemantics = *signedness ? IntegerType::Signed : IntegerType::Unsigned;303 304    consumeToken(Token::inttype);305    return IntegerType::get(getContext(), *width, signSemantics);306  }307 308  // float-type309  case Token::kw_f4E2M1FN:310    consumeToken(Token::kw_f4E2M1FN);311    return builder.getType<Float4E2M1FNType>();312  case Token::kw_f6E2M3FN:313    consumeToken(Token::kw_f6E2M3FN);314    return builder.getType<Float6E2M3FNType>();315  case Token::kw_f6E3M2FN:316    consumeToken(Token::kw_f6E3M2FN);317    return builder.getType<Float6E3M2FNType>();318  case Token::kw_f8E5M2:319    consumeToken(Token::kw_f8E5M2);320    return builder.getType<Float8E5M2Type>();321  case Token::kw_f8E4M3:322    consumeToken(Token::kw_f8E4M3);323    return builder.getType<Float8E4M3Type>();324  case Token::kw_f8E4M3FN:325    consumeToken(Token::kw_f8E4M3FN);326    return builder.getType<Float8E4M3FNType>();327  case Token::kw_f8E5M2FNUZ:328    consumeToken(Token::kw_f8E5M2FNUZ);329    return builder.getType<Float8E5M2FNUZType>();330  case Token::kw_f8E4M3FNUZ:331    consumeToken(Token::kw_f8E4M3FNUZ);332    return builder.getType<Float8E4M3FNUZType>();333  case Token::kw_f8E4M3B11FNUZ:334    consumeToken(Token::kw_f8E4M3B11FNUZ);335    return builder.getType<Float8E4M3B11FNUZType>();336  case Token::kw_f8E3M4:337    consumeToken(Token::kw_f8E3M4);338    return builder.getType<Float8E3M4Type>();339  case Token::kw_f8E8M0FNU:340    consumeToken(Token::kw_f8E8M0FNU);341    return builder.getType<Float8E8M0FNUType>();342  case Token::kw_bf16:343    consumeToken(Token::kw_bf16);344    return builder.getType<BFloat16Type>();345  case Token::kw_f16:346    consumeToken(Token::kw_f16);347    return builder.getType<Float16Type>();348  case Token::kw_tf32:349    consumeToken(Token::kw_tf32);350    return builder.getType<FloatTF32Type>();351  case Token::kw_f32:352    consumeToken(Token::kw_f32);353    return builder.getType<Float32Type>();354  case Token::kw_f64:355    consumeToken(Token::kw_f64);356    return builder.getType<Float64Type>();357  case Token::kw_f80:358    consumeToken(Token::kw_f80);359    return builder.getType<Float80Type>();360  case Token::kw_f128:361    consumeToken(Token::kw_f128);362    return builder.getType<Float128Type>();363 364  // index-type365  case Token::kw_index:366    consumeToken(Token::kw_index);367    return builder.getIndexType();368 369  // none-type370  case Token::kw_none:371    consumeToken(Token::kw_none);372    return builder.getNoneType();373 374  // extended type375  case Token::exclamation_identifier:376    return parseExtendedType();377 378  // Handle completion of a dialect type.379  case Token::code_complete:380    if (getToken().isCodeCompletionFor(Token::exclamation_identifier))381      return parseExtendedType();382    return codeCompleteType();383  }384}385 386/// Parse a tensor type.387///388///   tensor-type ::= `tensor` `<` dimension-list type `>`389///   dimension-list ::= dimension-list-ranked | `*x`390///391Type Parser::parseTensorType() {392  consumeToken(Token::kw_tensor);393 394  if (parseToken(Token::less, "expected '<' in tensor type"))395    return nullptr;396 397  bool isUnranked;398  SmallVector<int64_t, 4> dimensions;399 400  if (consumeIf(Token::star)) {401    // This is an unranked tensor type.402    isUnranked = true;403 404    if (parseXInDimensionList())405      return nullptr;406 407  } else {408    isUnranked = false;409    if (parseDimensionListRanked(dimensions))410      return nullptr;411  }412 413  // Parse the element type.414  auto elementTypeLoc = getToken().getLoc();415  auto elementType = parseType();416 417  // Parse an optional encoding attribute.418  Attribute encoding;419  if (consumeIf(Token::comma)) {420    auto parseResult = parseOptionalAttribute(encoding);421    if (parseResult.has_value()) {422      if (failed(parseResult.value()))423        return nullptr;424      if (auto v = dyn_cast_or_null<VerifiableTensorEncoding>(encoding)) {425        if (failed(v.verifyEncoding(dimensions, elementType,426                                    [&] { return emitError(); })))427          return nullptr;428      }429    }430  }431 432  if (!elementType || parseToken(Token::greater, "expected '>' in tensor type"))433    return nullptr;434  if (!TensorType::isValidElementType(elementType))435    return emitError(elementTypeLoc, "invalid tensor element type"), nullptr;436 437  if (isUnranked) {438    if (encoding)439      return emitError("cannot apply encoding to unranked tensor"), nullptr;440    return UnrankedTensorType::get(elementType);441  }442  return RankedTensorType::get(dimensions, elementType, encoding);443}444 445/// Parse a tuple type.446///447///   tuple-type ::= `tuple` `<` (type (`,` type)*)? `>`448///449Type Parser::parseTupleType() {450  consumeToken(Token::kw_tuple);451 452  // Parse the '<'.453  if (parseToken(Token::less, "expected '<' in tuple type"))454    return nullptr;455 456  // Check for an empty tuple by directly parsing '>'.457  if (consumeIf(Token::greater))458    return TupleType::get(getContext());459 460  // Parse the element types and the '>'.461  SmallVector<Type, 4> types;462  if (parseTypeListNoParens(types) ||463      parseToken(Token::greater, "expected '>' in tuple type"))464    return nullptr;465 466  return TupleType::get(getContext(), types);467}468 469/// Parse a vector type.470///471/// vector-type ::= `vector` `<` vector-dim-list vector-element-type `>`472/// vector-dim-list := (static-dim-list `x`)? (`[` static-dim-list `]` `x`)?473/// static-dim-list ::= decimal-literal (`x` decimal-literal)*474///475VectorType Parser::parseVectorType() {476  SMLoc loc = getToken().getLoc();477  consumeToken(Token::kw_vector);478 479  if (parseToken(Token::less, "expected '<' in vector type"))480    return nullptr;481 482  // Parse the dimensions.483  SmallVector<int64_t, 4> dimensions;484  SmallVector<bool, 4> scalableDims;485  if (parseVectorDimensionList(dimensions, scalableDims))486    return nullptr;487 488  // Parse the element type.489  auto elementType = parseType();490  if (!elementType || parseToken(Token::greater, "expected '>' in vector type"))491    return nullptr;492 493  return getChecked<VectorType>(loc, dimensions, elementType, scalableDims);494}495 496/// Parse a dimension list in a vector type. This populates the dimension list.497/// For i-th dimension, `scalableDims[i]` contains either:498///   * `false` for a non-scalable dimension (e.g. `4`),499///   * `true` for a scalable dimension (e.g. `[4]`).500///501/// vector-dim-list := (static-dim-list `x`)?502/// static-dim-list ::= static-dim (`x` static-dim)*503/// static-dim ::= (decimal-literal | `[` decimal-literal `]`)504///505ParseResult506Parser::parseVectorDimensionList(SmallVectorImpl<int64_t> &dimensions,507                                 SmallVectorImpl<bool> &scalableDims) {508  // If there is a set of fixed-length dimensions, consume it509  while (getToken().is(Token::integer) || getToken().is(Token::l_square)) {510    int64_t value;511    bool scalable = consumeIf(Token::l_square);512    if (parseIntegerInDimensionList(value))513      return failure();514    dimensions.push_back(value);515    if (scalable) {516      if (!consumeIf(Token::r_square))517        return emitWrongTokenError("missing ']' closing scalable dimension");518    }519    scalableDims.push_back(scalable);520    // Make sure we have an 'x' or something like 'xbf32'.521    if (parseXInDimensionList())522      return failure();523  }524 525  return success();526}527 528/// Parse a dimension list of a tensor or memref type.  This populates the529/// dimension list, using ShapedType::kDynamic for the `?` dimensions if530/// `allowDynamic` is set and errors out on `?` otherwise. Parsing the trailing531/// `x` is configurable.532///533///   dimension-list ::= eps | dimension (`x` dimension)*534///   dimension-list-with-trailing-x ::= (dimension `x`)*535///   dimension ::= `?` | decimal-literal536///537/// When `allowDynamic` is not set, this is used to parse:538///539///   static-dimension-list ::= eps | decimal-literal (`x` decimal-literal)*540///   static-dimension-list-with-trailing-x ::= (dimension `x`)*541ParseResult542Parser::parseDimensionListRanked(SmallVectorImpl<int64_t> &dimensions,543                                 bool allowDynamic, bool withTrailingX) {544  auto parseDim = [&]() -> LogicalResult {545    auto loc = getToken().getLoc();546    if (consumeIf(Token::question)) {547      if (!allowDynamic)548        return emitError(loc, "expected static shape");549      dimensions.push_back(ShapedType::kDynamic);550    } else {551      int64_t value;552      if (failed(parseIntegerInDimensionList(value)))553        return failure();554      dimensions.push_back(value);555    }556    return success();557  };558 559  if (withTrailingX) {560    while (getToken().isAny(Token::integer, Token::question)) {561      if (failed(parseDim()) || failed(parseXInDimensionList()))562        return failure();563    }564    return success();565  }566 567  if (getToken().isAny(Token::integer, Token::question)) {568    if (failed(parseDim()))569      return failure();570    while (getToken().is(Token::bare_identifier) &&571           getTokenSpelling()[0] == 'x') {572      if (failed(parseXInDimensionList()) || failed(parseDim()))573        return failure();574    }575  }576  return success();577}578 579ParseResult Parser::parseIntegerInDimensionList(int64_t &value) {580  // Hexadecimal integer literals (starting with `0x`) are not allowed in581  // aggregate type declarations.  Therefore, `0xf32` should be processed as582  // a sequence of separate elements `0`, `x`, `f32`.583  if (getTokenSpelling().size() > 1 && getTokenSpelling()[1] == 'x') {584    // We can get here only if the token is an integer literal.  Hexadecimal585    // integer literals can only start with `0x` (`1x` wouldn't lex as a586    // literal, just `1` would, at which point we don't get into this587    // branch).588    assert(getTokenSpelling()[0] == '0' && "invalid integer literal");589    value = 0;590    state.lex.resetPointer(getTokenSpelling().data() + 1);591    consumeToken();592  } else {593    // Make sure this integer value is in bound and valid.594    std::optional<uint64_t> dimension = getToken().getUInt64IntegerValue();595    if (!dimension ||596        *dimension > (uint64_t)std::numeric_limits<int64_t>::max())597      return emitError("invalid dimension");598    value = (int64_t)*dimension;599    consumeToken(Token::integer);600  }601  return success();602}603 604/// Parse an 'x' token in a dimension list, handling the case where the x is605/// juxtaposed with an element type, as in "xf32", leaving the "f32" as the next606/// token.607ParseResult Parser::parseXInDimensionList() {608  if (getToken().isNot(Token::bare_identifier) || getTokenSpelling()[0] != 'x')609    return emitWrongTokenError("expected 'x' in dimension list");610 611  // If we had a prefix of 'x', lex the next token immediately after the 'x'.612  if (getTokenSpelling().size() != 1)613    state.lex.resetPointer(getTokenSpelling().data() + 1);614 615  // Consume the 'x'.616  consumeToken(Token::bare_identifier);617 618  return success();619}620