brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.3 KiB · 70f7b88 Raw
496 lines · cpp
1//===-- WebAssemblyTargetTransformInfo.cpp - WebAssembly-specific TTI -----===//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/// \file10/// This file defines the WebAssembly-specific TargetTransformInfo11/// implementation.12///13//===----------------------------------------------------------------------===//14 15#include "WebAssemblyTargetTransformInfo.h"16 17#include "llvm/CodeGen/CostTable.h"18using namespace llvm;19 20#define DEBUG_TYPE "wasmtti"21 22TargetTransformInfo::PopcntSupportKind23WebAssemblyTTIImpl::getPopcntSupport(unsigned TyWidth) const {24  assert(isPowerOf2_32(TyWidth) && "Ty width must be power of 2");25  return TargetTransformInfo::PSK_FastHardware;26}27 28unsigned WebAssemblyTTIImpl::getNumberOfRegisters(unsigned ClassID) const {29  unsigned Result = BaseT::getNumberOfRegisters(ClassID);30 31  // For SIMD, use at least 16 registers, as a rough guess.32  bool Vector = (ClassID == 1);33  if (Vector)34    Result = std::max(Result, 16u);35 36  return Result;37}38 39TypeSize WebAssemblyTTIImpl::getRegisterBitWidth(40    TargetTransformInfo::RegisterKind K) const {41  switch (K) {42  case TargetTransformInfo::RGK_Scalar:43    return TypeSize::getFixed(64);44  case TargetTransformInfo::RGK_FixedWidthVector:45    return TypeSize::getFixed(getST()->hasSIMD128() ? 128 : 64);46  case TargetTransformInfo::RGK_ScalableVector:47    return TypeSize::getScalable(0);48  }49 50  llvm_unreachable("Unsupported register kind");51}52 53InstructionCost WebAssemblyTTIImpl::getArithmeticInstrCost(54    unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind,55    TTI::OperandValueInfo Op1Info, TTI::OperandValueInfo Op2Info,56    ArrayRef<const Value *> Args, const Instruction *CxtI) const {57 58  InstructionCost Cost =59      BasicTTIImplBase<WebAssemblyTTIImpl>::getArithmeticInstrCost(60          Opcode, Ty, CostKind, Op1Info, Op2Info);61 62  if (auto *VTy = dyn_cast<VectorType>(Ty)) {63    switch (Opcode) {64    case Instruction::LShr:65    case Instruction::AShr:66    case Instruction::Shl:67      // SIMD128's shifts currently only accept a scalar shift count. For each68      // element, we'll need to extract, op, insert. The following is a rough69      // approximation.70      if (!Op2Info.isUniform())71        Cost =72            cast<FixedVectorType>(VTy)->getNumElements() *73            (TargetTransformInfo::TCC_Basic +74             getArithmeticInstrCost(Opcode, VTy->getElementType(), CostKind) +75             TargetTransformInfo::TCC_Basic);76      break;77    }78  }79  return Cost;80}81 82InstructionCost WebAssemblyTTIImpl::getCastInstrCost(83    unsigned Opcode, Type *Dst, Type *Src, TTI::CastContextHint CCH,84    TTI::TargetCostKind CostKind, const Instruction *I) const {85  int ISD = TLI->InstructionOpcodeToISD(Opcode);86  auto SrcTy = TLI->getValueType(DL, Src);87  auto DstTy = TLI->getValueType(DL, Dst);88 89  if (!SrcTy.isSimple() || !DstTy.isSimple()) {90    return BaseT::getCastInstrCost(Opcode, Dst, Src, CCH, CostKind, I);91  }92 93  if (!ST->hasSIMD128()) {94    return BaseT::getCastInstrCost(Opcode, Dst, Src, CCH, CostKind, I);95  }96 97  auto DstVT = DstTy.getSimpleVT();98  auto SrcVT = SrcTy.getSimpleVT();99 100  if (I && I->hasOneUser()) {101    auto *SingleUser = cast<Instruction>(*I->user_begin());102    int UserISD = TLI->InstructionOpcodeToISD(SingleUser->getOpcode());103 104    // extmul_low support105    if (UserISD == ISD::MUL &&106        (ISD == ISD::ZERO_EXTEND || ISD == ISD::SIGN_EXTEND)) {107      // Free low extensions.108      if ((SrcVT == MVT::v8i8 && DstVT == MVT::v8i16) ||109          (SrcVT == MVT::v4i16 && DstVT == MVT::v4i32) ||110          (SrcVT == MVT::v2i32 && DstVT == MVT::v2i64)) {111        return 0;112      }113      // Will require an additional extlow operation for the intermediate114      // i16/i32 value.115      if ((SrcVT == MVT::v4i8 && DstVT == MVT::v4i32) ||116          (SrcVT == MVT::v2i16 && DstVT == MVT::v2i64)) {117        return 1;118      }119    }120  }121 122  static constexpr TypeConversionCostTblEntry ConversionTbl[] = {123      // extend_low124      {ISD::SIGN_EXTEND, MVT::v2i64, MVT::v2i32, 1},125      {ISD::ZERO_EXTEND, MVT::v2i64, MVT::v2i32, 1},126      {ISD::SIGN_EXTEND, MVT::v4i32, MVT::v4i16, 1},127      {ISD::ZERO_EXTEND, MVT::v4i32, MVT::v4i16, 1},128      {ISD::SIGN_EXTEND, MVT::v8i16, MVT::v8i8, 1},129      {ISD::ZERO_EXTEND, MVT::v8i16, MVT::v8i8, 1},130      // 2 x extend_low131      {ISD::SIGN_EXTEND, MVT::v2i64, MVT::v2i16, 2},132      {ISD::ZERO_EXTEND, MVT::v2i64, MVT::v2i16, 2},133      {ISD::SIGN_EXTEND, MVT::v4i32, MVT::v4i8, 2},134      {ISD::ZERO_EXTEND, MVT::v4i32, MVT::v4i8, 2},135      // extend_low, extend_high136      {ISD::SIGN_EXTEND, MVT::v4i64, MVT::v4i32, 2},137      {ISD::ZERO_EXTEND, MVT::v4i64, MVT::v4i32, 2},138      {ISD::SIGN_EXTEND, MVT::v8i32, MVT::v8i16, 2},139      {ISD::ZERO_EXTEND, MVT::v8i32, MVT::v8i16, 2},140      {ISD::SIGN_EXTEND, MVT::v16i16, MVT::v16i8, 2},141      {ISD::ZERO_EXTEND, MVT::v16i16, MVT::v16i8, 2},142      // 2x extend_low, extend_high143      {ISD::SIGN_EXTEND, MVT::v8i64, MVT::v8i32, 4},144      {ISD::ZERO_EXTEND, MVT::v8i64, MVT::v8i32, 4},145      {ISD::SIGN_EXTEND, MVT::v16i32, MVT::v16i16, 4},146      {ISD::ZERO_EXTEND, MVT::v16i32, MVT::v16i16, 4},147      // shuffle148      {ISD::TRUNCATE, MVT::v2i16, MVT::v2i32, 2},149      {ISD::TRUNCATE, MVT::v2i8, MVT::v2i32, 4},150      {ISD::TRUNCATE, MVT::v4i16, MVT::v4i32, 2},151      {ISD::TRUNCATE, MVT::v4i8, MVT::v4i32, 4},152      // narrow, and153      {ISD::TRUNCATE, MVT::v8i16, MVT::v8i32, 2},154      {ISD::TRUNCATE, MVT::v8i8, MVT::v8i16, 2},155      // narrow, 2x and156      {ISD::TRUNCATE, MVT::v16i8, MVT::v16i16, 3},157      // 3x narrow, 4x and158      {ISD::TRUNCATE, MVT::v8i16, MVT::v8i64, 7},159      {ISD::TRUNCATE, MVT::v16i8, MVT::v16i32, 7},160      // 7x narrow, 8x and161      {ISD::TRUNCATE, MVT::v16i8, MVT::v16i64, 15},162      // convert_i32x4163      {ISD::SINT_TO_FP, MVT::v2f32, MVT::v2i32, 1},164      {ISD::UINT_TO_FP, MVT::v2f32, MVT::v2i32, 1},165      {ISD::SINT_TO_FP, MVT::v4f32, MVT::v4i32, 1},166      {ISD::UINT_TO_FP, MVT::v4f32, MVT::v4i32, 1},167      // extend_low, convert168      {ISD::SINT_TO_FP, MVT::v2f32, MVT::v2i16, 2},169      {ISD::UINT_TO_FP, MVT::v2f32, MVT::v2i16, 2},170      {ISD::SINT_TO_FP, MVT::v4f32, MVT::v4i16, 2},171      {ISD::UINT_TO_FP, MVT::v4f32, MVT::v4i16, 2},172      // extend_low x 2, convert173      {ISD::SINT_TO_FP, MVT::v2f32, MVT::v2i8, 3},174      {ISD::UINT_TO_FP, MVT::v2f32, MVT::v2i8, 3},175      {ISD::SINT_TO_FP, MVT::v4f32, MVT::v4i8, 3},176      {ISD::UINT_TO_FP, MVT::v4f32, MVT::v4i8, 3},177      // several shuffles178      {ISD::SINT_TO_FP, MVT::v8f32, MVT::v8i8, 10},179      {ISD::UINT_TO_FP, MVT::v8f32, MVT::v8i8, 10},180      {ISD::SINT_TO_FP, MVT::v8f32, MVT::v8i16, 10},181      {ISD::UINT_TO_FP, MVT::v8f32, MVT::v8i8, 10},182      /// trunc_sat, const, and, 3x narrow183      {ISD::FP_TO_SINT, MVT::v2i8, MVT::v2f32, 6},184      {ISD::FP_TO_UINT, MVT::v2i8, MVT::v2f32, 6},185      {ISD::FP_TO_SINT, MVT::v4i8, MVT::v4f32, 6},186      {ISD::FP_TO_UINT, MVT::v4i8, MVT::v4f32, 6},187      /// trunc_sat, const, and, narrow188      {ISD::FP_TO_UINT, MVT::v2i16, MVT::v2f32, 4},189      {ISD::FP_TO_SINT, MVT::v2i16, MVT::v2f32, 4},190      {ISD::FP_TO_SINT, MVT::v4i16, MVT::v4f32, 4},191      {ISD::FP_TO_UINT, MVT::v4i16, MVT::v4f32, 4},192      // 2x trunc_sat, const, 2x and, 3x narrow193      {ISD::FP_TO_SINT, MVT::v8i8, MVT::v8f32, 8},194      {ISD::FP_TO_UINT, MVT::v8i8, MVT::v8f32, 8},195      // 2x trunc_sat, const, 2x and, narrow196      {ISD::FP_TO_SINT, MVT::v8i16, MVT::v8f32, 6},197      {ISD::FP_TO_UINT, MVT::v8i16, MVT::v8f32, 6},198  };199 200  if (const auto *Entry =201          ConvertCostTableLookup(ConversionTbl, ISD, DstVT, SrcVT)) {202    return Entry->Cost;203  }204 205  return BaseT::getCastInstrCost(Opcode, Dst, Src, CCH, CostKind, I);206}207 208WebAssemblyTTIImpl::TTI::MemCmpExpansionOptions209WebAssemblyTTIImpl::enableMemCmpExpansion(bool OptSize, bool IsZeroCmp) const {210  TTI::MemCmpExpansionOptions Options;211 212  Options.AllowOverlappingLoads = true;213 214  if (ST->hasSIMD128())215    Options.LoadSizes.push_back(16);216 217  Options.LoadSizes.append({8, 4, 2, 1});218  Options.MaxNumLoads = TLI->getMaxExpandSizeMemcmp(OptSize);219  Options.NumLoadsPerBlock = Options.MaxNumLoads;220 221  return Options;222}223 224InstructionCost WebAssemblyTTIImpl::getMemoryOpCost(225    unsigned Opcode, Type *Ty, Align Alignment, unsigned AddressSpace,226    TTI::TargetCostKind CostKind, TTI::OperandValueInfo OpInfo,227    const Instruction *I) const {228  if (!ST->hasSIMD128() || !isa<FixedVectorType>(Ty)) {229    return BaseT::getMemoryOpCost(Opcode, Ty, Alignment, AddressSpace,230                                  CostKind);231  }232 233  EVT VT = TLI->getValueType(DL, Ty, true);234  // Type legalization can't handle structs235  if (VT == MVT::Other)236    return BaseT::getMemoryOpCost(Opcode, Ty, Alignment, AddressSpace,237                                  CostKind);238 239  auto LT = getTypeLegalizationCost(Ty);240  if (!LT.first.isValid())241    return InstructionCost::getInvalid();242 243  int ISD = TLI->InstructionOpcodeToISD(Opcode);244  unsigned width = VT.getSizeInBits();245  if (ISD == ISD::LOAD) {246    // 128-bit loads are a single instruction. 32-bit and 64-bit vector loads247    // can be lowered to load32_zero and load64_zero respectively. Assume SIMD248    // loads are twice as expensive as scalar.249    switch (width) {250    default:251      break;252    case 32:253    case 64:254    case 128:255      return 2;256    }257  } else if (ISD == ISD::STORE) {258    // For stores, we can use store lane operations.259    switch (width) {260    default:261      break;262    case 8:263    case 16:264    case 32:265    case 64:266    case 128:267      return 2;268    }269  }270 271  return BaseT::getMemoryOpCost(Opcode, Ty, Alignment, AddressSpace, CostKind);272}273 274InstructionCost WebAssemblyTTIImpl::getInterleavedMemoryOpCost(275    unsigned Opcode, Type *Ty, unsigned Factor, ArrayRef<unsigned> Indices,276    Align Alignment, unsigned AddressSpace, TTI::TargetCostKind CostKind,277    bool UseMaskForCond, bool UseMaskForGaps) const {278  assert(Factor >= 2 && "Invalid interleave factor");279 280  auto *VecTy = cast<VectorType>(Ty);281  if (!ST->hasSIMD128() || !isa<FixedVectorType>(VecTy)) {282    return InstructionCost::getInvalid();283  }284 285  if (UseMaskForCond || UseMaskForGaps)286    return BaseT::getInterleavedMemoryOpCost(Opcode, Ty, Factor, Indices,287                                             Alignment, AddressSpace, CostKind,288                                             UseMaskForCond, UseMaskForGaps);289 290  constexpr unsigned MaxInterleaveFactor = 4;291  if (Factor <= MaxInterleaveFactor) {292    unsigned MinElts = VecTy->getElementCount().getKnownMinValue();293    // Ensure the number of vector elements is greater than 1.294    if (MinElts < 2 || MinElts % Factor != 0)295      return InstructionCost::getInvalid();296 297    unsigned ElSize = DL.getTypeSizeInBits(VecTy->getElementType());298    // Ensure the element type is legal.299    if (ElSize != 8 && ElSize != 16 && ElSize != 32 && ElSize != 64)300      return InstructionCost::getInvalid();301 302    auto *SubVecTy =303        VectorType::get(VecTy->getElementType(),304                        VecTy->getElementCount().divideCoefficientBy(Factor));305    InstructionCost MemCost =306        getMemoryOpCost(Opcode, SubVecTy, Alignment, AddressSpace, CostKind);307 308    unsigned VecSize = DL.getTypeSizeInBits(SubVecTy);309    unsigned MaxVecSize = 128;310    unsigned NumAccesses =311        std::max<unsigned>(1, (MinElts * ElSize + MaxVecSize - 1) / VecSize);312 313    // A stride of two is commonly supported via dedicated instructions, so it314    // should be relatively cheap for all element sizes. A stride of four is315    // more expensive as it will likely require more shuffles. Using two316    // simd128 inputs is considered more expensive and we mainly account for317    // shuffling two inputs (32 bytes), but we do model 4 x v4i32 to enable318    // arithmetic kernels.319    static const CostTblEntry ShuffleCostTbl[] = {320        // One reg.321        {2, MVT::v2i8, 1},  // interleave 2 x 2i8 into 4i8322        {2, MVT::v4i8, 1},  // interleave 2 x 4i8 into 8i8323        {2, MVT::v8i8, 1},  // interleave 2 x 8i8 into 16i8324        {2, MVT::v2i16, 1}, // interleave 2 x 2i16 into 4i16325        {2, MVT::v4i16, 1}, // interleave 2 x 4i16 into 8i16326        {2, MVT::v2i32, 1}, // interleave 2 x 2i32 into 4i32327 328        // Two regs.329        {2, MVT::v16i8, 2}, // interleave 2 x 16i8 into 32i8330        {2, MVT::v8i16, 2}, // interleave 2 x 8i16 into 16i16331        {2, MVT::v4i32, 2}, // interleave 2 x 4i32 into 8i32332 333        // One reg.334        {4, MVT::v2i8, 4},  // interleave 4 x 2i8 into 8i8335        {4, MVT::v4i8, 4},  // interleave 4 x 4i8 into 16i8336        {4, MVT::v2i16, 4}, // interleave 4 x 2i16 into 8i16337 338        // Two regs.339        {4, MVT::v8i8, 16}, // interleave 4 x 8i8 into 32i8340        {4, MVT::v4i16, 8}, // interleave 4 x 4i16 into 16i16341        {4, MVT::v2i32, 4}, // interleave 4 x 2i32 into 8i32342 343        // Four regs.344        {4, MVT::v4i32, 16}, // interleave 4 x 4i32 into 16i32345    };346 347    EVT ETy = TLI->getValueType(DL, SubVecTy);348    if (const auto *Entry =349            CostTableLookup(ShuffleCostTbl, Factor, ETy.getSimpleVT()))350      return Entry->Cost + (NumAccesses * MemCost);351  }352 353  return BaseT::getInterleavedMemoryOpCost(Opcode, VecTy, Factor, Indices,354                                           Alignment, AddressSpace, CostKind,355                                           UseMaskForCond, UseMaskForGaps);356}357 358InstructionCost WebAssemblyTTIImpl::getVectorInstrCost(359    unsigned Opcode, Type *Val, TTI::TargetCostKind CostKind, unsigned Index,360    const Value *Op0, const Value *Op1) const {361  InstructionCost Cost = BasicTTIImplBase::getVectorInstrCost(362      Opcode, Val, CostKind, Index, Op0, Op1);363 364  // SIMD128's insert/extract currently only take constant indices.365  if (Index == -1u)366    return Cost + 25 * TargetTransformInfo::TCC_Expensive;367 368  return Cost;369}370 371InstructionCost WebAssemblyTTIImpl::getPartialReductionCost(372    unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType,373    ElementCount VF, TTI::PartialReductionExtendKind OpAExtend,374    TTI::PartialReductionExtendKind OpBExtend, std::optional<unsigned> BinOp,375    TTI::TargetCostKind CostKind) const {376  InstructionCost Invalid = InstructionCost::getInvalid();377  if (!VF.isFixed() || !ST->hasSIMD128())378    return Invalid;379 380  if (CostKind != TTI::TCK_RecipThroughput)381    return Invalid;382 383  if (Opcode != Instruction::Add)384    return Invalid;385 386  EVT AccumEVT = EVT::getEVT(AccumType);387  // TODO: Add i64 accumulator.388  if (AccumEVT != MVT::i32)389    return Invalid;390 391  // Possible options:392  // - i16x8.extadd_pairwise_i8x16_sx393  // - i32x4.extadd_pairwise_i16x8_sx394  // - i32x4.dot_i16x8_s395  // Only try to support dot, for now.396 397  EVT InputEVT = EVT::getEVT(InputTypeA);398  if (!((InputEVT == MVT::i16 && VF.getFixedValue() == 8) ||399        (InputEVT == MVT::i8 && VF.getFixedValue() == 16))) {400    return Invalid;401  }402 403  if (OpAExtend == TTI::PR_None)404    return Invalid;405 406  InstructionCost Cost(TTI::TCC_Basic);407  if (!BinOp)408    return Cost;409 410  if (OpAExtend != OpBExtend)411    return Invalid;412 413  if (*BinOp != Instruction::Mul)414    return Invalid;415 416  if (InputTypeA != InputTypeB)417    return Invalid;418 419  // Signed inputs can lower to dot420  if (InputEVT == MVT::i16 && VF.getFixedValue() == 8)421    return OpAExtend == TTI::PR_SignExtend ? Cost : Cost * 2;422 423  // Double the size of the lowered sequence.424  if (InputEVT == MVT::i8 && VF.getFixedValue() == 16)425    return OpAExtend == TTI::PR_SignExtend ? Cost * 2 : Cost * 4;426 427  return Invalid;428}429 430TTI::ReductionShuffle WebAssemblyTTIImpl::getPreferredExpandedReductionShuffle(431    const IntrinsicInst *II) const {432 433  switch (II->getIntrinsicID()) {434  default:435    break;436  case Intrinsic::vector_reduce_fadd:437    return TTI::ReductionShuffle::Pairwise;438  }439  return TTI::ReductionShuffle::SplitHalf;440}441 442void WebAssemblyTTIImpl::getUnrollingPreferences(443    Loop *L, ScalarEvolution &SE, TTI::UnrollingPreferences &UP,444    OptimizationRemarkEmitter *ORE) const {445  // Scan the loop: don't unroll loops with calls. This is a standard approach446  // for most (all?) targets.447  for (BasicBlock *BB : L->blocks())448    for (Instruction &I : *BB)449      if (isa<CallInst>(I) || isa<InvokeInst>(I))450        if (const Function *F = cast<CallBase>(I).getCalledFunction())451          if (isLoweredToCall(F))452            return;453 454  // The chosen threshold is within the range of 'LoopMicroOpBufferSize' of455  // the various microarchitectures that use the BasicTTI implementation and456  // has been selected through heuristics across multiple cores and runtimes.457  UP.Partial = UP.Runtime = UP.UpperBound = true;458  UP.PartialThreshold = 30;459 460  // Avoid unrolling when optimizing for size.461  UP.OptSizeThreshold = 0;462  UP.PartialOptSizeThreshold = 0;463 464  // Set number of instructions optimized when "back edge"465  // becomes "fall through" to default value of 2.466  UP.BEInsns = 2;467}468 469bool WebAssemblyTTIImpl::supportsTailCalls() const {470  return getST()->hasTailCall();471}472 473bool WebAssemblyTTIImpl::isProfitableToSinkOperands(474    Instruction *I, SmallVectorImpl<Use *> &Ops) const {475  using namespace llvm::PatternMatch;476 477  if (!I->getType()->isVectorTy() || !I->isShift())478    return false;479 480  Value *V = I->getOperand(1);481  // We dont need to sink constant splat.482  if (isa<Constant>(V))483    return false;484 485  if (match(V, m_Shuffle(m_InsertElt(m_Value(), m_Value(), m_ZeroInt()),486                         m_Value(), m_ZeroMask()))) {487    // Sink insert488    Ops.push_back(&cast<Instruction>(V)->getOperandUse(0));489    // Sink shuffle490    Ops.push_back(&I->getOperandUse(1));491    return true;492  }493 494  return false;495}496