brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.6 KiB · 0cddf65 Raw
299 lines · cpp
1//===- ViewLikeInterface.cpp - View-like operations in MLIR ---------------===//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#include "mlir/Interfaces/ViewLikeInterface.h"10 11using namespace mlir;12 13//===----------------------------------------------------------------------===//14// ViewLike Interfaces15//===----------------------------------------------------------------------===//16 17/// Include the definitions of the loop-like interfaces.18#include "mlir/Interfaces/ViewLikeInterface.cpp.inc"19 20LogicalResult mlir::verifyListOfOperandsOrIntegers(Operation *op,21                                                   StringRef name,22                                                   unsigned numElements,23                                                   ArrayRef<int64_t> staticVals,24                                                   ValueRange values) {25  // Check static and dynamic offsets/sizes/strides does not overflow type.26  if (staticVals.size() != numElements)27    return op->emitError("expected ") << numElements << " " << name28                                      << " values, got " << staticVals.size();29  unsigned expectedNumDynamicEntries =30      llvm::count_if(staticVals, ShapedType::isDynamic);31  if (values.size() != expectedNumDynamicEntries)32    return op->emitError("expected ")33           << expectedNumDynamicEntries << " dynamic " << name << " values";34  return success();35}36 37SliceBoundsVerificationResult mlir::verifyInBoundsSlice(38    ArrayRef<int64_t> shape, ArrayRef<int64_t> staticOffsets,39    ArrayRef<int64_t> staticSizes, ArrayRef<int64_t> staticStrides,40    bool generateErrorMessage) {41  SliceBoundsVerificationResult result;42  result.isValid = true;43  for (int64_t i = 0, e = shape.size(); i < e; ++i) {44    // Nothing to verify for dynamic source dims.45    if (ShapedType::isDynamic(shape[i]))46      continue;47    // Nothing to verify if the offset is dynamic.48    if (ShapedType::isDynamic(staticOffsets[i]))49      continue;50    if (staticOffsets[i] >= shape[i]) {51      result.errorMessage =52          std::string("offset ") + std::to_string(i) +53          " is out-of-bounds: " + std::to_string(staticOffsets[i]) +54          " >= " + std::to_string(shape[i]);55      result.isValid = false;56      return result;57    }58    if (ShapedType::isDynamic(staticSizes[i]) ||59        ShapedType::isDynamic(staticStrides[i]))60      continue;61    int64_t lastPos =62        staticOffsets[i] + (staticSizes[i] - 1) * staticStrides[i];63    if (lastPos >= shape[i]) {64      result.errorMessage = std::string("slice along dimension ") +65                            std::to_string(i) +66                            " runs out-of-bounds: " + std::to_string(lastPos) +67                            " >= " + std::to_string(shape[i]);68      result.isValid = false;69      return result;70    }71  }72  return result;73}74 75SliceBoundsVerificationResult mlir::verifyInBoundsSlice(76    ArrayRef<int64_t> shape, ArrayRef<OpFoldResult> mixedOffsets,77    ArrayRef<OpFoldResult> mixedSizes, ArrayRef<OpFoldResult> mixedStrides,78    bool generateErrorMessage) {79  auto getStaticValues = [](ArrayRef<OpFoldResult> ofrs) {80    SmallVector<int64_t> staticValues;81    for (OpFoldResult ofr : ofrs) {82      if (auto attr = dyn_cast<Attribute>(ofr)) {83        staticValues.push_back(cast<IntegerAttr>(attr).getInt());84      } else {85        staticValues.push_back(ShapedType::kDynamic);86      }87    }88    return staticValues;89  };90  return verifyInBoundsSlice(91      shape, getStaticValues(mixedOffsets), getStaticValues(mixedSizes),92      getStaticValues(mixedStrides), generateErrorMessage);93}94 95LogicalResult96mlir::detail::verifyOffsetSizeAndStrideOp(OffsetSizeAndStrideOpInterface op) {97  // A dynamic size is represented as ShapedType::kDynamic in `static_sizes`.98  // Its corresponding Value appears in `sizes`. Thus, the number of dynamic99  // dimensions in `static_sizes` must equal the rank of `sizes`.100  // The same applies to strides and offsets.101  size_t numDynamicDims =102      llvm::count_if(op.getStaticSizes(), ShapedType::isDynamic);103  if (op.getSizes().size() != numDynamicDims) {104    return op->emitError("expected the number of 'sizes' to match the number "105                         "of dynamic entries in 'static_sizes' (")106           << op.getSizes().size() << " vs " << numDynamicDims << ")";107  }108  size_t numDynamicStrides =109      llvm::count_if(op.getStaticStrides(), ShapedType::isDynamic);110  if (op.getStrides().size() != numDynamicStrides) {111    return op->emitError("expected the number of 'strides' to match the number "112                         "of dynamic entries in 'static_strides' (")113           << op.getStrides().size() << " vs " << numDynamicStrides << ")";114  }115  size_t numDynamicOffsets =116      llvm::count_if(op.getStaticOffsets(), ShapedType::isDynamic);117  if (op.getOffsets().size() != numDynamicOffsets) {118    return op->emitError("expected the number of 'offsets' to match the number "119                         "of dynamic entries in 'static_offsets' (")120           << op.getOffsets().size() << " vs " << numDynamicOffsets << ")";121  }122 123  std::array<unsigned, 3> maxRanks = op.getArrayAttrMaxRanks();124  // Offsets can come in 2 flavors:125  //   1. Either single entry (when maxRanks == 1).126  //   2. Or as an array whose rank must match that of the mixed sizes.127  // So that the result type is well-formed.128  if (!(op.getMixedOffsets().size() == 1 && maxRanks[0] == 1) && // NOLINT129      op.getMixedOffsets().size() != op.getMixedSizes().size())130    return op->emitError(131               "expected mixed offsets rank to match mixed sizes rank (")132           << op.getMixedOffsets().size() << " vs " << op.getMixedSizes().size()133           << ") so the rank of the result type is well-formed.";134  // Ranks of mixed sizes and strides must always match so the result type is135  // well-formed.136  if (op.getMixedSizes().size() != op.getMixedStrides().size())137    return op->emitError(138               "expected mixed sizes rank to match mixed strides rank (")139           << op.getMixedSizes().size() << " vs " << op.getMixedStrides().size()140           << ") so the rank of the result type is well-formed.";141 142  if (failed(verifyListOfOperandsOrIntegers(143          op, "offset", maxRanks[0], op.getStaticOffsets(), op.getOffsets())))144    return failure();145  if (failed(verifyListOfOperandsOrIntegers(146          op, "size", maxRanks[1], op.getStaticSizes(), op.getSizes())))147    return failure();148  if (failed(verifyListOfOperandsOrIntegers(149          op, "stride", maxRanks[2], op.getStaticStrides(), op.getStrides())))150    return failure();151 152  for (int64_t offset : op.getStaticOffsets()) {153    if (offset < 0 && ShapedType::isStatic(offset))154      return op->emitError("expected offsets to be non-negative, but got ")155             << offset;156  }157  for (int64_t size : op.getStaticSizes()) {158    if (size < 0 && ShapedType::isStatic(size))159      return op->emitError("expected sizes to be non-negative, but got ")160             << size;161  }162  return success();163}164 165static char getLeftDelimiter(AsmParser::Delimiter delimiter) {166  switch (delimiter) {167  case AsmParser::Delimiter::Paren:168    return '(';169  case AsmParser::Delimiter::LessGreater:170    return '<';171  case AsmParser::Delimiter::Square:172    return '[';173  case AsmParser::Delimiter::Braces:174    return '{';175  default:176    llvm_unreachable("unsupported delimiter");177  }178}179 180static char getRightDelimiter(AsmParser::Delimiter delimiter) {181  switch (delimiter) {182  case AsmParser::Delimiter::Paren:183    return ')';184  case AsmParser::Delimiter::LessGreater:185    return '>';186  case AsmParser::Delimiter::Square:187    return ']';188  case AsmParser::Delimiter::Braces:189    return '}';190  default:191    llvm_unreachable("unsupported delimiter");192  }193}194 195void mlir::printDynamicIndexList(OpAsmPrinter &printer, Operation *op,196                                 OperandRange values,197                                 ArrayRef<int64_t> integers,198                                 ArrayRef<bool> scalableFlags,199                                 TypeRange valueTypes,200                                 AsmParser::Delimiter delimiter) {201  char leftDelimiter = getLeftDelimiter(delimiter);202  char rightDelimiter = getRightDelimiter(delimiter);203  printer << leftDelimiter;204  if (integers.empty()) {205    printer << rightDelimiter;206    return;207  }208 209  unsigned dynamicValIdx = 0;210  unsigned scalableIndexIdx = 0;211  llvm::interleaveComma(integers, printer, [&](int64_t integer) {212    if (!scalableFlags.empty() && scalableFlags[scalableIndexIdx])213      printer << "[";214    if (ShapedType::isDynamic(integer)) {215      printer << values[dynamicValIdx];216      if (!valueTypes.empty())217        printer << " : " << valueTypes[dynamicValIdx];218      ++dynamicValIdx;219    } else {220      printer << integer;221    }222    if (!scalableFlags.empty() && scalableFlags[scalableIndexIdx])223      printer << "]";224 225    scalableIndexIdx++;226  });227 228  printer << rightDelimiter;229}230 231ParseResult mlir::parseDynamicIndexList(232    OpAsmParser &parser,233    SmallVectorImpl<OpAsmParser::UnresolvedOperand> &values,234    DenseI64ArrayAttr &integers, DenseBoolArrayAttr &scalableFlags,235    SmallVectorImpl<Type> *valueTypes, AsmParser::Delimiter delimiter) {236 237  SmallVector<int64_t, 4> integerVals;238  SmallVector<bool, 4> scalableVals;239  auto parseIntegerOrValue = [&]() {240    OpAsmParser::UnresolvedOperand operand;241    auto res = parser.parseOptionalOperand(operand);242 243    // When encountering `[`, assume that this is a scalable index.244    scalableVals.push_back(parser.parseOptionalLSquare().succeeded());245 246    if (res.has_value() && succeeded(res.value())) {247      values.push_back(operand);248      integerVals.push_back(ShapedType::kDynamic);249      if (valueTypes && parser.parseColonType(valueTypes->emplace_back()))250        return failure();251    } else {252      int64_t integer;253      if (failed(parser.parseInteger(integer)))254        return failure();255      integerVals.push_back(integer);256    }257 258    // If this is assumed to be a scalable index, verify that there's a closing259    // `]`.260    if (scalableVals.back() && parser.parseOptionalRSquare().failed())261      return failure();262    return success();263  };264  if (parser.parseCommaSeparatedList(delimiter, parseIntegerOrValue,265                                     " in dynamic index list"))266    return parser.emitError(parser.getNameLoc())267           << "expected SSA value or integer";268  integers = parser.getBuilder().getDenseI64ArrayAttr(integerVals);269  scalableFlags = parser.getBuilder().getDenseBoolArrayAttr(scalableVals);270  return success();271}272 273bool mlir::detail::sameOffsetsSizesAndStrides(274    OffsetSizeAndStrideOpInterface a, OffsetSizeAndStrideOpInterface b,275    llvm::function_ref<bool(OpFoldResult, OpFoldResult)> cmp) {276  if (a.getStaticOffsets().size() != b.getStaticOffsets().size())277    return false;278  if (a.getStaticSizes().size() != b.getStaticSizes().size())279    return false;280  if (a.getStaticStrides().size() != b.getStaticStrides().size())281    return false;282  for (auto it : llvm::zip(a.getMixedOffsets(), b.getMixedOffsets()))283    if (!cmp(std::get<0>(it), std::get<1>(it)))284      return false;285  for (auto it : llvm::zip(a.getMixedSizes(), b.getMixedSizes()))286    if (!cmp(std::get<0>(it), std::get<1>(it)))287      return false;288  for (auto it : llvm::zip(a.getMixedStrides(), b.getMixedStrides()))289    if (!cmp(std::get<0>(it), std::get<1>(it)))290      return false;291  return true;292}293 294unsigned mlir::detail::getNumDynamicEntriesUpToIdx(ArrayRef<int64_t> staticVals,295                                                   unsigned idx) {296  return std::count_if(staticVals.begin(), staticVals.begin() + idx,297                       ShapedType::isDynamic);298}299