brintos

brintos / llvm-project-archived public Read only

0
0
Text · 388.9 KiB · 120c38a Raw
10815 lines · cpp
1//===-- llvm/CodeGen/GlobalISel/LegalizerHelper.cpp -----------------------===//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/// \file This file implements the LegalizerHelper class to legalize10/// individual instructions and the LegalizeMachineIR wrapper pass for the11/// primary legalization.12//13//===----------------------------------------------------------------------===//14 15#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"16#include "llvm/CodeGen/GlobalISel/CallLowering.h"17#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"18#include "llvm/CodeGen/GlobalISel/GISelValueTracking.h"19#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"20#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"21#include "llvm/CodeGen/GlobalISel/LostDebugLocObserver.h"22#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"23#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"24#include "llvm/CodeGen/GlobalISel/Utils.h"25#include "llvm/CodeGen/LowLevelTypeUtils.h"26#include "llvm/CodeGen/MachineConstantPool.h"27#include "llvm/CodeGen/MachineFrameInfo.h"28#include "llvm/CodeGen/MachineRegisterInfo.h"29#include "llvm/CodeGen/RuntimeLibcallUtil.h"30#include "llvm/CodeGen/TargetFrameLowering.h"31#include "llvm/CodeGen/TargetInstrInfo.h"32#include "llvm/CodeGen/TargetLowering.h"33#include "llvm/CodeGen/TargetOpcodes.h"34#include "llvm/CodeGen/TargetSubtargetInfo.h"35#include "llvm/IR/Instructions.h"36#include "llvm/Support/Debug.h"37#include "llvm/Support/MathExtras.h"38#include "llvm/Support/raw_ostream.h"39#include "llvm/Target/TargetMachine.h"40#include <numeric>41#include <optional>42 43#define DEBUG_TYPE "legalizer"44 45using namespace llvm;46using namespace LegalizeActions;47using namespace MIPatternMatch;48 49/// Try to break down \p OrigTy into \p NarrowTy sized pieces.50///51/// Returns the number of \p NarrowTy elements needed to reconstruct \p OrigTy,52/// with any leftover piece as type \p LeftoverTy53///54/// Returns -1 in the first element of the pair if the breakdown is not55/// satisfiable.56static std::pair<int, int>57getNarrowTypeBreakDown(LLT OrigTy, LLT NarrowTy, LLT &LeftoverTy) {58  assert(!LeftoverTy.isValid() && "this is an out argument");59 60  unsigned Size = OrigTy.getSizeInBits();61  unsigned NarrowSize = NarrowTy.getSizeInBits();62  unsigned NumParts = Size / NarrowSize;63  unsigned LeftoverSize = Size - NumParts * NarrowSize;64  assert(Size > NarrowSize);65 66  if (LeftoverSize == 0)67    return {NumParts, 0};68 69  if (NarrowTy.isVector()) {70    unsigned EltSize = OrigTy.getScalarSizeInBits();71    if (LeftoverSize % EltSize != 0)72      return {-1, -1};73    LeftoverTy =74        LLT::scalarOrVector(ElementCount::getFixed(LeftoverSize / EltSize),75                            OrigTy.getElementType());76  } else {77    LeftoverTy = LLT::scalar(LeftoverSize);78  }79 80  int NumLeftover = LeftoverSize / LeftoverTy.getSizeInBits();81  return std::make_pair(NumParts, NumLeftover);82}83 84static Type *getFloatTypeForLLT(LLVMContext &Ctx, LLT Ty) {85 86  if (!Ty.isScalar())87    return nullptr;88 89  switch (Ty.getSizeInBits()) {90  case 16:91    return Type::getHalfTy(Ctx);92  case 32:93    return Type::getFloatTy(Ctx);94  case 64:95    return Type::getDoubleTy(Ctx);96  case 80:97    return Type::getX86_FP80Ty(Ctx);98  case 128:99    return Type::getFP128Ty(Ctx);100  default:101    return nullptr;102  }103}104 105LegalizerHelper::LegalizerHelper(MachineFunction &MF,106                                 GISelChangeObserver &Observer,107                                 MachineIRBuilder &Builder)108    : MIRBuilder(Builder), Observer(Observer), MRI(MF.getRegInfo()),109      LI(*MF.getSubtarget().getLegalizerInfo()),110      TLI(*MF.getSubtarget().getTargetLowering()), VT(nullptr) {}111 112LegalizerHelper::LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI,113                                 GISelChangeObserver &Observer,114                                 MachineIRBuilder &B, GISelValueTracking *VT)115    : MIRBuilder(B), Observer(Observer), MRI(MF.getRegInfo()), LI(LI),116      TLI(*MF.getSubtarget().getTargetLowering()), VT(VT) {}117 118LegalizerHelper::LegalizeResult119LegalizerHelper::legalizeInstrStep(MachineInstr &MI,120                                   LostDebugLocObserver &LocObserver) {121  LLVM_DEBUG(dbgs() << "\nLegalizing: " << MI);122 123  MIRBuilder.setInstrAndDebugLoc(MI);124 125  if (isa<GIntrinsic>(MI))126    return LI.legalizeIntrinsic(*this, MI) ? Legalized : UnableToLegalize;127  auto Step = LI.getAction(MI, MRI);128  switch (Step.Action) {129  case Legal:130    LLVM_DEBUG(dbgs() << ".. Already legal\n");131    return AlreadyLegal;132  case Libcall:133    LLVM_DEBUG(dbgs() << ".. Convert to libcall\n");134    return libcall(MI, LocObserver);135  case NarrowScalar:136    LLVM_DEBUG(dbgs() << ".. Narrow scalar\n");137    return narrowScalar(MI, Step.TypeIdx, Step.NewType);138  case WidenScalar:139    LLVM_DEBUG(dbgs() << ".. Widen scalar\n");140    return widenScalar(MI, Step.TypeIdx, Step.NewType);141  case Bitcast:142    LLVM_DEBUG(dbgs() << ".. Bitcast type\n");143    return bitcast(MI, Step.TypeIdx, Step.NewType);144  case Lower:145    LLVM_DEBUG(dbgs() << ".. Lower\n");146    return lower(MI, Step.TypeIdx, Step.NewType);147  case FewerElements:148    LLVM_DEBUG(dbgs() << ".. Reduce number of elements\n");149    return fewerElementsVector(MI, Step.TypeIdx, Step.NewType);150  case MoreElements:151    LLVM_DEBUG(dbgs() << ".. Increase number of elements\n");152    return moreElementsVector(MI, Step.TypeIdx, Step.NewType);153  case Custom:154    LLVM_DEBUG(dbgs() << ".. Custom legalization\n");155    return LI.legalizeCustom(*this, MI, LocObserver) ? Legalized156                                                     : UnableToLegalize;157  default:158    LLVM_DEBUG(dbgs() << ".. Unable to legalize\n");159    return UnableToLegalize;160  }161}162 163void LegalizerHelper::insertParts(Register DstReg,164                                  LLT ResultTy, LLT PartTy,165                                  ArrayRef<Register> PartRegs,166                                  LLT LeftoverTy,167                                  ArrayRef<Register> LeftoverRegs) {168  if (!LeftoverTy.isValid()) {169    assert(LeftoverRegs.empty());170 171    if (!ResultTy.isVector()) {172      MIRBuilder.buildMergeLikeInstr(DstReg, PartRegs);173      return;174    }175 176    if (PartTy.isVector())177      MIRBuilder.buildConcatVectors(DstReg, PartRegs);178    else179      MIRBuilder.buildBuildVector(DstReg, PartRegs);180    return;181  }182 183  // Merge sub-vectors with different number of elements and insert into DstReg.184  if (ResultTy.isVector()) {185    assert(LeftoverRegs.size() == 1 && "Expected one leftover register");186    SmallVector<Register, 8> AllRegs(PartRegs);187    AllRegs.append(LeftoverRegs.begin(), LeftoverRegs.end());188    return mergeMixedSubvectors(DstReg, AllRegs);189  }190 191  SmallVector<Register> GCDRegs;192  LLT GCDTy = getGCDType(getGCDType(ResultTy, LeftoverTy), PartTy);193  for (auto PartReg : concat<const Register>(PartRegs, LeftoverRegs))194    extractGCDType(GCDRegs, GCDTy, PartReg);195  LLT ResultLCMTy = buildLCMMergePieces(ResultTy, LeftoverTy, GCDTy, GCDRegs);196  buildWidenedRemergeToDst(DstReg, ResultLCMTy, GCDRegs);197}198 199void LegalizerHelper::appendVectorElts(SmallVectorImpl<Register> &Elts,200                                       Register Reg) {201  LLT Ty = MRI.getType(Reg);202  SmallVector<Register, 8> RegElts;203  extractParts(Reg, Ty.getScalarType(), Ty.getNumElements(), RegElts,204               MIRBuilder, MRI);205  Elts.append(RegElts);206}207 208/// Merge \p PartRegs with different types into \p DstReg.209void LegalizerHelper::mergeMixedSubvectors(Register DstReg,210                                           ArrayRef<Register> PartRegs) {211  SmallVector<Register, 8> AllElts;212  for (unsigned i = 0; i < PartRegs.size() - 1; ++i)213    appendVectorElts(AllElts, PartRegs[i]);214 215  Register Leftover = PartRegs[PartRegs.size() - 1];216  if (!MRI.getType(Leftover).isVector())217    AllElts.push_back(Leftover);218  else219    appendVectorElts(AllElts, Leftover);220 221  MIRBuilder.buildMergeLikeInstr(DstReg, AllElts);222}223 224/// Append the result registers of G_UNMERGE_VALUES \p MI to \p Regs.225static void getUnmergeResults(SmallVectorImpl<Register> &Regs,226                              const MachineInstr &MI) {227  assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);228 229  const int StartIdx = Regs.size();230  const int NumResults = MI.getNumOperands() - 1;231  Regs.resize(Regs.size() + NumResults);232  for (int I = 0; I != NumResults; ++I)233    Regs[StartIdx + I] = MI.getOperand(I).getReg();234}235 236void LegalizerHelper::extractGCDType(SmallVectorImpl<Register> &Parts,237                                     LLT GCDTy, Register SrcReg) {238  LLT SrcTy = MRI.getType(SrcReg);239  if (SrcTy == GCDTy) {240    // If the source already evenly divides the result type, we don't need to do241    // anything.242    Parts.push_back(SrcReg);243  } else {244    // Need to split into common type sized pieces.245    auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);246    getUnmergeResults(Parts, *Unmerge);247  }248}249 250LLT LegalizerHelper::extractGCDType(SmallVectorImpl<Register> &Parts, LLT DstTy,251                                    LLT NarrowTy, Register SrcReg) {252  LLT SrcTy = MRI.getType(SrcReg);253  LLT GCDTy = getGCDType(getGCDType(SrcTy, NarrowTy), DstTy);254  extractGCDType(Parts, GCDTy, SrcReg);255  return GCDTy;256}257 258LLT LegalizerHelper::buildLCMMergePieces(LLT DstTy, LLT NarrowTy, LLT GCDTy,259                                         SmallVectorImpl<Register> &VRegs,260                                         unsigned PadStrategy) {261  LLT LCMTy = getLCMType(DstTy, NarrowTy);262 263  int NumParts = LCMTy.getSizeInBits() / NarrowTy.getSizeInBits();264  int NumSubParts = NarrowTy.getSizeInBits() / GCDTy.getSizeInBits();265  int NumOrigSrc = VRegs.size();266 267  Register PadReg;268 269  // Get a value we can use to pad the source value if the sources won't evenly270  // cover the result type.271  if (NumOrigSrc < NumParts * NumSubParts) {272    if (PadStrategy == TargetOpcode::G_ZEXT)273      PadReg = MIRBuilder.buildConstant(GCDTy, 0).getReg(0);274    else if (PadStrategy == TargetOpcode::G_ANYEXT)275      PadReg = MIRBuilder.buildUndef(GCDTy).getReg(0);276    else {277      assert(PadStrategy == TargetOpcode::G_SEXT);278 279      // Shift the sign bit of the low register through the high register.280      auto ShiftAmt =281        MIRBuilder.buildConstant(LLT::scalar(64), GCDTy.getSizeInBits() - 1);282      PadReg = MIRBuilder.buildAShr(GCDTy, VRegs.back(), ShiftAmt).getReg(0);283    }284  }285 286  // Registers for the final merge to be produced.287  SmallVector<Register, 4> Remerge(NumParts);288 289  // Registers needed for intermediate merges, which will be merged into a290  // source for Remerge.291  SmallVector<Register, 4> SubMerge(NumSubParts);292 293  // Once we've fully read off the end of the original source bits, we can reuse294  // the same high bits for remaining padding elements.295  Register AllPadReg;296 297  // Build merges to the LCM type to cover the original result type.298  for (int I = 0; I != NumParts; ++I) {299    bool AllMergePartsArePadding = true;300 301    // Build the requested merges to the requested type.302    for (int J = 0; J != NumSubParts; ++J) {303      int Idx = I * NumSubParts + J;304      if (Idx >= NumOrigSrc) {305        SubMerge[J] = PadReg;306        continue;307      }308 309      SubMerge[J] = VRegs[Idx];310 311      // There are meaningful bits here we can't reuse later.312      AllMergePartsArePadding = false;313    }314 315    // If we've filled up a complete piece with padding bits, we can directly316    // emit the natural sized constant if applicable, rather than a merge of317    // smaller constants.318    if (AllMergePartsArePadding && !AllPadReg) {319      if (PadStrategy == TargetOpcode::G_ANYEXT)320        AllPadReg = MIRBuilder.buildUndef(NarrowTy).getReg(0);321      else if (PadStrategy == TargetOpcode::G_ZEXT)322        AllPadReg = MIRBuilder.buildConstant(NarrowTy, 0).getReg(0);323 324      // If this is a sign extension, we can't materialize a trivial constant325      // with the right type and have to produce a merge.326    }327 328    if (AllPadReg) {329      // Avoid creating additional instructions if we're just adding additional330      // copies of padding bits.331      Remerge[I] = AllPadReg;332      continue;333    }334 335    if (NumSubParts == 1)336      Remerge[I] = SubMerge[0];337    else338      Remerge[I] = MIRBuilder.buildMergeLikeInstr(NarrowTy, SubMerge).getReg(0);339 340    // In the sign extend padding case, re-use the first all-signbit merge.341    if (AllMergePartsArePadding && !AllPadReg)342      AllPadReg = Remerge[I];343  }344 345  VRegs = std::move(Remerge);346  return LCMTy;347}348 349void LegalizerHelper::buildWidenedRemergeToDst(Register DstReg, LLT LCMTy,350                                               ArrayRef<Register> RemergeRegs) {351  LLT DstTy = MRI.getType(DstReg);352 353  // Create the merge to the widened source, and extract the relevant bits into354  // the result.355 356  if (DstTy == LCMTy) {357    MIRBuilder.buildMergeLikeInstr(DstReg, RemergeRegs);358    return;359  }360 361  auto Remerge = MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs);362  if (DstTy.isScalar() && LCMTy.isScalar()) {363    MIRBuilder.buildTrunc(DstReg, Remerge);364    return;365  }366 367  if (LCMTy.isVector()) {368    unsigned NumDefs = LCMTy.getSizeInBits() / DstTy.getSizeInBits();369    SmallVector<Register, 8> UnmergeDefs(NumDefs);370    UnmergeDefs[0] = DstReg;371    for (unsigned I = 1; I != NumDefs; ++I)372      UnmergeDefs[I] = MRI.createGenericVirtualRegister(DstTy);373 374    MIRBuilder.buildUnmerge(UnmergeDefs,375                            MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs));376    return;377  }378 379  llvm_unreachable("unhandled case");380}381 382static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {383#define RTLIBCASE_INT(LibcallPrefix)                                           \384  do {                                                                         \385    switch (Size) {                                                            \386    case 32:                                                                   \387      return RTLIB::LibcallPrefix##32;                                         \388    case 64:                                                                   \389      return RTLIB::LibcallPrefix##64;                                         \390    case 128:                                                                  \391      return RTLIB::LibcallPrefix##128;                                        \392    default:                                                                   \393      llvm_unreachable("unexpected size");                                     \394    }                                                                          \395  } while (0)396 397#define RTLIBCASE(LibcallPrefix)                                               \398  do {                                                                         \399    switch (Size) {                                                            \400    case 32:                                                                   \401      return RTLIB::LibcallPrefix##32;                                         \402    case 64:                                                                   \403      return RTLIB::LibcallPrefix##64;                                         \404    case 80:                                                                   \405      return RTLIB::LibcallPrefix##80;                                         \406    case 128:                                                                  \407      return RTLIB::LibcallPrefix##128;                                        \408    default:                                                                   \409      llvm_unreachable("unexpected size");                                     \410    }                                                                          \411  } while (0)412 413  switch (Opcode) {414  case TargetOpcode::G_LROUND:415    RTLIBCASE(LROUND_F);416  case TargetOpcode::G_LLROUND:417    RTLIBCASE(LLROUND_F);418  case TargetOpcode::G_MUL:419    RTLIBCASE_INT(MUL_I);420  case TargetOpcode::G_SDIV:421    RTLIBCASE_INT(SDIV_I);422  case TargetOpcode::G_UDIV:423    RTLIBCASE_INT(UDIV_I);424  case TargetOpcode::G_SREM:425    RTLIBCASE_INT(SREM_I);426  case TargetOpcode::G_UREM:427    RTLIBCASE_INT(UREM_I);428  case TargetOpcode::G_CTLZ_ZERO_UNDEF:429    RTLIBCASE_INT(CTLZ_I);430  case TargetOpcode::G_FADD:431    RTLIBCASE(ADD_F);432  case TargetOpcode::G_FSUB:433    RTLIBCASE(SUB_F);434  case TargetOpcode::G_FMUL:435    RTLIBCASE(MUL_F);436  case TargetOpcode::G_FDIV:437    RTLIBCASE(DIV_F);438  case TargetOpcode::G_FEXP:439    RTLIBCASE(EXP_F);440  case TargetOpcode::G_FEXP2:441    RTLIBCASE(EXP2_F);442  case TargetOpcode::G_FEXP10:443    RTLIBCASE(EXP10_F);444  case TargetOpcode::G_FREM:445    RTLIBCASE(REM_F);446  case TargetOpcode::G_FPOW:447    RTLIBCASE(POW_F);448  case TargetOpcode::G_FPOWI:449    RTLIBCASE(POWI_F);450  case TargetOpcode::G_FMA:451    RTLIBCASE(FMA_F);452  case TargetOpcode::G_FSIN:453    RTLIBCASE(SIN_F);454  case TargetOpcode::G_FCOS:455    RTLIBCASE(COS_F);456  case TargetOpcode::G_FTAN:457    RTLIBCASE(TAN_F);458  case TargetOpcode::G_FASIN:459    RTLIBCASE(ASIN_F);460  case TargetOpcode::G_FACOS:461    RTLIBCASE(ACOS_F);462  case TargetOpcode::G_FATAN:463    RTLIBCASE(ATAN_F);464  case TargetOpcode::G_FATAN2:465    RTLIBCASE(ATAN2_F);466  case TargetOpcode::G_FSINH:467    RTLIBCASE(SINH_F);468  case TargetOpcode::G_FCOSH:469    RTLIBCASE(COSH_F);470  case TargetOpcode::G_FTANH:471    RTLIBCASE(TANH_F);472  case TargetOpcode::G_FSINCOS:473    RTLIBCASE(SINCOS_F);474  case TargetOpcode::G_FMODF:475    RTLIBCASE(MODF_F);476  case TargetOpcode::G_FLOG10:477    RTLIBCASE(LOG10_F);478  case TargetOpcode::G_FLOG:479    RTLIBCASE(LOG_F);480  case TargetOpcode::G_FLOG2:481    RTLIBCASE(LOG2_F);482  case TargetOpcode::G_FLDEXP:483    RTLIBCASE(LDEXP_F);484  case TargetOpcode::G_FCEIL:485    RTLIBCASE(CEIL_F);486  case TargetOpcode::G_FFLOOR:487    RTLIBCASE(FLOOR_F);488  case TargetOpcode::G_FMINNUM:489    RTLIBCASE(FMIN_F);490  case TargetOpcode::G_FMAXNUM:491    RTLIBCASE(FMAX_F);492  case TargetOpcode::G_FMINIMUMNUM:493    RTLIBCASE(FMINIMUM_NUM_F);494  case TargetOpcode::G_FMAXIMUMNUM:495    RTLIBCASE(FMAXIMUM_NUM_F);496  case TargetOpcode::G_FSQRT:497    RTLIBCASE(SQRT_F);498  case TargetOpcode::G_FRINT:499    RTLIBCASE(RINT_F);500  case TargetOpcode::G_FNEARBYINT:501    RTLIBCASE(NEARBYINT_F);502  case TargetOpcode::G_INTRINSIC_TRUNC:503    RTLIBCASE(TRUNC_F);504  case TargetOpcode::G_INTRINSIC_ROUND:505    RTLIBCASE(ROUND_F);506  case TargetOpcode::G_INTRINSIC_ROUNDEVEN:507    RTLIBCASE(ROUNDEVEN_F);508  case TargetOpcode::G_INTRINSIC_LRINT:509    RTLIBCASE(LRINT_F);510  case TargetOpcode::G_INTRINSIC_LLRINT:511    RTLIBCASE(LLRINT_F);512  }513  llvm_unreachable("Unknown libcall function");514#undef RTLIBCASE_INT515#undef RTLIBCASE516}517 518/// True if an instruction is in tail position in its caller. Intended for519/// legalizing libcalls as tail calls when possible.520static bool isLibCallInTailPosition(const CallLowering::ArgInfo &Result,521                                    MachineInstr &MI,522                                    const TargetInstrInfo &TII,523                                    MachineRegisterInfo &MRI) {524  MachineBasicBlock &MBB = *MI.getParent();525  const Function &F = MBB.getParent()->getFunction();526 527  // Conservatively require the attributes of the call to match those of528  // the return. Ignore NoAlias and NonNull because they don't affect the529  // call sequence.530  AttributeList CallerAttrs = F.getAttributes();531  if (AttrBuilder(F.getContext(), CallerAttrs.getRetAttrs())532          .removeAttribute(Attribute::NoAlias)533          .removeAttribute(Attribute::NonNull)534          .hasAttributes())535    return false;536 537  // It's not safe to eliminate the sign / zero extension of the return value.538  if (CallerAttrs.hasRetAttr(Attribute::ZExt) ||539      CallerAttrs.hasRetAttr(Attribute::SExt))540    return false;541 542  // Only tail call if the following instruction is a standard return or if we543  // have a `thisreturn` callee, and a sequence like:544  //545  //   G_MEMCPY %0, %1, %2546  //   $x0 = COPY %0547  //   RET_ReallyLR implicit $x0548  auto Next = next_nodbg(MI.getIterator(), MBB.instr_end());549  if (Next != MBB.instr_end() && Next->isCopy()) {550    if (MI.getOpcode() == TargetOpcode::G_BZERO)551      return false;552 553    // For MEMCPY/MOMMOVE/MEMSET these will be the first use (the dst), as the554    // mempy/etc routines return the same parameter. For other it will be the555    // returned value.556    Register VReg = MI.getOperand(0).getReg();557    if (!VReg.isVirtual() || VReg != Next->getOperand(1).getReg())558      return false;559 560    Register PReg = Next->getOperand(0).getReg();561    if (!PReg.isPhysical())562      return false;563 564    auto Ret = next_nodbg(Next, MBB.instr_end());565    if (Ret == MBB.instr_end() || !Ret->isReturn())566      return false;567 568    if (Ret->getNumImplicitOperands() != 1)569      return false;570 571    if (!Ret->getOperand(0).isReg() || PReg != Ret->getOperand(0).getReg())572      return false;573 574    // Skip over the COPY that we just validated.575    Next = Ret;576  }577 578  if (Next == MBB.instr_end() || TII.isTailCall(*Next) || !Next->isReturn())579    return false;580 581  return true;582}583 584LegalizerHelper::LegalizeResult585llvm::createLibcall(MachineIRBuilder &MIRBuilder, const char *Name,586                    const CallLowering::ArgInfo &Result,587                    ArrayRef<CallLowering::ArgInfo> Args,588                    const CallingConv::ID CC, LostDebugLocObserver &LocObserver,589                    MachineInstr *MI) {590  auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();591 592  CallLowering::CallLoweringInfo Info;593  Info.CallConv = CC;594  Info.Callee = MachineOperand::CreateES(Name);595  Info.OrigRet = Result;596  if (MI)597    Info.IsTailCall =598        (Result.Ty->isVoidTy() ||599         Result.Ty == MIRBuilder.getMF().getFunction().getReturnType()) &&600        isLibCallInTailPosition(Result, *MI, MIRBuilder.getTII(),601                                *MIRBuilder.getMRI());602 603  llvm::append_range(Info.OrigArgs, Args);604  if (!CLI.lowerCall(MIRBuilder, Info))605    return LegalizerHelper::UnableToLegalize;606 607  if (MI && Info.LoweredTailCall) {608    assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");609 610    // Check debug locations before removing the return.611    LocObserver.checkpoint(true);612 613    // We must have a return following the call (or debug insts) to get past614    // isLibCallInTailPosition.615    do {616      MachineInstr *Next = MI->getNextNode();617      assert(Next &&618             (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&619             "Expected instr following MI to be return or debug inst?");620      // We lowered a tail call, so the call is now the return from the block.621      // Delete the old return.622      Next->eraseFromParent();623    } while (MI->getNextNode());624 625    // We expect to lose the debug location from the return.626    LocObserver.checkpoint(false);627  }628  return LegalizerHelper::Legalized;629}630 631LegalizerHelper::LegalizeResult632llvm::createLibcall(MachineIRBuilder &MIRBuilder, RTLIB::Libcall Libcall,633                    const CallLowering::ArgInfo &Result,634                    ArrayRef<CallLowering::ArgInfo> Args,635                    LostDebugLocObserver &LocObserver, MachineInstr *MI) {636  auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();637  const char *Name = TLI.getLibcallName(Libcall);638  if (!Name)639    return LegalizerHelper::UnableToLegalize;640  const CallingConv::ID CC = TLI.getLibcallCallingConv(Libcall);641  return createLibcall(MIRBuilder, Name, Result, Args, CC, LocObserver, MI);642}643 644// Useful for libcalls where all operands have the same type.645static LegalizerHelper::LegalizeResult646simpleLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size,647              Type *OpType, LostDebugLocObserver &LocObserver) {648  auto Libcall = getRTLibDesc(MI.getOpcode(), Size);649 650  // FIXME: What does the original arg index mean here?651  SmallVector<CallLowering::ArgInfo, 3> Args;652  for (const MachineOperand &MO : llvm::drop_begin(MI.operands()))653    Args.push_back({MO.getReg(), OpType, 0});654  return createLibcall(MIRBuilder, Libcall,655                       {MI.getOperand(0).getReg(), OpType, 0}, Args,656                       LocObserver, &MI);657}658 659LegalizerHelper::LegalizeResult LegalizerHelper::emitSincosLibcall(660    MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, Type *OpType,661    LostDebugLocObserver &LocObserver) {662  MachineFunction &MF = *MI.getMF();663  MachineRegisterInfo &MRI = MF.getRegInfo();664 665  Register DstSin = MI.getOperand(0).getReg();666  Register DstCos = MI.getOperand(1).getReg();667  Register Src = MI.getOperand(2).getReg();668  LLT DstTy = MRI.getType(DstSin);669 670  int MemSize = DstTy.getSizeInBytes();671  Align Alignment = getStackTemporaryAlignment(DstTy);672  const DataLayout &DL = MIRBuilder.getDataLayout();673  unsigned AddrSpace = DL.getAllocaAddrSpace();674  MachinePointerInfo PtrInfo;675 676  Register StackPtrSin =677      createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)678          .getReg(0);679  Register StackPtrCos =680      createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)681          .getReg(0);682 683  auto &Ctx = MF.getFunction().getContext();684  auto LibcallResult =685      createLibcall(MIRBuilder, getRTLibDesc(MI.getOpcode(), Size),686                    {{0}, Type::getVoidTy(Ctx), 0},687                    {{Src, OpType, 0},688                     {StackPtrSin, PointerType::get(Ctx, AddrSpace), 1},689                     {StackPtrCos, PointerType::get(Ctx, AddrSpace), 2}},690                    LocObserver, &MI);691 692  if (LibcallResult != LegalizeResult::Legalized)693    return LegalizerHelper::UnableToLegalize;694 695  MachineMemOperand *LoadMMOSin = MF.getMachineMemOperand(696      PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);697  MachineMemOperand *LoadMMOCos = MF.getMachineMemOperand(698      PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);699 700  MIRBuilder.buildLoad(DstSin, StackPtrSin, *LoadMMOSin);701  MIRBuilder.buildLoad(DstCos, StackPtrCos, *LoadMMOCos);702  MI.eraseFromParent();703 704  return LegalizerHelper::Legalized;705}706 707LegalizerHelper::LegalizeResult708LegalizerHelper::emitModfLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder,709                                 unsigned Size, Type *OpType,710                                 LostDebugLocObserver &LocObserver) {711  MachineFunction &MF = MIRBuilder.getMF();712  MachineRegisterInfo &MRI = MF.getRegInfo();713 714  Register DstFrac = MI.getOperand(0).getReg();715  Register DstInt = MI.getOperand(1).getReg();716  Register Src = MI.getOperand(2).getReg();717  LLT DstTy = MRI.getType(DstFrac);718 719  int MemSize = DstTy.getSizeInBytes();720  Align Alignment = getStackTemporaryAlignment(DstTy);721  const DataLayout &DL = MIRBuilder.getDataLayout();722  unsigned AddrSpace = DL.getAllocaAddrSpace();723  MachinePointerInfo PtrInfo;724 725  Register StackPtrInt =726      createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)727          .getReg(0);728 729  auto &Ctx = MF.getFunction().getContext();730  auto LibcallResult = createLibcall(731      MIRBuilder, getRTLibDesc(MI.getOpcode(), Size), {DstFrac, OpType, 0},732      {{Src, OpType, 0}, {StackPtrInt, PointerType::get(Ctx, AddrSpace), 1}},733      LocObserver, &MI);734 735  if (LibcallResult != LegalizeResult::Legalized)736    return LegalizerHelper::UnableToLegalize;737 738  MachineMemOperand *LoadMMOInt = MF.getMachineMemOperand(739      PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);740 741  MIRBuilder.buildLoad(DstInt, StackPtrInt, *LoadMMOInt);742  MI.eraseFromParent();743 744  return LegalizerHelper::Legalized;745}746 747LegalizerHelper::LegalizeResult748llvm::createMemLibcall(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,749                       MachineInstr &MI, LostDebugLocObserver &LocObserver) {750  auto &Ctx = MIRBuilder.getMF().getFunction().getContext();751 752  SmallVector<CallLowering::ArgInfo, 3> Args;753  // Add all the args, except for the last which is an imm denoting 'tail'.754  for (unsigned i = 0; i < MI.getNumOperands() - 1; ++i) {755    Register Reg = MI.getOperand(i).getReg();756 757    // Need derive an IR type for call lowering.758    LLT OpLLT = MRI.getType(Reg);759    Type *OpTy = nullptr;760    if (OpLLT.isPointer())761      OpTy = PointerType::get(Ctx, OpLLT.getAddressSpace());762    else763      OpTy = IntegerType::get(Ctx, OpLLT.getSizeInBits());764    Args.push_back({Reg, OpTy, 0});765  }766 767  auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();768  auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();769  RTLIB::Libcall RTLibcall;770  unsigned Opc = MI.getOpcode();771  const char *Name;772  switch (Opc) {773  case TargetOpcode::G_BZERO:774    RTLibcall = RTLIB::BZERO;775    Name = TLI.getLibcallName(RTLibcall);776    break;777  case TargetOpcode::G_MEMCPY:778    RTLibcall = RTLIB::MEMCPY;779    Name = TLI.getLibcallImplName(TLI.getMemcpyImpl()).data();780    Args[0].Flags[0].setReturned();781    break;782  case TargetOpcode::G_MEMMOVE:783    RTLibcall = RTLIB::MEMMOVE;784    Name = TLI.getLibcallName(RTLibcall);785    Args[0].Flags[0].setReturned();786    break;787  case TargetOpcode::G_MEMSET:788    RTLibcall = RTLIB::MEMSET;789    Name = TLI.getLibcallName(RTLibcall);790    Args[0].Flags[0].setReturned();791    break;792  default:793    llvm_unreachable("unsupported opcode");794  }795 796  // Unsupported libcall on the target.797  if (!Name) {798    LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "799                      << MIRBuilder.getTII().getName(Opc) << "\n");800    return LegalizerHelper::UnableToLegalize;801  }802 803  CallLowering::CallLoweringInfo Info;804  Info.CallConv = TLI.getLibcallCallingConv(RTLibcall);805  Info.Callee = MachineOperand::CreateES(Name);806  Info.OrigRet = CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0);807  Info.IsTailCall =808      MI.getOperand(MI.getNumOperands() - 1).getImm() &&809      isLibCallInTailPosition(Info.OrigRet, MI, MIRBuilder.getTII(), MRI);810 811  llvm::append_range(Info.OrigArgs, Args);812  if (!CLI.lowerCall(MIRBuilder, Info))813    return LegalizerHelper::UnableToLegalize;814 815  if (Info.LoweredTailCall) {816    assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");817 818    // Check debug locations before removing the return.819    LocObserver.checkpoint(true);820 821    // We must have a return following the call (or debug insts) to get past822    // isLibCallInTailPosition.823    do {824      MachineInstr *Next = MI.getNextNode();825      assert(Next &&826             (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&827             "Expected instr following MI to be return or debug inst?");828      // We lowered a tail call, so the call is now the return from the block.829      // Delete the old return.830      Next->eraseFromParent();831    } while (MI.getNextNode());832 833    // We expect to lose the debug location from the return.834    LocObserver.checkpoint(false);835  }836 837  return LegalizerHelper::Legalized;838}839 840static RTLIB::Libcall getOutlineAtomicLibcall(MachineInstr &MI) {841  unsigned Opc = MI.getOpcode();842  auto &AtomicMI = cast<GMemOperation>(MI);843  auto &MMO = AtomicMI.getMMO();844  auto Ordering = MMO.getMergedOrdering();845  LLT MemType = MMO.getMemoryType();846  uint64_t MemSize = MemType.getSizeInBytes();847  if (MemType.isVector())848    return RTLIB::UNKNOWN_LIBCALL;849 850#define LCALLS(A, B) {A##B##_RELAX, A##B##_ACQ, A##B##_REL, A##B##_ACQ_REL}851#define LCALL5(A)                                                              \852  LCALLS(A, 1), LCALLS(A, 2), LCALLS(A, 4), LCALLS(A, 8), LCALLS(A, 16)853  switch (Opc) {854  case TargetOpcode::G_ATOMIC_CMPXCHG:855  case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {856    const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_CAS)};857    return getOutlineAtomicHelper(LC, Ordering, MemSize);858  }859  case TargetOpcode::G_ATOMICRMW_XCHG: {860    const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_SWP)};861    return getOutlineAtomicHelper(LC, Ordering, MemSize);862  }863  case TargetOpcode::G_ATOMICRMW_ADD:864  case TargetOpcode::G_ATOMICRMW_SUB: {865    const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDADD)};866    return getOutlineAtomicHelper(LC, Ordering, MemSize);867  }868  case TargetOpcode::G_ATOMICRMW_AND: {869    const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDCLR)};870    return getOutlineAtomicHelper(LC, Ordering, MemSize);871  }872  case TargetOpcode::G_ATOMICRMW_OR: {873    const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDSET)};874    return getOutlineAtomicHelper(LC, Ordering, MemSize);875  }876  case TargetOpcode::G_ATOMICRMW_XOR: {877    const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDEOR)};878    return getOutlineAtomicHelper(LC, Ordering, MemSize);879  }880  default:881    return RTLIB::UNKNOWN_LIBCALL;882  }883#undef LCALLS884#undef LCALL5885}886 887static LegalizerHelper::LegalizeResult888createAtomicLibcall(MachineIRBuilder &MIRBuilder, MachineInstr &MI) {889  auto &Ctx = MIRBuilder.getMF().getFunction().getContext();890 891  Type *RetTy;892  SmallVector<Register> RetRegs;893  SmallVector<CallLowering::ArgInfo, 3> Args;894  unsigned Opc = MI.getOpcode();895  switch (Opc) {896  case TargetOpcode::G_ATOMIC_CMPXCHG:897  case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {898    Register Success;899    LLT SuccessLLT;900    auto [Ret, RetLLT, Mem, MemLLT, Cmp, CmpLLT, New, NewLLT] =901        MI.getFirst4RegLLTs();902    RetRegs.push_back(Ret);903    RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());904    if (Opc == TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS) {905      std::tie(Ret, RetLLT, Success, SuccessLLT, Mem, MemLLT, Cmp, CmpLLT, New,906               NewLLT) = MI.getFirst5RegLLTs();907      RetRegs.push_back(Success);908      RetTy = StructType::get(909          Ctx, {RetTy, IntegerType::get(Ctx, SuccessLLT.getSizeInBits())});910    }911    Args.push_back({Cmp, IntegerType::get(Ctx, CmpLLT.getSizeInBits()), 0});912    Args.push_back({New, IntegerType::get(Ctx, NewLLT.getSizeInBits()), 0});913    Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});914    break;915  }916  case TargetOpcode::G_ATOMICRMW_XCHG:917  case TargetOpcode::G_ATOMICRMW_ADD:918  case TargetOpcode::G_ATOMICRMW_SUB:919  case TargetOpcode::G_ATOMICRMW_AND:920  case TargetOpcode::G_ATOMICRMW_OR:921  case TargetOpcode::G_ATOMICRMW_XOR: {922    auto [Ret, RetLLT, Mem, MemLLT, Val, ValLLT] = MI.getFirst3RegLLTs();923    RetRegs.push_back(Ret);924    RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());925    if (Opc == TargetOpcode::G_ATOMICRMW_AND)926      Val =927          MIRBuilder.buildXor(ValLLT, MIRBuilder.buildConstant(ValLLT, -1), Val)928              .getReg(0);929    else if (Opc == TargetOpcode::G_ATOMICRMW_SUB)930      Val =931          MIRBuilder.buildSub(ValLLT, MIRBuilder.buildConstant(ValLLT, 0), Val)932              .getReg(0);933    Args.push_back({Val, IntegerType::get(Ctx, ValLLT.getSizeInBits()), 0});934    Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});935    break;936  }937  default:938    llvm_unreachable("unsupported opcode");939  }940 941  auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();942  auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();943  RTLIB::Libcall RTLibcall = getOutlineAtomicLibcall(MI);944  const char *Name = TLI.getLibcallName(RTLibcall);945 946  // Unsupported libcall on the target.947  if (!Name) {948    LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "949                      << MIRBuilder.getTII().getName(Opc) << "\n");950    return LegalizerHelper::UnableToLegalize;951  }952 953  CallLowering::CallLoweringInfo Info;954  Info.CallConv = TLI.getLibcallCallingConv(RTLibcall);955  Info.Callee = MachineOperand::CreateES(Name);956  Info.OrigRet = CallLowering::ArgInfo(RetRegs, RetTy, 0);957 958  llvm::append_range(Info.OrigArgs, Args);959  if (!CLI.lowerCall(MIRBuilder, Info))960    return LegalizerHelper::UnableToLegalize;961 962  return LegalizerHelper::Legalized;963}964 965static RTLIB::Libcall getConvRTLibDesc(unsigned Opcode, Type *ToType,966                                       Type *FromType) {967  auto ToMVT = MVT::getVT(ToType);968  auto FromMVT = MVT::getVT(FromType);969 970  switch (Opcode) {971  case TargetOpcode::G_FPEXT:972    return RTLIB::getFPEXT(FromMVT, ToMVT);973  case TargetOpcode::G_FPTRUNC:974    return RTLIB::getFPROUND(FromMVT, ToMVT);975  case TargetOpcode::G_FPTOSI:976    return RTLIB::getFPTOSINT(FromMVT, ToMVT);977  case TargetOpcode::G_FPTOUI:978    return RTLIB::getFPTOUINT(FromMVT, ToMVT);979  case TargetOpcode::G_SITOFP:980    return RTLIB::getSINTTOFP(FromMVT, ToMVT);981  case TargetOpcode::G_UITOFP:982    return RTLIB::getUINTTOFP(FromMVT, ToMVT);983  }984  llvm_unreachable("Unsupported libcall function");985}986 987static LegalizerHelper::LegalizeResult988conversionLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, Type *ToType,989                  Type *FromType, LostDebugLocObserver &LocObserver,990                  const TargetLowering &TLI, bool IsSigned = false) {991  CallLowering::ArgInfo Arg = {MI.getOperand(1).getReg(), FromType, 0};992  if (FromType->isIntegerTy()) {993    if (TLI.shouldSignExtendTypeInLibCall(FromType, IsSigned))994      Arg.Flags[0].setSExt();995    else996      Arg.Flags[0].setZExt();997  }998 999  RTLIB::Libcall Libcall = getConvRTLibDesc(MI.getOpcode(), ToType, FromType);1000  return createLibcall(MIRBuilder, Libcall,1001                       {MI.getOperand(0).getReg(), ToType, 0}, Arg, LocObserver,1002                       &MI);1003}1004 1005static RTLIB::Libcall1006getStateLibraryFunctionFor(MachineInstr &MI, const TargetLowering &TLI) {1007  RTLIB::Libcall RTLibcall;1008  switch (MI.getOpcode()) {1009  case TargetOpcode::G_GET_FPENV:1010    RTLibcall = RTLIB::FEGETENV;1011    break;1012  case TargetOpcode::G_SET_FPENV:1013  case TargetOpcode::G_RESET_FPENV:1014    RTLibcall = RTLIB::FESETENV;1015    break;1016  case TargetOpcode::G_GET_FPMODE:1017    RTLibcall = RTLIB::FEGETMODE;1018    break;1019  case TargetOpcode::G_SET_FPMODE:1020  case TargetOpcode::G_RESET_FPMODE:1021    RTLibcall = RTLIB::FESETMODE;1022    break;1023  default:1024    llvm_unreachable("Unexpected opcode");1025  }1026  return RTLibcall;1027}1028 1029// Some library functions that read FP state (fegetmode, fegetenv) write the1030// state into a region in memory. IR intrinsics that do the same operations1031// (get_fpmode, get_fpenv) return the state as integer value. To implement these1032// intrinsics via the library functions, we need to use temporary variable,1033// for example:1034//1035//     %0:_(s32) = G_GET_FPMODE1036//1037// is transformed to:1038//1039//     %1:_(p0) = G_FRAME_INDEX %stack.01040//     BL &fegetmode1041//     %0:_(s32) = G_LOAD % 11042//1043LegalizerHelper::LegalizeResult1044LegalizerHelper::createGetStateLibcall(MachineIRBuilder &MIRBuilder,1045                                       MachineInstr &MI,1046                                       LostDebugLocObserver &LocObserver) {1047  const DataLayout &DL = MIRBuilder.getDataLayout();1048  auto &MF = MIRBuilder.getMF();1049  auto &MRI = *MIRBuilder.getMRI();1050  auto &Ctx = MF.getFunction().getContext();1051 1052  // Create temporary, where library function will put the read state.1053  Register Dst = MI.getOperand(0).getReg();1054  LLT StateTy = MRI.getType(Dst);1055  TypeSize StateSize = StateTy.getSizeInBytes();1056  Align TempAlign = getStackTemporaryAlignment(StateTy);1057  MachinePointerInfo TempPtrInfo;1058  auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);1059 1060  // Create a call to library function, with the temporary as an argument.1061  unsigned TempAddrSpace = DL.getAllocaAddrSpace();1062  Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);1063  RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);1064  auto Res =1065      createLibcall(MIRBuilder, RTLibcall,1066                    CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),1067                    CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}),1068                    LocObserver, nullptr);1069  if (Res != LegalizerHelper::Legalized)1070    return Res;1071 1072  // Create a load from the temporary.1073  MachineMemOperand *MMO = MF.getMachineMemOperand(1074      TempPtrInfo, MachineMemOperand::MOLoad, StateTy, TempAlign);1075  MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, Dst, Temp, *MMO);1076 1077  return LegalizerHelper::Legalized;1078}1079 1080// Similar to `createGetStateLibcall` the function calls a library function1081// using transient space in stack. In this case the library function reads1082// content of memory region.1083LegalizerHelper::LegalizeResult1084LegalizerHelper::createSetStateLibcall(MachineIRBuilder &MIRBuilder,1085                                       MachineInstr &MI,1086                                       LostDebugLocObserver &LocObserver) {1087  const DataLayout &DL = MIRBuilder.getDataLayout();1088  auto &MF = MIRBuilder.getMF();1089  auto &MRI = *MIRBuilder.getMRI();1090  auto &Ctx = MF.getFunction().getContext();1091 1092  // Create temporary, where library function will get the new state.1093  Register Src = MI.getOperand(0).getReg();1094  LLT StateTy = MRI.getType(Src);1095  TypeSize StateSize = StateTy.getSizeInBytes();1096  Align TempAlign = getStackTemporaryAlignment(StateTy);1097  MachinePointerInfo TempPtrInfo;1098  auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);1099 1100  // Put the new state into the temporary.1101  MachineMemOperand *MMO = MF.getMachineMemOperand(1102      TempPtrInfo, MachineMemOperand::MOStore, StateTy, TempAlign);1103  MIRBuilder.buildStore(Src, Temp, *MMO);1104 1105  // Create a call to library function, with the temporary as an argument.1106  unsigned TempAddrSpace = DL.getAllocaAddrSpace();1107  Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);1108  RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);1109  return createLibcall(MIRBuilder, RTLibcall,1110                       CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),1111                       CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}),1112                       LocObserver, nullptr);1113}1114 1115/// Returns the corresponding libcall for the given Pred and1116/// the ICMP predicate that should be generated to compare with #01117/// after the libcall.1118static std::pair<RTLIB::Libcall, CmpInst::Predicate>1119getFCMPLibcallDesc(const CmpInst::Predicate Pred, unsigned Size) {1120#define RTLIBCASE_CMP(LibcallPrefix, ICmpPred)                                 \1121  do {                                                                         \1122    switch (Size) {                                                            \1123    case 32:                                                                   \1124      return {RTLIB::LibcallPrefix##32, ICmpPred};                             \1125    case 64:                                                                   \1126      return {RTLIB::LibcallPrefix##64, ICmpPred};                             \1127    case 128:                                                                  \1128      return {RTLIB::LibcallPrefix##128, ICmpPred};                            \1129    default:                                                                   \1130      llvm_unreachable("unexpected size");                                     \1131    }                                                                          \1132  } while (0)1133 1134  switch (Pred) {1135  case CmpInst::FCMP_OEQ:1136    RTLIBCASE_CMP(OEQ_F, CmpInst::ICMP_EQ);1137  case CmpInst::FCMP_UNE:1138    RTLIBCASE_CMP(UNE_F, CmpInst::ICMP_NE);1139  case CmpInst::FCMP_OGE:1140    RTLIBCASE_CMP(OGE_F, CmpInst::ICMP_SGE);1141  case CmpInst::FCMP_OLT:1142    RTLIBCASE_CMP(OLT_F, CmpInst::ICMP_SLT);1143  case CmpInst::FCMP_OLE:1144    RTLIBCASE_CMP(OLE_F, CmpInst::ICMP_SLE);1145  case CmpInst::FCMP_OGT:1146    RTLIBCASE_CMP(OGT_F, CmpInst::ICMP_SGT);1147  case CmpInst::FCMP_UNO:1148    RTLIBCASE_CMP(UO_F, CmpInst::ICMP_NE);1149  default:1150    return {RTLIB::UNKNOWN_LIBCALL, CmpInst::BAD_ICMP_PREDICATE};1151  }1152}1153 1154LegalizerHelper::LegalizeResult1155LegalizerHelper::createFCMPLibcall(MachineIRBuilder &MIRBuilder,1156                                   MachineInstr &MI,1157                                   LostDebugLocObserver &LocObserver) {1158  auto &MF = MIRBuilder.getMF();1159  auto &Ctx = MF.getFunction().getContext();1160  const GFCmp *Cmp = cast<GFCmp>(&MI);1161 1162  LLT OpLLT = MRI.getType(Cmp->getLHSReg());1163  unsigned Size = OpLLT.getSizeInBits();1164  if ((Size != 32 && Size != 64 && Size != 128) ||1165      OpLLT != MRI.getType(Cmp->getRHSReg()))1166    return UnableToLegalize;1167 1168  Type *OpType = getFloatTypeForLLT(Ctx, OpLLT);1169 1170  // DstReg type is s321171  const Register DstReg = Cmp->getReg(0);1172  LLT DstTy = MRI.getType(DstReg);1173  const auto Cond = Cmp->getCond();1174 1175  // Reference:1176  // https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-11177  // Generates a libcall followed by ICMP.1178  const auto BuildLibcall = [&](const RTLIB::Libcall Libcall,1179                                const CmpInst::Predicate ICmpPred,1180                                const DstOp &Res) -> Register {1181    // FCMP libcall always returns an i32, and needs an ICMP with #0.1182    constexpr LLT TempLLT = LLT::scalar(32);1183    Register Temp = MRI.createGenericVirtualRegister(TempLLT);1184    // Generate libcall, holding result in Temp1185    const auto Status = createLibcall(1186        MIRBuilder, Libcall, {Temp, Type::getInt32Ty(Ctx), 0},1187        {{Cmp->getLHSReg(), OpType, 0}, {Cmp->getRHSReg(), OpType, 1}},1188        LocObserver, &MI);1189    if (!Status)1190      return {};1191 1192    // Compare temp with #0 to get the final result.1193    return MIRBuilder1194        .buildICmp(ICmpPred, Res, Temp, MIRBuilder.buildConstant(TempLLT, 0))1195        .getReg(0);1196  };1197 1198  // Simple case if we have a direct mapping from predicate to libcall1199  if (const auto [Libcall, ICmpPred] = getFCMPLibcallDesc(Cond, Size);1200      Libcall != RTLIB::UNKNOWN_LIBCALL &&1201      ICmpPred != CmpInst::BAD_ICMP_PREDICATE) {1202    if (BuildLibcall(Libcall, ICmpPred, DstReg)) {1203      return Legalized;1204    }1205    return UnableToLegalize;1206  }1207 1208  // No direct mapping found, should be generated as combination of libcalls.1209 1210  switch (Cond) {1211  case CmpInst::FCMP_UEQ: {1212    // FCMP_UEQ: unordered or equal1213    // Convert into (FCMP_OEQ || FCMP_UNO).1214 1215    const auto [OeqLibcall, OeqPred] =1216        getFCMPLibcallDesc(CmpInst::FCMP_OEQ, Size);1217    const auto Oeq = BuildLibcall(OeqLibcall, OeqPred, DstTy);1218 1219    const auto [UnoLibcall, UnoPred] =1220        getFCMPLibcallDesc(CmpInst::FCMP_UNO, Size);1221    const auto Uno = BuildLibcall(UnoLibcall, UnoPred, DstTy);1222    if (Oeq && Uno)1223      MIRBuilder.buildOr(DstReg, Oeq, Uno);1224    else1225      return UnableToLegalize;1226 1227    break;1228  }1229  case CmpInst::FCMP_ONE: {1230    // FCMP_ONE: ordered and operands are unequal1231    // Convert into (!FCMP_OEQ && !FCMP_UNO).1232 1233    // We inverse the predicate instead of generating a NOT1234    // to save one instruction.1235    // On AArch64 isel can even select two cmp into a single ccmp.1236    const auto [OeqLibcall, OeqPred] =1237        getFCMPLibcallDesc(CmpInst::FCMP_OEQ, Size);1238    const auto NotOeq =1239        BuildLibcall(OeqLibcall, CmpInst::getInversePredicate(OeqPred), DstTy);1240 1241    const auto [UnoLibcall, UnoPred] =1242        getFCMPLibcallDesc(CmpInst::FCMP_UNO, Size);1243    const auto NotUno =1244        BuildLibcall(UnoLibcall, CmpInst::getInversePredicate(UnoPred), DstTy);1245 1246    if (NotOeq && NotUno)1247      MIRBuilder.buildAnd(DstReg, NotOeq, NotUno);1248    else1249      return UnableToLegalize;1250 1251    break;1252  }1253  case CmpInst::FCMP_ULT:1254  case CmpInst::FCMP_UGE:1255  case CmpInst::FCMP_UGT:1256  case CmpInst::FCMP_ULE:1257  case CmpInst::FCMP_ORD: {1258    // Convert into: !(inverse(Pred))1259    // E.g. FCMP_ULT becomes !FCMP_OGE1260    // This is equivalent to the following, but saves some instructions.1261    //   MIRBuilder.buildNot(1262    //       PredTy,1263    //       MIRBuilder.buildFCmp(CmpInst::getInversePredicate(Pred), PredTy,1264    //                            Op1, Op2));1265    const auto [InversedLibcall, InversedPred] =1266        getFCMPLibcallDesc(CmpInst::getInversePredicate(Cond), Size);1267    if (!BuildLibcall(InversedLibcall,1268                      CmpInst::getInversePredicate(InversedPred), DstReg))1269      return UnableToLegalize;1270    break;1271  }1272  default:1273    return UnableToLegalize;1274  }1275 1276  return Legalized;1277}1278 1279// The function is used to legalize operations that set default environment1280// state. In C library a call like `fesetmode(FE_DFL_MODE)` is used for that.1281// On most targets supported in glibc FE_DFL_MODE is defined as1282// `((const femode_t *) -1)`. Such assumption is used here. If for some target1283// it is not true, the target must provide custom lowering.1284LegalizerHelper::LegalizeResult1285LegalizerHelper::createResetStateLibcall(MachineIRBuilder &MIRBuilder,1286                                         MachineInstr &MI,1287                                         LostDebugLocObserver &LocObserver) {1288  const DataLayout &DL = MIRBuilder.getDataLayout();1289  auto &MF = MIRBuilder.getMF();1290  auto &Ctx = MF.getFunction().getContext();1291 1292  // Create an argument for the library function.1293  unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();1294  Type *StatePtrTy = PointerType::get(Ctx, AddrSpace);1295  unsigned PtrSize = DL.getPointerSizeInBits(AddrSpace);1296  LLT MemTy = LLT::pointer(AddrSpace, PtrSize);1297  auto DefValue = MIRBuilder.buildConstant(LLT::scalar(PtrSize), -1LL);1298  DstOp Dest(MRI.createGenericVirtualRegister(MemTy));1299  MIRBuilder.buildIntToPtr(Dest, DefValue);1300 1301  RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);1302  return createLibcall(MIRBuilder, RTLibcall,1303                       CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),1304                       CallLowering::ArgInfo({Dest.getReg(), StatePtrTy, 0}),1305                       LocObserver, &MI);1306}1307 1308LegalizerHelper::LegalizeResult1309LegalizerHelper::libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver) {1310  auto &Ctx = MIRBuilder.getMF().getFunction().getContext();1311 1312  switch (MI.getOpcode()) {1313  default:1314    return UnableToLegalize;1315  case TargetOpcode::G_MUL:1316  case TargetOpcode::G_SDIV:1317  case TargetOpcode::G_UDIV:1318  case TargetOpcode::G_SREM:1319  case TargetOpcode::G_UREM:1320  case TargetOpcode::G_CTLZ_ZERO_UNDEF: {1321    LLT LLTy = MRI.getType(MI.getOperand(0).getReg());1322    unsigned Size = LLTy.getSizeInBits();1323    Type *HLTy = IntegerType::get(Ctx, Size);1324    auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);1325    if (Status != Legalized)1326      return Status;1327    break;1328  }1329  case TargetOpcode::G_FADD:1330  case TargetOpcode::G_FSUB:1331  case TargetOpcode::G_FMUL:1332  case TargetOpcode::G_FDIV:1333  case TargetOpcode::G_FMA:1334  case TargetOpcode::G_FPOW:1335  case TargetOpcode::G_FREM:1336  case TargetOpcode::G_FCOS:1337  case TargetOpcode::G_FSIN:1338  case TargetOpcode::G_FTAN:1339  case TargetOpcode::G_FACOS:1340  case TargetOpcode::G_FASIN:1341  case TargetOpcode::G_FATAN:1342  case TargetOpcode::G_FATAN2:1343  case TargetOpcode::G_FCOSH:1344  case TargetOpcode::G_FSINH:1345  case TargetOpcode::G_FTANH:1346  case TargetOpcode::G_FLOG10:1347  case TargetOpcode::G_FLOG:1348  case TargetOpcode::G_FLOG2:1349  case TargetOpcode::G_FEXP:1350  case TargetOpcode::G_FEXP2:1351  case TargetOpcode::G_FEXP10:1352  case TargetOpcode::G_FCEIL:1353  case TargetOpcode::G_FFLOOR:1354  case TargetOpcode::G_FMINNUM:1355  case TargetOpcode::G_FMAXNUM:1356  case TargetOpcode::G_FMINIMUMNUM:1357  case TargetOpcode::G_FMAXIMUMNUM:1358  case TargetOpcode::G_FSQRT:1359  case TargetOpcode::G_FRINT:1360  case TargetOpcode::G_FNEARBYINT:1361  case TargetOpcode::G_INTRINSIC_TRUNC:1362  case TargetOpcode::G_INTRINSIC_ROUND:1363  case TargetOpcode::G_INTRINSIC_ROUNDEVEN: {1364    LLT LLTy = MRI.getType(MI.getOperand(0).getReg());1365    unsigned Size = LLTy.getSizeInBits();1366    Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);1367    if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {1368      LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");1369      return UnableToLegalize;1370    }1371    auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);1372    if (Status != Legalized)1373      return Status;1374    break;1375  }1376  case TargetOpcode::G_FSINCOS: {1377    LLT LLTy = MRI.getType(MI.getOperand(0).getReg());1378    unsigned Size = LLTy.getSizeInBits();1379    Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);1380    if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {1381      LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");1382      return UnableToLegalize;1383    }1384    return emitSincosLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);1385  }1386  case TargetOpcode::G_FMODF: {1387    LLT LLTy = MRI.getType(MI.getOperand(0).getReg());1388    unsigned Size = LLTy.getSizeInBits();1389    Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);1390    if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {1391      LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");1392      return UnableToLegalize;1393    }1394    return emitModfLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);1395  }1396  case TargetOpcode::G_LROUND:1397  case TargetOpcode::G_LLROUND:1398  case TargetOpcode::G_INTRINSIC_LRINT:1399  case TargetOpcode::G_INTRINSIC_LLRINT: {1400    LLT LLTy = MRI.getType(MI.getOperand(1).getReg());1401    unsigned Size = LLTy.getSizeInBits();1402    Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);1403    Type *ITy = IntegerType::get(1404        Ctx, MRI.getType(MI.getOperand(0).getReg()).getSizeInBits());1405    if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {1406      LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");1407      return UnableToLegalize;1408    }1409    auto Libcall = getRTLibDesc(MI.getOpcode(), Size);1410    LegalizeResult Status =1411        createLibcall(MIRBuilder, Libcall, {MI.getOperand(0).getReg(), ITy, 0},1412                      {{MI.getOperand(1).getReg(), HLTy, 0}}, LocObserver, &MI);1413    if (Status != Legalized)1414      return Status;1415    MI.eraseFromParent();1416    return Legalized;1417  }1418  case TargetOpcode::G_FPOWI:1419  case TargetOpcode::G_FLDEXP: {1420    LLT LLTy = MRI.getType(MI.getOperand(0).getReg());1421    unsigned Size = LLTy.getSizeInBits();1422    Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);1423    Type *ITy = IntegerType::get(1424        Ctx, MRI.getType(MI.getOperand(2).getReg()).getSizeInBits());1425    if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {1426      LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");1427      return UnableToLegalize;1428    }1429    auto Libcall = getRTLibDesc(MI.getOpcode(), Size);1430    SmallVector<CallLowering::ArgInfo, 2> Args = {1431        {MI.getOperand(1).getReg(), HLTy, 0},1432        {MI.getOperand(2).getReg(), ITy, 1}};1433    Args[1].Flags[0].setSExt();1434    LegalizeResult Status =1435        createLibcall(MIRBuilder, Libcall, {MI.getOperand(0).getReg(), HLTy, 0},1436                      Args, LocObserver, &MI);1437    if (Status != Legalized)1438      return Status;1439    break;1440  }1441  case TargetOpcode::G_FPEXT:1442  case TargetOpcode::G_FPTRUNC: {1443    Type *FromTy = getFloatTypeForLLT(Ctx,  MRI.getType(MI.getOperand(1).getReg()));1444    Type *ToTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));1445    if (!FromTy || !ToTy)1446      return UnableToLegalize;1447    LegalizeResult Status =1448        conversionLibcall(MI, MIRBuilder, ToTy, FromTy, LocObserver, TLI);1449    if (Status != Legalized)1450      return Status;1451    break;1452  }1453  case TargetOpcode::G_FCMP: {1454    LegalizeResult Status = createFCMPLibcall(MIRBuilder, MI, LocObserver);1455    if (Status != Legalized)1456      return Status;1457    MI.eraseFromParent();1458    return Status;1459  }1460  case TargetOpcode::G_FPTOSI:1461  case TargetOpcode::G_FPTOUI: {1462    // FIXME: Support other types1463    Type *FromTy =1464        getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));1465    unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();1466    if ((ToSize != 32 && ToSize != 64 && ToSize != 128) || !FromTy)1467      return UnableToLegalize;1468    LegalizeResult Status = conversionLibcall(1469        MI, MIRBuilder, Type::getIntNTy(Ctx, ToSize), FromTy, LocObserver, TLI);1470    if (Status != Legalized)1471      return Status;1472    break;1473  }1474  case TargetOpcode::G_SITOFP:1475  case TargetOpcode::G_UITOFP: {1476    unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();1477    Type *ToTy =1478        getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));1479    if ((FromSize != 32 && FromSize != 64 && FromSize != 128) || !ToTy)1480      return UnableToLegalize;1481    bool IsSigned = MI.getOpcode() == TargetOpcode::G_SITOFP;1482    LegalizeResult Status =1483        conversionLibcall(MI, MIRBuilder, ToTy, Type::getIntNTy(Ctx, FromSize),1484                          LocObserver, TLI, IsSigned);1485    if (Status != Legalized)1486      return Status;1487    break;1488  }1489  case TargetOpcode::G_ATOMICRMW_XCHG:1490  case TargetOpcode::G_ATOMICRMW_ADD:1491  case TargetOpcode::G_ATOMICRMW_SUB:1492  case TargetOpcode::G_ATOMICRMW_AND:1493  case TargetOpcode::G_ATOMICRMW_OR:1494  case TargetOpcode::G_ATOMICRMW_XOR:1495  case TargetOpcode::G_ATOMIC_CMPXCHG:1496  case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {1497    auto Status = createAtomicLibcall(MIRBuilder, MI);1498    if (Status != Legalized)1499      return Status;1500    break;1501  }1502  case TargetOpcode::G_BZERO:1503  case TargetOpcode::G_MEMCPY:1504  case TargetOpcode::G_MEMMOVE:1505  case TargetOpcode::G_MEMSET: {1506    LegalizeResult Result =1507        createMemLibcall(MIRBuilder, *MIRBuilder.getMRI(), MI, LocObserver);1508    if (Result != Legalized)1509      return Result;1510    MI.eraseFromParent();1511    return Result;1512  }1513  case TargetOpcode::G_GET_FPENV:1514  case TargetOpcode::G_GET_FPMODE: {1515    LegalizeResult Result = createGetStateLibcall(MIRBuilder, MI, LocObserver);1516    if (Result != Legalized)1517      return Result;1518    break;1519  }1520  case TargetOpcode::G_SET_FPENV:1521  case TargetOpcode::G_SET_FPMODE: {1522    LegalizeResult Result = createSetStateLibcall(MIRBuilder, MI, LocObserver);1523    if (Result != Legalized)1524      return Result;1525    break;1526  }1527  case TargetOpcode::G_RESET_FPENV:1528  case TargetOpcode::G_RESET_FPMODE: {1529    LegalizeResult Result =1530        createResetStateLibcall(MIRBuilder, MI, LocObserver);1531    if (Result != Legalized)1532      return Result;1533    break;1534  }1535  }1536 1537  MI.eraseFromParent();1538  return Legalized;1539}1540 1541LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,1542                                                              unsigned TypeIdx,1543                                                              LLT NarrowTy) {1544  uint64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();1545  uint64_t NarrowSize = NarrowTy.getSizeInBits();1546 1547  switch (MI.getOpcode()) {1548  default:1549    return UnableToLegalize;1550  case TargetOpcode::G_IMPLICIT_DEF: {1551    Register DstReg = MI.getOperand(0).getReg();1552    LLT DstTy = MRI.getType(DstReg);1553 1554    // If SizeOp0 is not an exact multiple of NarrowSize, emit1555    // G_ANYEXT(G_IMPLICIT_DEF). Cast result to vector if needed.1556    // FIXME: Although this would also be legal for the general case, it causes1557    //  a lot of regressions in the emitted code (superfluous COPYs, artifact1558    //  combines not being hit). This seems to be a problem related to the1559    //  artifact combiner.1560    if (SizeOp0 % NarrowSize != 0) {1561      LLT ImplicitTy = NarrowTy;1562      if (DstTy.isVector())1563        ImplicitTy = LLT::vector(DstTy.getElementCount(), ImplicitTy);1564 1565      Register ImplicitReg = MIRBuilder.buildUndef(ImplicitTy).getReg(0);1566      MIRBuilder.buildAnyExt(DstReg, ImplicitReg);1567 1568      MI.eraseFromParent();1569      return Legalized;1570    }1571 1572    int NumParts = SizeOp0 / NarrowSize;1573 1574    SmallVector<Register, 2> DstRegs;1575    for (int i = 0; i < NumParts; ++i)1576      DstRegs.push_back(MIRBuilder.buildUndef(NarrowTy).getReg(0));1577 1578    if (DstTy.isVector())1579      MIRBuilder.buildBuildVector(DstReg, DstRegs);1580    else1581      MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);1582    MI.eraseFromParent();1583    return Legalized;1584  }1585  case TargetOpcode::G_CONSTANT: {1586    LLT Ty = MRI.getType(MI.getOperand(0).getReg());1587    const APInt &Val = MI.getOperand(1).getCImm()->getValue();1588    unsigned TotalSize = Ty.getSizeInBits();1589    unsigned NarrowSize = NarrowTy.getSizeInBits();1590    int NumParts = TotalSize / NarrowSize;1591 1592    SmallVector<Register, 4> PartRegs;1593    for (int I = 0; I != NumParts; ++I) {1594      unsigned Offset = I * NarrowSize;1595      auto K = MIRBuilder.buildConstant(NarrowTy,1596                                        Val.lshr(Offset).trunc(NarrowSize));1597      PartRegs.push_back(K.getReg(0));1598    }1599 1600    LLT LeftoverTy;1601    unsigned LeftoverBits = TotalSize - NumParts * NarrowSize;1602    SmallVector<Register, 1> LeftoverRegs;1603    if (LeftoverBits != 0) {1604      LeftoverTy = LLT::scalar(LeftoverBits);1605      auto K = MIRBuilder.buildConstant(1606        LeftoverTy,1607        Val.lshr(NumParts * NarrowSize).trunc(LeftoverBits));1608      LeftoverRegs.push_back(K.getReg(0));1609    }1610 1611    insertParts(MI.getOperand(0).getReg(),1612                Ty, NarrowTy, PartRegs, LeftoverTy, LeftoverRegs);1613 1614    MI.eraseFromParent();1615    return Legalized;1616  }1617  case TargetOpcode::G_SEXT:1618  case TargetOpcode::G_ZEXT:1619  case TargetOpcode::G_ANYEXT:1620    return narrowScalarExt(MI, TypeIdx, NarrowTy);1621  case TargetOpcode::G_TRUNC: {1622    if (TypeIdx != 1)1623      return UnableToLegalize;1624 1625    uint64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();1626    if (NarrowTy.getSizeInBits() * 2 != SizeOp1) {1627      LLVM_DEBUG(dbgs() << "Can't narrow trunc to type " << NarrowTy << "\n");1628      return UnableToLegalize;1629    }1630 1631    auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));1632    MIRBuilder.buildCopy(MI.getOperand(0), Unmerge.getReg(0));1633    MI.eraseFromParent();1634    return Legalized;1635  }1636  case TargetOpcode::G_CONSTANT_FOLD_BARRIER:1637  case TargetOpcode::G_FREEZE: {1638    if (TypeIdx != 0)1639      return UnableToLegalize;1640 1641    LLT Ty = MRI.getType(MI.getOperand(0).getReg());1642    // Should widen scalar first1643    if (Ty.getSizeInBits() % NarrowTy.getSizeInBits() != 0)1644      return UnableToLegalize;1645 1646    auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1).getReg());1647    SmallVector<Register, 8> Parts;1648    for (unsigned i = 0; i < Unmerge->getNumDefs(); ++i) {1649      Parts.push_back(1650          MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy}, {Unmerge.getReg(i)})1651              .getReg(0));1652    }1653 1654    MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), Parts);1655    MI.eraseFromParent();1656    return Legalized;1657  }1658  case TargetOpcode::G_ADD:1659  case TargetOpcode::G_SUB:1660  case TargetOpcode::G_SADDO:1661  case TargetOpcode::G_SSUBO:1662  case TargetOpcode::G_SADDE:1663  case TargetOpcode::G_SSUBE:1664  case TargetOpcode::G_UADDO:1665  case TargetOpcode::G_USUBO:1666  case TargetOpcode::G_UADDE:1667  case TargetOpcode::G_USUBE:1668    return narrowScalarAddSub(MI, TypeIdx, NarrowTy);1669  case TargetOpcode::G_MUL:1670  case TargetOpcode::G_UMULH:1671    return narrowScalarMul(MI, NarrowTy);1672  case TargetOpcode::G_EXTRACT:1673    return narrowScalarExtract(MI, TypeIdx, NarrowTy);1674  case TargetOpcode::G_INSERT:1675    return narrowScalarInsert(MI, TypeIdx, NarrowTy);1676  case TargetOpcode::G_LOAD: {1677    auto &LoadMI = cast<GLoad>(MI);1678    Register DstReg = LoadMI.getDstReg();1679    LLT DstTy = MRI.getType(DstReg);1680    if (DstTy.isVector())1681      return UnableToLegalize;1682 1683    if (8 * LoadMI.getMemSize().getValue() != DstTy.getSizeInBits()) {1684      Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);1685      MIRBuilder.buildLoad(TmpReg, LoadMI.getPointerReg(), LoadMI.getMMO());1686      MIRBuilder.buildAnyExt(DstReg, TmpReg);1687      LoadMI.eraseFromParent();1688      return Legalized;1689    }1690 1691    return reduceLoadStoreWidth(LoadMI, TypeIdx, NarrowTy);1692  }1693  case TargetOpcode::G_ZEXTLOAD:1694  case TargetOpcode::G_SEXTLOAD: {1695    auto &LoadMI = cast<GExtLoad>(MI);1696    Register DstReg = LoadMI.getDstReg();1697    Register PtrReg = LoadMI.getPointerReg();1698 1699    Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);1700    auto &MMO = LoadMI.getMMO();1701    unsigned MemSize = MMO.getSizeInBits().getValue();1702 1703    if (MemSize == NarrowSize) {1704      MIRBuilder.buildLoad(TmpReg, PtrReg, MMO);1705    } else if (MemSize < NarrowSize) {1706      MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), TmpReg, PtrReg, MMO);1707    } else if (MemSize > NarrowSize) {1708      // FIXME: Need to split the load.1709      return UnableToLegalize;1710    }1711 1712    if (isa<GZExtLoad>(LoadMI))1713      MIRBuilder.buildZExt(DstReg, TmpReg);1714    else1715      MIRBuilder.buildSExt(DstReg, TmpReg);1716 1717    LoadMI.eraseFromParent();1718    return Legalized;1719  }1720  case TargetOpcode::G_STORE: {1721    auto &StoreMI = cast<GStore>(MI);1722 1723    Register SrcReg = StoreMI.getValueReg();1724    LLT SrcTy = MRI.getType(SrcReg);1725    if (SrcTy.isVector())1726      return UnableToLegalize;1727 1728    int NumParts = SizeOp0 / NarrowSize;1729    unsigned HandledSize = NumParts * NarrowTy.getSizeInBits();1730    unsigned LeftoverBits = SrcTy.getSizeInBits() - HandledSize;1731    if (SrcTy.isVector() && LeftoverBits != 0)1732      return UnableToLegalize;1733 1734    if (8 * StoreMI.getMemSize().getValue() != SrcTy.getSizeInBits()) {1735      Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);1736      MIRBuilder.buildTrunc(TmpReg, SrcReg);1737      MIRBuilder.buildStore(TmpReg, StoreMI.getPointerReg(), StoreMI.getMMO());1738      StoreMI.eraseFromParent();1739      return Legalized;1740    }1741 1742    return reduceLoadStoreWidth(StoreMI, 0, NarrowTy);1743  }1744  case TargetOpcode::G_SELECT:1745    return narrowScalarSelect(MI, TypeIdx, NarrowTy);1746  case TargetOpcode::G_AND:1747  case TargetOpcode::G_OR:1748  case TargetOpcode::G_XOR: {1749    // Legalize bitwise operation:1750    // A = BinOp<Ty> B, C1751    // into:1752    // B1, ..., BN = G_UNMERGE_VALUES B1753    // C1, ..., CN = G_UNMERGE_VALUES C1754    // A1 = BinOp<Ty/N> B1, C21755    // ...1756    // AN = BinOp<Ty/N> BN, CN1757    // A = G_MERGE_VALUES A1, ..., AN1758    return narrowScalarBasic(MI, TypeIdx, NarrowTy);1759  }1760  case TargetOpcode::G_SHL:1761  case TargetOpcode::G_LSHR:1762  case TargetOpcode::G_ASHR:1763    return narrowScalarShift(MI, TypeIdx, NarrowTy);1764  case TargetOpcode::G_CTLZ:1765  case TargetOpcode::G_CTLZ_ZERO_UNDEF:1766  case TargetOpcode::G_CTTZ:1767  case TargetOpcode::G_CTTZ_ZERO_UNDEF:1768  case TargetOpcode::G_CTPOP:1769    if (TypeIdx == 1)1770      switch (MI.getOpcode()) {1771      case TargetOpcode::G_CTLZ:1772      case TargetOpcode::G_CTLZ_ZERO_UNDEF:1773        return narrowScalarCTLZ(MI, TypeIdx, NarrowTy);1774      case TargetOpcode::G_CTTZ:1775      case TargetOpcode::G_CTTZ_ZERO_UNDEF:1776        return narrowScalarCTTZ(MI, TypeIdx, NarrowTy);1777      case TargetOpcode::G_CTPOP:1778        return narrowScalarCTPOP(MI, TypeIdx, NarrowTy);1779      default:1780        return UnableToLegalize;1781      }1782 1783    Observer.changingInstr(MI);1784    narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);1785    Observer.changedInstr(MI);1786    return Legalized;1787  case TargetOpcode::G_INTTOPTR:1788    if (TypeIdx != 1)1789      return UnableToLegalize;1790 1791    Observer.changingInstr(MI);1792    narrowScalarSrc(MI, NarrowTy, 1);1793    Observer.changedInstr(MI);1794    return Legalized;1795  case TargetOpcode::G_PTRTOINT:1796    if (TypeIdx != 0)1797      return UnableToLegalize;1798 1799    Observer.changingInstr(MI);1800    narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);1801    Observer.changedInstr(MI);1802    return Legalized;1803  case TargetOpcode::G_PHI: {1804    // FIXME: add support for when SizeOp0 isn't an exact multiple of1805    // NarrowSize.1806    if (SizeOp0 % NarrowSize != 0)1807      return UnableToLegalize;1808 1809    unsigned NumParts = SizeOp0 / NarrowSize;1810    SmallVector<Register, 2> DstRegs(NumParts);1811    SmallVector<SmallVector<Register, 2>, 2> SrcRegs(MI.getNumOperands() / 2);1812    Observer.changingInstr(MI);1813    for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {1814      MachineBasicBlock &OpMBB = *MI.getOperand(i + 1).getMBB();1815      MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());1816      extractParts(MI.getOperand(i).getReg(), NarrowTy, NumParts,1817                   SrcRegs[i / 2], MIRBuilder, MRI);1818    }1819    MachineBasicBlock &MBB = *MI.getParent();1820    MIRBuilder.setInsertPt(MBB, MI);1821    for (unsigned i = 0; i < NumParts; ++i) {1822      DstRegs[i] = MRI.createGenericVirtualRegister(NarrowTy);1823      MachineInstrBuilder MIB =1824          MIRBuilder.buildInstr(TargetOpcode::G_PHI).addDef(DstRegs[i]);1825      for (unsigned j = 1; j < MI.getNumOperands(); j += 2)1826        MIB.addUse(SrcRegs[j / 2][i]).add(MI.getOperand(j + 1));1827    }1828    MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());1829    MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);1830    Observer.changedInstr(MI);1831    MI.eraseFromParent();1832    return Legalized;1833  }1834  case TargetOpcode::G_EXTRACT_VECTOR_ELT:1835  case TargetOpcode::G_INSERT_VECTOR_ELT: {1836    if (TypeIdx != 2)1837      return UnableToLegalize;1838 1839    int OpIdx = MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;1840    Observer.changingInstr(MI);1841    narrowScalarSrc(MI, NarrowTy, OpIdx);1842    Observer.changedInstr(MI);1843    return Legalized;1844  }1845  case TargetOpcode::G_ICMP: {1846    Register LHS = MI.getOperand(2).getReg();1847    LLT SrcTy = MRI.getType(LHS);1848    CmpInst::Predicate Pred =1849        static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());1850 1851    LLT LeftoverTy; // Example: s88 -> s64 (NarrowTy) + s24 (leftover)1852    SmallVector<Register, 4> LHSPartRegs, LHSLeftoverRegs;1853    if (!extractParts(LHS, SrcTy, NarrowTy, LeftoverTy, LHSPartRegs,1854                      LHSLeftoverRegs, MIRBuilder, MRI))1855      return UnableToLegalize;1856 1857    LLT Unused; // Matches LeftoverTy; G_ICMP LHS and RHS are the same type.1858    SmallVector<Register, 4> RHSPartRegs, RHSLeftoverRegs;1859    if (!extractParts(MI.getOperand(3).getReg(), SrcTy, NarrowTy, Unused,1860                      RHSPartRegs, RHSLeftoverRegs, MIRBuilder, MRI))1861      return UnableToLegalize;1862 1863    // We now have the LHS and RHS of the compare split into narrow-type1864    // registers, plus potentially some leftover type.1865    Register Dst = MI.getOperand(0).getReg();1866    LLT ResTy = MRI.getType(Dst);1867    if (ICmpInst::isEquality(Pred)) {1868      // For each part on the LHS and RHS, keep track of the result of XOR-ing1869      // them together. For each equal part, the result should be all 0s. For1870      // each non-equal part, we'll get at least one 1.1871      auto Zero = MIRBuilder.buildConstant(NarrowTy, 0);1872      SmallVector<Register, 4> Xors;1873      for (auto LHSAndRHS : zip(LHSPartRegs, RHSPartRegs)) {1874        auto LHS = std::get<0>(LHSAndRHS);1875        auto RHS = std::get<1>(LHSAndRHS);1876        auto Xor = MIRBuilder.buildXor(NarrowTy, LHS, RHS).getReg(0);1877        Xors.push_back(Xor);1878      }1879 1880      // Build a G_XOR for each leftover register. Each G_XOR must be widened1881      // to the desired narrow type so that we can OR them together later.1882      SmallVector<Register, 4> WidenedXors;1883      for (auto LHSAndRHS : zip(LHSLeftoverRegs, RHSLeftoverRegs)) {1884        auto LHS = std::get<0>(LHSAndRHS);1885        auto RHS = std::get<1>(LHSAndRHS);1886        auto Xor = MIRBuilder.buildXor(LeftoverTy, LHS, RHS).getReg(0);1887        LLT GCDTy = extractGCDType(WidenedXors, NarrowTy, LeftoverTy, Xor);1888        buildLCMMergePieces(LeftoverTy, NarrowTy, GCDTy, WidenedXors,1889                            /* PadStrategy = */ TargetOpcode::G_ZEXT);1890        llvm::append_range(Xors, WidenedXors);1891      }1892 1893      // Now, for each part we broke up, we know if they are equal/not equal1894      // based off the G_XOR. We can OR these all together and compare against1895      // 0 to get the result.1896      assert(Xors.size() >= 2 && "Should have gotten at least two Xors?");1897      auto Or = MIRBuilder.buildOr(NarrowTy, Xors[0], Xors[1]);1898      for (unsigned I = 2, E = Xors.size(); I < E; ++I)1899        Or = MIRBuilder.buildOr(NarrowTy, Or, Xors[I]);1900      MIRBuilder.buildICmp(Pred, Dst, Or, Zero);1901    } else {1902      Register CmpIn;1903      for (unsigned I = 0, E = LHSPartRegs.size(); I != E; ++I) {1904        Register CmpOut;1905        CmpInst::Predicate PartPred;1906 1907        if (I == E - 1 && LHSLeftoverRegs.empty()) {1908          PartPred = Pred;1909          CmpOut = Dst;1910        } else {1911          PartPred = ICmpInst::getUnsignedPredicate(Pred);1912          CmpOut = MRI.createGenericVirtualRegister(ResTy);1913        }1914 1915        if (!CmpIn) {1916          MIRBuilder.buildICmp(PartPred, CmpOut, LHSPartRegs[I],1917                               RHSPartRegs[I]);1918        } else {1919          auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSPartRegs[I],1920                                          RHSPartRegs[I]);1921          auto CmpEq = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,1922                                            LHSPartRegs[I], RHSPartRegs[I]);1923          MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);1924        }1925 1926        CmpIn = CmpOut;1927      }1928 1929      for (unsigned I = 0, E = LHSLeftoverRegs.size(); I != E; ++I) {1930        Register CmpOut;1931        CmpInst::Predicate PartPred;1932 1933        if (I == E - 1 && LHSLeftoverRegs.empty()) {1934          PartPred = Pred;1935          CmpOut = Dst;1936        } else {1937          PartPred = ICmpInst::getUnsignedPredicate(Pred);1938          CmpOut = MRI.createGenericVirtualRegister(ResTy);1939        }1940 1941        if (!CmpIn) {1942          MIRBuilder.buildICmp(PartPred, CmpOut, LHSLeftoverRegs[I],1943                               RHSLeftoverRegs[I]);1944        } else {1945          auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSLeftoverRegs[I],1946                                          RHSLeftoverRegs[I]);1947          auto CmpEq =1948              MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,1949                                   LHSLeftoverRegs[I], RHSLeftoverRegs[I]);1950          MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);1951        }1952 1953        CmpIn = CmpOut;1954      }1955    }1956    MI.eraseFromParent();1957    return Legalized;1958  }1959  case TargetOpcode::G_FCMP:1960    if (TypeIdx != 0)1961      return UnableToLegalize;1962 1963    Observer.changingInstr(MI);1964    narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);1965    Observer.changedInstr(MI);1966    return Legalized;1967 1968  case TargetOpcode::G_SEXT_INREG: {1969    if (TypeIdx != 0)1970      return UnableToLegalize;1971 1972    int64_t SizeInBits = MI.getOperand(2).getImm();1973 1974    // So long as the new type has more bits than the bits we're extending we1975    // don't need to break it apart.1976    if (NarrowTy.getScalarSizeInBits() > SizeInBits) {1977      Observer.changingInstr(MI);1978      // We don't lose any non-extension bits by truncating the src and1979      // sign-extending the dst.1980      MachineOperand &MO1 = MI.getOperand(1);1981      auto TruncMIB = MIRBuilder.buildTrunc(NarrowTy, MO1);1982      MO1.setReg(TruncMIB.getReg(0));1983 1984      MachineOperand &MO2 = MI.getOperand(0);1985      Register DstExt = MRI.createGenericVirtualRegister(NarrowTy);1986      MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());1987      MIRBuilder.buildSExt(MO2, DstExt);1988      MO2.setReg(DstExt);1989      Observer.changedInstr(MI);1990      return Legalized;1991    }1992 1993    // Break it apart. Components below the extension point are unmodified. The1994    // component containing the extension point becomes a narrower SEXT_INREG.1995    // Components above it are ashr'd from the component containing the1996    // extension point.1997    if (SizeOp0 % NarrowSize != 0)1998      return UnableToLegalize;1999    int NumParts = SizeOp0 / NarrowSize;2000 2001    // List the registers where the destination will be scattered.2002    SmallVector<Register, 2> DstRegs;2003    // List the registers where the source will be split.2004    SmallVector<Register, 2> SrcRegs;2005 2006    // Create all the temporary registers.2007    for (int i = 0; i < NumParts; ++i) {2008      Register SrcReg = MRI.createGenericVirtualRegister(NarrowTy);2009 2010      SrcRegs.push_back(SrcReg);2011    }2012 2013    // Explode the big arguments into smaller chunks.2014    MIRBuilder.buildUnmerge(SrcRegs, MI.getOperand(1));2015 2016    Register AshrCstReg =2017        MIRBuilder.buildConstant(NarrowTy, NarrowTy.getScalarSizeInBits() - 1)2018            .getReg(0);2019    Register FullExtensionReg;2020    Register PartialExtensionReg;2021 2022    // Do the operation on each small part.2023    for (int i = 0; i < NumParts; ++i) {2024      if ((i + 1) * NarrowTy.getScalarSizeInBits() <= SizeInBits) {2025        DstRegs.push_back(SrcRegs[i]);2026        PartialExtensionReg = DstRegs.back();2027      } else if (i * NarrowTy.getScalarSizeInBits() >= SizeInBits) {2028        assert(PartialExtensionReg &&2029               "Expected to visit partial extension before full");2030        if (FullExtensionReg) {2031          DstRegs.push_back(FullExtensionReg);2032          continue;2033        }2034        DstRegs.push_back(2035            MIRBuilder.buildAShr(NarrowTy, PartialExtensionReg, AshrCstReg)2036                .getReg(0));2037        FullExtensionReg = DstRegs.back();2038      } else {2039        DstRegs.push_back(2040            MIRBuilder2041                .buildInstr(2042                    TargetOpcode::G_SEXT_INREG, {NarrowTy},2043                    {SrcRegs[i], SizeInBits % NarrowTy.getScalarSizeInBits()})2044                .getReg(0));2045        PartialExtensionReg = DstRegs.back();2046      }2047    }2048 2049    // Gather the destination registers into the final destination.2050    Register DstReg = MI.getOperand(0).getReg();2051    MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);2052    MI.eraseFromParent();2053    return Legalized;2054  }2055  case TargetOpcode::G_BSWAP:2056  case TargetOpcode::G_BITREVERSE: {2057    if (SizeOp0 % NarrowSize != 0)2058      return UnableToLegalize;2059 2060    Observer.changingInstr(MI);2061    SmallVector<Register, 2> SrcRegs, DstRegs;2062    unsigned NumParts = SizeOp0 / NarrowSize;2063    extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,2064                 MIRBuilder, MRI);2065 2066    for (unsigned i = 0; i < NumParts; ++i) {2067      auto DstPart = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},2068                                           {SrcRegs[NumParts - 1 - i]});2069      DstRegs.push_back(DstPart.getReg(0));2070    }2071 2072    MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);2073 2074    Observer.changedInstr(MI);2075    MI.eraseFromParent();2076    return Legalized;2077  }2078  case TargetOpcode::G_PTR_ADD:2079  case TargetOpcode::G_PTRMASK: {2080    if (TypeIdx != 1)2081      return UnableToLegalize;2082    Observer.changingInstr(MI);2083    narrowScalarSrc(MI, NarrowTy, 2);2084    Observer.changedInstr(MI);2085    return Legalized;2086  }2087  case TargetOpcode::G_FPTOUI:2088  case TargetOpcode::G_FPTOSI:2089  case TargetOpcode::G_FPTOUI_SAT:2090  case TargetOpcode::G_FPTOSI_SAT:2091    return narrowScalarFPTOI(MI, TypeIdx, NarrowTy);2092  case TargetOpcode::G_FPEXT:2093    if (TypeIdx != 0)2094      return UnableToLegalize;2095    Observer.changingInstr(MI);2096    narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_FPEXT);2097    Observer.changedInstr(MI);2098    return Legalized;2099  case TargetOpcode::G_FLDEXP:2100  case TargetOpcode::G_STRICT_FLDEXP:2101    return narrowScalarFLDEXP(MI, TypeIdx, NarrowTy);2102  case TargetOpcode::G_VSCALE: {2103    Register Dst = MI.getOperand(0).getReg();2104    LLT Ty = MRI.getType(Dst);2105 2106    // Assume VSCALE(1) fits into a legal integer2107    const APInt One(NarrowTy.getSizeInBits(), 1);2108    auto VScaleBase = MIRBuilder.buildVScale(NarrowTy, One);2109    auto ZExt = MIRBuilder.buildZExt(Ty, VScaleBase);2110    auto C = MIRBuilder.buildConstant(Ty, *MI.getOperand(1).getCImm());2111    MIRBuilder.buildMul(Dst, ZExt, C);2112 2113    MI.eraseFromParent();2114    return Legalized;2115  }2116  }2117}2118 2119Register LegalizerHelper::coerceToScalar(Register Val) {2120  LLT Ty = MRI.getType(Val);2121  if (Ty.isScalar())2122    return Val;2123 2124  const DataLayout &DL = MIRBuilder.getDataLayout();2125  LLT NewTy = LLT::scalar(Ty.getSizeInBits());2126  if (Ty.isPointer()) {2127    if (DL.isNonIntegralAddressSpace(Ty.getAddressSpace()))2128      return Register();2129    return MIRBuilder.buildPtrToInt(NewTy, Val).getReg(0);2130  }2131 2132  Register NewVal = Val;2133 2134  assert(Ty.isVector());2135  if (Ty.isPointerVector())2136    NewVal = MIRBuilder.buildPtrToInt(NewTy, NewVal).getReg(0);2137  return MIRBuilder.buildBitcast(NewTy, NewVal).getReg(0);2138}2139 2140void LegalizerHelper::widenScalarSrc(MachineInstr &MI, LLT WideTy,2141                                     unsigned OpIdx, unsigned ExtOpcode) {2142  MachineOperand &MO = MI.getOperand(OpIdx);2143  auto ExtB = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MO});2144  MO.setReg(ExtB.getReg(0));2145}2146 2147void LegalizerHelper::narrowScalarSrc(MachineInstr &MI, LLT NarrowTy,2148                                      unsigned OpIdx) {2149  MachineOperand &MO = MI.getOperand(OpIdx);2150  auto ExtB = MIRBuilder.buildTrunc(NarrowTy, MO);2151  MO.setReg(ExtB.getReg(0));2152}2153 2154void LegalizerHelper::widenScalarDst(MachineInstr &MI, LLT WideTy,2155                                     unsigned OpIdx, unsigned TruncOpcode) {2156  MachineOperand &MO = MI.getOperand(OpIdx);2157  Register DstExt = MRI.createGenericVirtualRegister(WideTy);2158  MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());2159  MIRBuilder.buildInstr(TruncOpcode, {MO}, {DstExt});2160  MO.setReg(DstExt);2161}2162 2163void LegalizerHelper::narrowScalarDst(MachineInstr &MI, LLT NarrowTy,2164                                      unsigned OpIdx, unsigned ExtOpcode) {2165  MachineOperand &MO = MI.getOperand(OpIdx);2166  Register DstTrunc = MRI.createGenericVirtualRegister(NarrowTy);2167  MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());2168  MIRBuilder.buildInstr(ExtOpcode, {MO}, {DstTrunc});2169  MO.setReg(DstTrunc);2170}2171 2172void LegalizerHelper::moreElementsVectorDst(MachineInstr &MI, LLT WideTy,2173                                            unsigned OpIdx) {2174  MachineOperand &MO = MI.getOperand(OpIdx);2175  MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());2176  Register Dst = MO.getReg();2177  Register DstExt = MRI.createGenericVirtualRegister(WideTy);2178  MO.setReg(DstExt);2179  MIRBuilder.buildDeleteTrailingVectorElements(Dst, DstExt);2180}2181 2182void LegalizerHelper::moreElementsVectorSrc(MachineInstr &MI, LLT MoreTy,2183                                            unsigned OpIdx) {2184  MachineOperand &MO = MI.getOperand(OpIdx);2185  MO.setReg(MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO).getReg(0));2186}2187 2188void LegalizerHelper::bitcastSrc(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {2189  MachineOperand &Op = MI.getOperand(OpIdx);2190  Op.setReg(MIRBuilder.buildBitcast(CastTy, Op).getReg(0));2191}2192 2193void LegalizerHelper::bitcastDst(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {2194  MachineOperand &MO = MI.getOperand(OpIdx);2195  Register CastDst = MRI.createGenericVirtualRegister(CastTy);2196  MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());2197  MIRBuilder.buildBitcast(MO, CastDst);2198  MO.setReg(CastDst);2199}2200 2201LegalizerHelper::LegalizeResult2202LegalizerHelper::widenScalarMergeValues(MachineInstr &MI, unsigned TypeIdx,2203                                        LLT WideTy) {2204  if (TypeIdx != 1)2205    return UnableToLegalize;2206 2207  auto [DstReg, DstTy, Src1Reg, Src1Ty] = MI.getFirst2RegLLTs();2208  if (DstTy.isVector())2209    return UnableToLegalize;2210 2211  LLT SrcTy = MRI.getType(Src1Reg);2212  const int DstSize = DstTy.getSizeInBits();2213  const int SrcSize = SrcTy.getSizeInBits();2214  const int WideSize = WideTy.getSizeInBits();2215  const int NumMerge = (DstSize + WideSize - 1) / WideSize;2216 2217  unsigned NumOps = MI.getNumOperands();2218  unsigned NumSrc = MI.getNumOperands() - 1;2219  unsigned PartSize = DstTy.getSizeInBits() / NumSrc;2220 2221  if (WideSize >= DstSize) {2222    // Directly pack the bits in the target type.2223    Register ResultReg = MIRBuilder.buildZExt(WideTy, Src1Reg).getReg(0);2224 2225    for (unsigned I = 2; I != NumOps; ++I) {2226      const unsigned Offset = (I - 1) * PartSize;2227 2228      Register SrcReg = MI.getOperand(I).getReg();2229      assert(MRI.getType(SrcReg) == LLT::scalar(PartSize));2230 2231      auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);2232 2233      Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :2234        MRI.createGenericVirtualRegister(WideTy);2235 2236      auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);2237      auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);2238      MIRBuilder.buildOr(NextResult, ResultReg, Shl);2239      ResultReg = NextResult;2240    }2241 2242    if (WideSize > DstSize)2243      MIRBuilder.buildTrunc(DstReg, ResultReg);2244    else if (DstTy.isPointer())2245      MIRBuilder.buildIntToPtr(DstReg, ResultReg);2246 2247    MI.eraseFromParent();2248    return Legalized;2249  }2250 2251  // Unmerge the original values to the GCD type, and recombine to the next2252  // multiple greater than the original type.2253  //2254  // %3:_(s12) = G_MERGE_VALUES %0:_(s4), %1:_(s4), %2:_(s4) -> s62255  // %4:_(s2), %5:_(s2) = G_UNMERGE_VALUES %02256  // %6:_(s2), %7:_(s2) = G_UNMERGE_VALUES %12257  // %8:_(s2), %9:_(s2) = G_UNMERGE_VALUES %22258  // %10:_(s6) = G_MERGE_VALUES %4, %5, %62259  // %11:_(s6) = G_MERGE_VALUES %7, %8, %92260  // %12:_(s12) = G_MERGE_VALUES %10, %112261  //2262  // Padding with undef if necessary:2263  //2264  // %2:_(s8) = G_MERGE_VALUES %0:_(s4), %1:_(s4) -> s62265  // %3:_(s2), %4:_(s2) = G_UNMERGE_VALUES %02266  // %5:_(s2), %6:_(s2) = G_UNMERGE_VALUES %12267  // %7:_(s2) = G_IMPLICIT_DEF2268  // %8:_(s6) = G_MERGE_VALUES %3, %4, %52269  // %9:_(s6) = G_MERGE_VALUES %6, %7, %72270  // %10:_(s12) = G_MERGE_VALUES %8, %92271 2272  const int GCD = std::gcd(SrcSize, WideSize);2273  LLT GCDTy = LLT::scalar(GCD);2274 2275  SmallVector<Register, 8> NewMergeRegs;2276  SmallVector<Register, 8> Unmerges;2277  LLT WideDstTy = LLT::scalar(NumMerge * WideSize);2278 2279  // Decompose the original operands if they don't evenly divide.2280  for (const MachineOperand &MO : llvm::drop_begin(MI.operands())) {2281    Register SrcReg = MO.getReg();2282    if (GCD == SrcSize) {2283      Unmerges.push_back(SrcReg);2284    } else {2285      auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);2286      for (int J = 0, JE = Unmerge->getNumOperands() - 1; J != JE; ++J)2287        Unmerges.push_back(Unmerge.getReg(J));2288    }2289  }2290 2291  // Pad with undef to the next size that is a multiple of the requested size.2292  if (static_cast<int>(Unmerges.size()) != NumMerge * WideSize) {2293    Register UndefReg = MIRBuilder.buildUndef(GCDTy).getReg(0);2294    for (int I = Unmerges.size(); I != NumMerge * WideSize; ++I)2295      Unmerges.push_back(UndefReg);2296  }2297 2298  const int PartsPerGCD = WideSize / GCD;2299 2300  // Build merges of each piece.2301  ArrayRef<Register> Slicer(Unmerges);2302  for (int I = 0; I != NumMerge; ++I, Slicer = Slicer.drop_front(PartsPerGCD)) {2303    auto Merge =2304        MIRBuilder.buildMergeLikeInstr(WideTy, Slicer.take_front(PartsPerGCD));2305    NewMergeRegs.push_back(Merge.getReg(0));2306  }2307 2308  // A truncate may be necessary if the requested type doesn't evenly divide the2309  // original result type.2310  if (DstTy.getSizeInBits() == WideDstTy.getSizeInBits()) {2311    MIRBuilder.buildMergeLikeInstr(DstReg, NewMergeRegs);2312  } else {2313    auto FinalMerge = MIRBuilder.buildMergeLikeInstr(WideDstTy, NewMergeRegs);2314    MIRBuilder.buildTrunc(DstReg, FinalMerge.getReg(0));2315  }2316 2317  MI.eraseFromParent();2318  return Legalized;2319}2320 2321LegalizerHelper::LegalizeResult2322LegalizerHelper::widenScalarUnmergeValues(MachineInstr &MI, unsigned TypeIdx,2323                                          LLT WideTy) {2324  if (TypeIdx != 0)2325    return UnableToLegalize;2326 2327  int NumDst = MI.getNumOperands() - 1;2328  Register SrcReg = MI.getOperand(NumDst).getReg();2329  LLT SrcTy = MRI.getType(SrcReg);2330  if (SrcTy.isVector())2331    return UnableToLegalize;2332 2333  Register Dst0Reg = MI.getOperand(0).getReg();2334  LLT DstTy = MRI.getType(Dst0Reg);2335  if (!DstTy.isScalar())2336    return UnableToLegalize;2337 2338  if (WideTy.getSizeInBits() >= SrcTy.getSizeInBits()) {2339    if (SrcTy.isPointer()) {2340      const DataLayout &DL = MIRBuilder.getDataLayout();2341      if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) {2342        LLVM_DEBUG(2343            dbgs() << "Not casting non-integral address space integer\n");2344        return UnableToLegalize;2345      }2346 2347      SrcTy = LLT::scalar(SrcTy.getSizeInBits());2348      SrcReg = MIRBuilder.buildPtrToInt(SrcTy, SrcReg).getReg(0);2349    }2350 2351    // Widen SrcTy to WideTy. This does not affect the result, but since the2352    // user requested this size, it is probably better handled than SrcTy and2353    // should reduce the total number of legalization artifacts.2354    if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {2355      SrcTy = WideTy;2356      SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);2357    }2358 2359    // Theres no unmerge type to target. Directly extract the bits from the2360    // source type2361    unsigned DstSize = DstTy.getSizeInBits();2362 2363    MIRBuilder.buildTrunc(Dst0Reg, SrcReg);2364    for (int I = 1; I != NumDst; ++I) {2365      auto ShiftAmt = MIRBuilder.buildConstant(SrcTy, DstSize * I);2366      auto Shr = MIRBuilder.buildLShr(SrcTy, SrcReg, ShiftAmt);2367      MIRBuilder.buildTrunc(MI.getOperand(I), Shr);2368    }2369 2370    MI.eraseFromParent();2371    return Legalized;2372  }2373 2374  // Extend the source to a wider type.2375  LLT LCMTy = getLCMType(SrcTy, WideTy);2376 2377  Register WideSrc = SrcReg;2378  if (LCMTy.getSizeInBits() != SrcTy.getSizeInBits()) {2379    // TODO: If this is an integral address space, cast to integer and anyext.2380    if (SrcTy.isPointer()) {2381      LLVM_DEBUG(dbgs() << "Widening pointer source types not implemented\n");2382      return UnableToLegalize;2383    }2384 2385    WideSrc = MIRBuilder.buildAnyExt(LCMTy, WideSrc).getReg(0);2386  }2387 2388  auto Unmerge = MIRBuilder.buildUnmerge(WideTy, WideSrc);2389 2390  // Create a sequence of unmerges and merges to the original results. Since we2391  // may have widened the source, we will need to pad the results with dead defs2392  // to cover the source register.2393  // e.g. widen s48 to s64:2394  // %1:_(s48), %2:_(s48) = G_UNMERGE_VALUES %0:_(s96)2395  //2396  // =>2397  //  %4:_(s192) = G_ANYEXT %0:_(s96)2398  //  %5:_(s64), %6, %7 = G_UNMERGE_VALUES %4 ; Requested unmerge2399  //  ; unpack to GCD type, with extra dead defs2400  //  %8:_(s16), %9, %10, %11 = G_UNMERGE_VALUES %5:_(s64)2401  //  %12:_(s16), %13, dead %14, dead %15 = G_UNMERGE_VALUES %6:_(s64)2402  //  dead %16:_(s16), dead %17, dead %18, dead %18 = G_UNMERGE_VALUES %7:_(s64)2403  //  %1:_(s48) = G_MERGE_VALUES %8:_(s16), %9, %10   ; Remerge to destination2404  //  %2:_(s48) = G_MERGE_VALUES %11:_(s16), %12, %13 ; Remerge to destination2405  const LLT GCDTy = getGCDType(WideTy, DstTy);2406  const int NumUnmerge = Unmerge->getNumOperands() - 1;2407  const int PartsPerRemerge = DstTy.getSizeInBits() / GCDTy.getSizeInBits();2408 2409  // Directly unmerge to the destination without going through a GCD type2410  // if possible2411  if (PartsPerRemerge == 1) {2412    const int PartsPerUnmerge = WideTy.getSizeInBits() / DstTy.getSizeInBits();2413 2414    for (int I = 0; I != NumUnmerge; ++I) {2415      auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);2416 2417      for (int J = 0; J != PartsPerUnmerge; ++J) {2418        int Idx = I * PartsPerUnmerge + J;2419        if (Idx < NumDst)2420          MIB.addDef(MI.getOperand(Idx).getReg());2421        else {2422          // Create dead def for excess components.2423          MIB.addDef(MRI.createGenericVirtualRegister(DstTy));2424        }2425      }2426 2427      MIB.addUse(Unmerge.getReg(I));2428    }2429  } else {2430    SmallVector<Register, 16> Parts;2431    for (int J = 0; J != NumUnmerge; ++J)2432      extractGCDType(Parts, GCDTy, Unmerge.getReg(J));2433 2434    SmallVector<Register, 8> RemergeParts;2435    for (int I = 0; I != NumDst; ++I) {2436      for (int J = 0; J < PartsPerRemerge; ++J) {2437        const int Idx = I * PartsPerRemerge + J;2438        RemergeParts.emplace_back(Parts[Idx]);2439      }2440 2441      MIRBuilder.buildMergeLikeInstr(MI.getOperand(I).getReg(), RemergeParts);2442      RemergeParts.clear();2443    }2444  }2445 2446  MI.eraseFromParent();2447  return Legalized;2448}2449 2450LegalizerHelper::LegalizeResult2451LegalizerHelper::widenScalarExtract(MachineInstr &MI, unsigned TypeIdx,2452                                    LLT WideTy) {2453  auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();2454  unsigned Offset = MI.getOperand(2).getImm();2455 2456  if (TypeIdx == 0) {2457    if (SrcTy.isVector() || DstTy.isVector())2458      return UnableToLegalize;2459 2460    SrcOp Src(SrcReg);2461    if (SrcTy.isPointer()) {2462      // Extracts from pointers can be handled only if they are really just2463      // simple integers.2464      const DataLayout &DL = MIRBuilder.getDataLayout();2465      if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace()))2466        return UnableToLegalize;2467 2468      LLT SrcAsIntTy = LLT::scalar(SrcTy.getSizeInBits());2469      Src = MIRBuilder.buildPtrToInt(SrcAsIntTy, Src);2470      SrcTy = SrcAsIntTy;2471    }2472 2473    if (DstTy.isPointer())2474      return UnableToLegalize;2475 2476    if (Offset == 0) {2477      // Avoid a shift in the degenerate case.2478      MIRBuilder.buildTrunc(DstReg,2479                            MIRBuilder.buildAnyExtOrTrunc(WideTy, Src));2480      MI.eraseFromParent();2481      return Legalized;2482    }2483 2484    // Do a shift in the source type.2485    LLT ShiftTy = SrcTy;2486    if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {2487      Src = MIRBuilder.buildAnyExt(WideTy, Src);2488      ShiftTy = WideTy;2489    }2490 2491    auto LShr = MIRBuilder.buildLShr(2492      ShiftTy, Src, MIRBuilder.buildConstant(ShiftTy, Offset));2493    MIRBuilder.buildTrunc(DstReg, LShr);2494    MI.eraseFromParent();2495    return Legalized;2496  }2497 2498  if (SrcTy.isScalar()) {2499    Observer.changingInstr(MI);2500    widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);2501    Observer.changedInstr(MI);2502    return Legalized;2503  }2504 2505  if (!SrcTy.isVector())2506    return UnableToLegalize;2507 2508  if (DstTy != SrcTy.getElementType())2509    return UnableToLegalize;2510 2511  if (Offset % SrcTy.getScalarSizeInBits() != 0)2512    return UnableToLegalize;2513 2514  Observer.changingInstr(MI);2515  widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);2516 2517  MI.getOperand(2).setImm((WideTy.getSizeInBits() / SrcTy.getSizeInBits()) *2518                          Offset);2519  widenScalarDst(MI, WideTy.getScalarType(), 0);2520  Observer.changedInstr(MI);2521  return Legalized;2522}2523 2524LegalizerHelper::LegalizeResult2525LegalizerHelper::widenScalarInsert(MachineInstr &MI, unsigned TypeIdx,2526                                   LLT WideTy) {2527  if (TypeIdx != 0 || WideTy.isVector())2528    return UnableToLegalize;2529  Observer.changingInstr(MI);2530  widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);2531  widenScalarDst(MI, WideTy);2532  Observer.changedInstr(MI);2533  return Legalized;2534}2535 2536LegalizerHelper::LegalizeResult2537LegalizerHelper::widenScalarAddSubOverflow(MachineInstr &MI, unsigned TypeIdx,2538                                           LLT WideTy) {2539  unsigned Opcode;2540  unsigned ExtOpcode;2541  std::optional<Register> CarryIn;2542  switch (MI.getOpcode()) {2543  default:2544    llvm_unreachable("Unexpected opcode!");2545  case TargetOpcode::G_SADDO:2546    Opcode = TargetOpcode::G_ADD;2547    ExtOpcode = TargetOpcode::G_SEXT;2548    break;2549  case TargetOpcode::G_SSUBO:2550    Opcode = TargetOpcode::G_SUB;2551    ExtOpcode = TargetOpcode::G_SEXT;2552    break;2553  case TargetOpcode::G_UADDO:2554    Opcode = TargetOpcode::G_ADD;2555    ExtOpcode = TargetOpcode::G_ZEXT;2556    break;2557  case TargetOpcode::G_USUBO:2558    Opcode = TargetOpcode::G_SUB;2559    ExtOpcode = TargetOpcode::G_ZEXT;2560    break;2561  case TargetOpcode::G_SADDE:2562    Opcode = TargetOpcode::G_UADDE;2563    ExtOpcode = TargetOpcode::G_SEXT;2564    CarryIn = MI.getOperand(4).getReg();2565    break;2566  case TargetOpcode::G_SSUBE:2567    Opcode = TargetOpcode::G_USUBE;2568    ExtOpcode = TargetOpcode::G_SEXT;2569    CarryIn = MI.getOperand(4).getReg();2570    break;2571  case TargetOpcode::G_UADDE:2572    Opcode = TargetOpcode::G_UADDE;2573    ExtOpcode = TargetOpcode::G_ZEXT;2574    CarryIn = MI.getOperand(4).getReg();2575    break;2576  case TargetOpcode::G_USUBE:2577    Opcode = TargetOpcode::G_USUBE;2578    ExtOpcode = TargetOpcode::G_ZEXT;2579    CarryIn = MI.getOperand(4).getReg();2580    break;2581  }2582 2583  if (TypeIdx == 1) {2584    unsigned BoolExtOp = MIRBuilder.getBoolExtOp(WideTy.isVector(), false);2585 2586    Observer.changingInstr(MI);2587    if (CarryIn)2588      widenScalarSrc(MI, WideTy, 4, BoolExtOp);2589    widenScalarDst(MI, WideTy, 1);2590 2591    Observer.changedInstr(MI);2592    return Legalized;2593  }2594 2595  auto LHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(2)});2596  auto RHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(3)});2597  // Do the arithmetic in the larger type.2598  Register NewOp;2599  if (CarryIn) {2600    LLT CarryOutTy = MRI.getType(MI.getOperand(1).getReg());2601    NewOp = MIRBuilder2602                .buildInstr(Opcode, {WideTy, CarryOutTy},2603                            {LHSExt, RHSExt, *CarryIn})2604                .getReg(0);2605  } else {2606    NewOp = MIRBuilder.buildInstr(Opcode, {WideTy}, {LHSExt, RHSExt}).getReg(0);2607  }2608  LLT OrigTy = MRI.getType(MI.getOperand(0).getReg());2609  auto TruncOp = MIRBuilder.buildTrunc(OrigTy, NewOp);2610  auto ExtOp = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {TruncOp});2611  // There is no overflow if the ExtOp is the same as NewOp.2612  MIRBuilder.buildICmp(CmpInst::ICMP_NE, MI.getOperand(1), NewOp, ExtOp);2613  // Now trunc the NewOp to the original result.2614  MIRBuilder.buildTrunc(MI.getOperand(0), NewOp);2615  MI.eraseFromParent();2616  return Legalized;2617}2618 2619LegalizerHelper::LegalizeResult2620LegalizerHelper::widenScalarAddSubShlSat(MachineInstr &MI, unsigned TypeIdx,2621                                         LLT WideTy) {2622  bool IsSigned = MI.getOpcode() == TargetOpcode::G_SADDSAT ||2623                  MI.getOpcode() == TargetOpcode::G_SSUBSAT ||2624                  MI.getOpcode() == TargetOpcode::G_SSHLSAT;2625  bool IsShift = MI.getOpcode() == TargetOpcode::G_SSHLSAT ||2626                 MI.getOpcode() == TargetOpcode::G_USHLSAT;2627  // We can convert this to:2628  //   1. Any extend iN to iM2629  //   2. SHL by M-N2630  //   3. [US][ADD|SUB|SHL]SAT2631  //   4. L/ASHR by M-N2632  //2633  // It may be more efficient to lower this to a min and a max operation in2634  // the higher precision arithmetic if the promoted operation isn't legal,2635  // but this decision is up to the target's lowering request.2636  Register DstReg = MI.getOperand(0).getReg();2637 2638  unsigned NewBits = WideTy.getScalarSizeInBits();2639  unsigned SHLAmount = NewBits - MRI.getType(DstReg).getScalarSizeInBits();2640 2641  // Shifts must zero-extend the RHS to preserve the unsigned quantity, and2642  // must not left shift the RHS to preserve the shift amount.2643  auto LHS = MIRBuilder.buildAnyExt(WideTy, MI.getOperand(1));2644  auto RHS = IsShift ? MIRBuilder.buildZExt(WideTy, MI.getOperand(2))2645                     : MIRBuilder.buildAnyExt(WideTy, MI.getOperand(2));2646  auto ShiftK = MIRBuilder.buildConstant(WideTy, SHLAmount);2647  auto ShiftL = MIRBuilder.buildShl(WideTy, LHS, ShiftK);2648  auto ShiftR = IsShift ? RHS : MIRBuilder.buildShl(WideTy, RHS, ShiftK);2649 2650  auto WideInst = MIRBuilder.buildInstr(MI.getOpcode(), {WideTy},2651                                        {ShiftL, ShiftR}, MI.getFlags());2652 2653  // Use a shift that will preserve the number of sign bits when the trunc is2654  // folded away.2655  auto Result = IsSigned ? MIRBuilder.buildAShr(WideTy, WideInst, ShiftK)2656                         : MIRBuilder.buildLShr(WideTy, WideInst, ShiftK);2657 2658  MIRBuilder.buildTrunc(DstReg, Result);2659  MI.eraseFromParent();2660  return Legalized;2661}2662 2663LegalizerHelper::LegalizeResult2664LegalizerHelper::widenScalarMulo(MachineInstr &MI, unsigned TypeIdx,2665                                 LLT WideTy) {2666  if (TypeIdx == 1) {2667    Observer.changingInstr(MI);2668    widenScalarDst(MI, WideTy, 1);2669    Observer.changedInstr(MI);2670    return Legalized;2671  }2672 2673  bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULO;2674  auto [Result, OriginalOverflow, LHS, RHS] = MI.getFirst4Regs();2675  LLT SrcTy = MRI.getType(LHS);2676  LLT OverflowTy = MRI.getType(OriginalOverflow);2677  unsigned SrcBitWidth = SrcTy.getScalarSizeInBits();2678 2679  // To determine if the result overflowed in the larger type, we extend the2680  // input to the larger type, do the multiply (checking if it overflows),2681  // then also check the high bits of the result to see if overflow happened2682  // there.2683  unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;2684  auto LeftOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {LHS});2685  auto RightOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {RHS});2686 2687  // Multiplication cannot overflow if the WideTy is >= 2 * original width,2688  // so we don't need to check the overflow result of larger type Mulo.2689  bool WideMulCanOverflow = WideTy.getScalarSizeInBits() < 2 * SrcBitWidth;2690 2691  unsigned MulOpc =2692      WideMulCanOverflow ? MI.getOpcode() : (unsigned)TargetOpcode::G_MUL;2693 2694  MachineInstrBuilder Mulo;2695  if (WideMulCanOverflow)2696    Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy, OverflowTy},2697                                 {LeftOperand, RightOperand});2698  else2699    Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy}, {LeftOperand, RightOperand});2700 2701  auto Mul = Mulo->getOperand(0);2702  MIRBuilder.buildTrunc(Result, Mul);2703 2704  MachineInstrBuilder ExtResult;2705  // Overflow occurred if it occurred in the larger type, or if the high part2706  // of the result does not zero/sign-extend the low part.  Check this second2707  // possibility first.2708  if (IsSigned) {2709    // For signed, overflow occurred when the high part does not sign-extend2710    // the low part.2711    ExtResult = MIRBuilder.buildSExtInReg(WideTy, Mul, SrcBitWidth);2712  } else {2713    // Unsigned overflow occurred when the high part does not zero-extend the2714    // low part.2715    ExtResult = MIRBuilder.buildZExtInReg(WideTy, Mul, SrcBitWidth);2716  }2717 2718  if (WideMulCanOverflow) {2719    auto Overflow =2720        MIRBuilder.buildICmp(CmpInst::ICMP_NE, OverflowTy, Mul, ExtResult);2721    // Finally check if the multiplication in the larger type itself overflowed.2722    MIRBuilder.buildOr(OriginalOverflow, Mulo->getOperand(1), Overflow);2723  } else {2724    MIRBuilder.buildICmp(CmpInst::ICMP_NE, OriginalOverflow, Mul, ExtResult);2725  }2726  MI.eraseFromParent();2727  return Legalized;2728}2729 2730LegalizerHelper::LegalizeResult2731LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {2732  unsigned Opcode = MI.getOpcode();2733  switch (Opcode) {2734  default:2735    return UnableToLegalize;2736  case TargetOpcode::G_ATOMICRMW_XCHG:2737  case TargetOpcode::G_ATOMICRMW_ADD:2738  case TargetOpcode::G_ATOMICRMW_SUB:2739  case TargetOpcode::G_ATOMICRMW_AND:2740  case TargetOpcode::G_ATOMICRMW_OR:2741  case TargetOpcode::G_ATOMICRMW_XOR:2742  case TargetOpcode::G_ATOMICRMW_MIN:2743  case TargetOpcode::G_ATOMICRMW_MAX:2744  case TargetOpcode::G_ATOMICRMW_UMIN:2745  case TargetOpcode::G_ATOMICRMW_UMAX:2746    assert(TypeIdx == 0 && "atomicrmw with second scalar type");2747    Observer.changingInstr(MI);2748    widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);2749    widenScalarDst(MI, WideTy, 0);2750    Observer.changedInstr(MI);2751    return Legalized;2752  case TargetOpcode::G_ATOMIC_CMPXCHG:2753    assert(TypeIdx == 0 && "G_ATOMIC_CMPXCHG with second scalar type");2754    Observer.changingInstr(MI);2755    widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);2756    widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);2757    widenScalarDst(MI, WideTy, 0);2758    Observer.changedInstr(MI);2759    return Legalized;2760  case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS:2761    if (TypeIdx == 0) {2762      Observer.changingInstr(MI);2763      widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);2764      widenScalarSrc(MI, WideTy, 4, TargetOpcode::G_ANYEXT);2765      widenScalarDst(MI, WideTy, 0);2766      Observer.changedInstr(MI);2767      return Legalized;2768    }2769    assert(TypeIdx == 1 &&2770           "G_ATOMIC_CMPXCHG_WITH_SUCCESS with third scalar type");2771    Observer.changingInstr(MI);2772    widenScalarDst(MI, WideTy, 1);2773    Observer.changedInstr(MI);2774    return Legalized;2775  case TargetOpcode::G_EXTRACT:2776    return widenScalarExtract(MI, TypeIdx, WideTy);2777  case TargetOpcode::G_INSERT:2778    return widenScalarInsert(MI, TypeIdx, WideTy);2779  case TargetOpcode::G_MERGE_VALUES:2780    return widenScalarMergeValues(MI, TypeIdx, WideTy);2781  case TargetOpcode::G_UNMERGE_VALUES:2782    return widenScalarUnmergeValues(MI, TypeIdx, WideTy);2783  case TargetOpcode::G_SADDO:2784  case TargetOpcode::G_SSUBO:2785  case TargetOpcode::G_UADDO:2786  case TargetOpcode::G_USUBO:2787  case TargetOpcode::G_SADDE:2788  case TargetOpcode::G_SSUBE:2789  case TargetOpcode::G_UADDE:2790  case TargetOpcode::G_USUBE:2791    return widenScalarAddSubOverflow(MI, TypeIdx, WideTy);2792  case TargetOpcode::G_UMULO:2793  case TargetOpcode::G_SMULO:2794    return widenScalarMulo(MI, TypeIdx, WideTy);2795  case TargetOpcode::G_SADDSAT:2796  case TargetOpcode::G_SSUBSAT:2797  case TargetOpcode::G_SSHLSAT:2798  case TargetOpcode::G_UADDSAT:2799  case TargetOpcode::G_USUBSAT:2800  case TargetOpcode::G_USHLSAT:2801    return widenScalarAddSubShlSat(MI, TypeIdx, WideTy);2802  case TargetOpcode::G_CTTZ:2803  case TargetOpcode::G_CTTZ_ZERO_UNDEF:2804  case TargetOpcode::G_CTLZ:2805  case TargetOpcode::G_CTLZ_ZERO_UNDEF:2806  case TargetOpcode::G_CTPOP: {2807    if (TypeIdx == 0) {2808      Observer.changingInstr(MI);2809      widenScalarDst(MI, WideTy, 0);2810      Observer.changedInstr(MI);2811      return Legalized;2812    }2813 2814    Register SrcReg = MI.getOperand(1).getReg();2815 2816    // First extend the input.2817    unsigned ExtOpc = Opcode == TargetOpcode::G_CTTZ ||2818                              Opcode == TargetOpcode::G_CTTZ_ZERO_UNDEF2819                          ? TargetOpcode::G_ANYEXT2820                          : TargetOpcode::G_ZEXT;2821    auto MIBSrc = MIRBuilder.buildInstr(ExtOpc, {WideTy}, {SrcReg});2822    LLT CurTy = MRI.getType(SrcReg);2823    unsigned NewOpc = Opcode;2824    if (NewOpc == TargetOpcode::G_CTTZ) {2825      // The count is the same in the larger type except if the original2826      // value was zero.  This can be handled by setting the bit just off2827      // the top of the original type.2828      auto TopBit =2829          APInt::getOneBitSet(WideTy.getSizeInBits(), CurTy.getSizeInBits());2830      MIBSrc = MIRBuilder.buildOr(2831        WideTy, MIBSrc, MIRBuilder.buildConstant(WideTy, TopBit));2832      // Now we know the operand is non-zero, use the more relaxed opcode.2833      NewOpc = TargetOpcode::G_CTTZ_ZERO_UNDEF;2834    }2835 2836    unsigned SizeDiff = WideTy.getSizeInBits() - CurTy.getSizeInBits();2837 2838    if (Opcode == TargetOpcode::G_CTLZ_ZERO_UNDEF) {2839      // An optimization where the result is the CTLZ after the left shift by2840      // (Difference in widety and current ty), that is,2841      // MIBSrc = MIBSrc << (sizeinbits(WideTy) - sizeinbits(CurTy))2842      // Result = ctlz MIBSrc2843      MIBSrc = MIRBuilder.buildShl(WideTy, MIBSrc,2844                                   MIRBuilder.buildConstant(WideTy, SizeDiff));2845    }2846 2847    // Perform the operation at the larger size.2848    auto MIBNewOp = MIRBuilder.buildInstr(NewOpc, {WideTy}, {MIBSrc});2849    // This is already the correct result for CTPOP and CTTZs2850    if (Opcode == TargetOpcode::G_CTLZ) {2851      // The correct result is NewOp - (Difference in widety and current ty).2852      MIBNewOp = MIRBuilder.buildSub(2853          WideTy, MIBNewOp, MIRBuilder.buildConstant(WideTy, SizeDiff));2854    }2855 2856    MIRBuilder.buildZExtOrTrunc(MI.getOperand(0), MIBNewOp);2857    MI.eraseFromParent();2858    return Legalized;2859  }2860  case TargetOpcode::G_BSWAP: {2861    Observer.changingInstr(MI);2862    Register DstReg = MI.getOperand(0).getReg();2863 2864    Register ShrReg = MRI.createGenericVirtualRegister(WideTy);2865    Register DstExt = MRI.createGenericVirtualRegister(WideTy);2866    Register ShiftAmtReg = MRI.createGenericVirtualRegister(WideTy);2867    widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);2868 2869    MI.getOperand(0).setReg(DstExt);2870 2871    MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());2872 2873    LLT Ty = MRI.getType(DstReg);2874    unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();2875    MIRBuilder.buildConstant(ShiftAmtReg, DiffBits);2876    MIRBuilder.buildLShr(ShrReg, DstExt, ShiftAmtReg);2877 2878    MIRBuilder.buildTrunc(DstReg, ShrReg);2879    Observer.changedInstr(MI);2880    return Legalized;2881  }2882  case TargetOpcode::G_BITREVERSE: {2883    Observer.changingInstr(MI);2884 2885    Register DstReg = MI.getOperand(0).getReg();2886    LLT Ty = MRI.getType(DstReg);2887    unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();2888 2889    Register DstExt = MRI.createGenericVirtualRegister(WideTy);2890    widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);2891    MI.getOperand(0).setReg(DstExt);2892    MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());2893 2894    auto ShiftAmt = MIRBuilder.buildConstant(WideTy, DiffBits);2895    auto Shift = MIRBuilder.buildLShr(WideTy, DstExt, ShiftAmt);2896    MIRBuilder.buildTrunc(DstReg, Shift);2897    Observer.changedInstr(MI);2898    return Legalized;2899  }2900  case TargetOpcode::G_FREEZE:2901  case TargetOpcode::G_CONSTANT_FOLD_BARRIER:2902    Observer.changingInstr(MI);2903    widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);2904    widenScalarDst(MI, WideTy);2905    Observer.changedInstr(MI);2906    return Legalized;2907 2908  case TargetOpcode::G_ABS:2909    Observer.changingInstr(MI);2910    widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);2911    widenScalarDst(MI, WideTy);2912    Observer.changedInstr(MI);2913    return Legalized;2914 2915  case TargetOpcode::G_ADD:2916  case TargetOpcode::G_AND:2917  case TargetOpcode::G_MUL:2918  case TargetOpcode::G_OR:2919  case TargetOpcode::G_XOR:2920  case TargetOpcode::G_SUB:2921  case TargetOpcode::G_SHUFFLE_VECTOR:2922    // Perform operation at larger width (any extension is fines here, high bits2923    // don't affect the result) and then truncate the result back to the2924    // original type.2925    Observer.changingInstr(MI);2926    widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);2927    widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);2928    widenScalarDst(MI, WideTy);2929    Observer.changedInstr(MI);2930    return Legalized;2931 2932  case TargetOpcode::G_SBFX:2933  case TargetOpcode::G_UBFX:2934    Observer.changingInstr(MI);2935 2936    if (TypeIdx == 0) {2937      widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);2938      widenScalarDst(MI, WideTy);2939    } else {2940      widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);2941      widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);2942    }2943 2944    Observer.changedInstr(MI);2945    return Legalized;2946 2947  case TargetOpcode::G_SHL:2948    Observer.changingInstr(MI);2949 2950    if (TypeIdx == 0) {2951      widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);2952      widenScalarDst(MI, WideTy);2953    } else {2954      assert(TypeIdx == 1);2955      // The "number of bits to shift" operand must preserve its value as an2956      // unsigned integer:2957      widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);2958    }2959 2960    Observer.changedInstr(MI);2961    return Legalized;2962 2963  case TargetOpcode::G_ROTR:2964  case TargetOpcode::G_ROTL:2965    if (TypeIdx != 1)2966      return UnableToLegalize;2967 2968    Observer.changingInstr(MI);2969    widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);2970    Observer.changedInstr(MI);2971    return Legalized;2972 2973  case TargetOpcode::G_SDIV:2974  case TargetOpcode::G_SREM:2975  case TargetOpcode::G_SMIN:2976  case TargetOpcode::G_SMAX:2977  case TargetOpcode::G_ABDS:2978    Observer.changingInstr(MI);2979    widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);2980    widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);2981    widenScalarDst(MI, WideTy);2982    Observer.changedInstr(MI);2983    return Legalized;2984 2985  case TargetOpcode::G_SDIVREM:2986    Observer.changingInstr(MI);2987    widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);2988    widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_SEXT);2989    widenScalarDst(MI, WideTy);2990    MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());2991    widenScalarDst(MI, WideTy, 1);2992    Observer.changedInstr(MI);2993    return Legalized;2994 2995  case TargetOpcode::G_ASHR:2996  case TargetOpcode::G_LSHR:2997    Observer.changingInstr(MI);2998 2999    if (TypeIdx == 0) {3000      unsigned CvtOp = Opcode == TargetOpcode::G_ASHR ? TargetOpcode::G_SEXT3001                                                      : TargetOpcode::G_ZEXT;3002 3003      widenScalarSrc(MI, WideTy, 1, CvtOp);3004      widenScalarDst(MI, WideTy);3005    } else {3006      assert(TypeIdx == 1);3007      // The "number of bits to shift" operand must preserve its value as an3008      // unsigned integer:3009      widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);3010    }3011 3012    Observer.changedInstr(MI);3013    return Legalized;3014  case TargetOpcode::G_UDIV:3015  case TargetOpcode::G_UREM:3016  case TargetOpcode::G_ABDU:3017    Observer.changingInstr(MI);3018    widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);3019    widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);3020    widenScalarDst(MI, WideTy);3021    Observer.changedInstr(MI);3022    return Legalized;3023  case TargetOpcode::G_UDIVREM:3024    Observer.changingInstr(MI);3025    widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);3026    widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);3027    widenScalarDst(MI, WideTy);3028    MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());3029    widenScalarDst(MI, WideTy, 1);3030    Observer.changedInstr(MI);3031    return Legalized;3032  case TargetOpcode::G_UMIN:3033  case TargetOpcode::G_UMAX: {3034    LLT Ty = MRI.getType(MI.getOperand(0).getReg());3035 3036    auto &Ctx = MIRBuilder.getMF().getFunction().getContext();3037    unsigned ExtOpc =3038        TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(Ty, Ctx),3039                                  getApproximateEVTForLLT(WideTy, Ctx))3040            ? TargetOpcode::G_SEXT3041            : TargetOpcode::G_ZEXT;3042 3043    Observer.changingInstr(MI);3044    widenScalarSrc(MI, WideTy, 1, ExtOpc);3045    widenScalarSrc(MI, WideTy, 2, ExtOpc);3046    widenScalarDst(MI, WideTy);3047    Observer.changedInstr(MI);3048    return Legalized;3049  }3050 3051  case TargetOpcode::G_SELECT:3052    Observer.changingInstr(MI);3053    if (TypeIdx == 0) {3054      // Perform operation at larger width (any extension is fine here, high3055      // bits don't affect the result) and then truncate the result back to the3056      // original type.3057      widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);3058      widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);3059      widenScalarDst(MI, WideTy);3060    } else {3061      bool IsVec = MRI.getType(MI.getOperand(1).getReg()).isVector();3062      // Explicit extension is required here since high bits affect the result.3063      widenScalarSrc(MI, WideTy, 1, MIRBuilder.getBoolExtOp(IsVec, false));3064    }3065    Observer.changedInstr(MI);3066    return Legalized;3067 3068  case TargetOpcode::G_FPEXT:3069    if (TypeIdx != 1)3070      return UnableToLegalize;3071 3072    Observer.changingInstr(MI);3073    widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_FPEXT);3074    Observer.changedInstr(MI);3075    return Legalized;3076  case TargetOpcode::G_FPTOSI:3077  case TargetOpcode::G_FPTOUI:3078  case TargetOpcode::G_INTRINSIC_LRINT:3079  case TargetOpcode::G_INTRINSIC_LLRINT:3080  case TargetOpcode::G_IS_FPCLASS:3081    Observer.changingInstr(MI);3082 3083    if (TypeIdx == 0)3084      widenScalarDst(MI, WideTy);3085    else3086      widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_FPEXT);3087 3088    Observer.changedInstr(MI);3089    return Legalized;3090  case TargetOpcode::G_SITOFP:3091    Observer.changingInstr(MI);3092 3093    if (TypeIdx == 0)3094      widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);3095    else3096      widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);3097 3098    Observer.changedInstr(MI);3099    return Legalized;3100  case TargetOpcode::G_UITOFP:3101    Observer.changingInstr(MI);3102 3103    if (TypeIdx == 0)3104      widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);3105    else3106      widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);3107 3108    Observer.changedInstr(MI);3109    return Legalized;3110  case TargetOpcode::G_FPTOSI_SAT:3111  case TargetOpcode::G_FPTOUI_SAT:3112    Observer.changingInstr(MI);3113 3114    if (TypeIdx == 0) {3115      Register OldDst = MI.getOperand(0).getReg();3116      LLT Ty = MRI.getType(OldDst);3117      Register ExtReg = MRI.createGenericVirtualRegister(WideTy);3118      Register NewDst;3119      MI.getOperand(0).setReg(ExtReg);3120      uint64_t ShortBits = Ty.getScalarSizeInBits();3121      uint64_t WideBits = WideTy.getScalarSizeInBits();3122      MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());3123      if (Opcode == TargetOpcode::G_FPTOSI_SAT) {3124        // z = i16 fptosi_sat(a)3125        // ->3126        // x = i32 fptosi_sat(a)3127        // y = smin(x, 32767)3128        // z = smax(y, -32768)3129        auto MaxVal = MIRBuilder.buildConstant(3130            WideTy, APInt::getSignedMaxValue(ShortBits).sext(WideBits));3131        auto MinVal = MIRBuilder.buildConstant(3132            WideTy, APInt::getSignedMinValue(ShortBits).sext(WideBits));3133        Register MidReg =3134            MIRBuilder.buildSMin(WideTy, ExtReg, MaxVal).getReg(0);3135        NewDst = MIRBuilder.buildSMax(WideTy, MidReg, MinVal).getReg(0);3136      } else {3137        // z = i16 fptoui_sat(a)3138        // ->3139        // x = i32 fptoui_sat(a)3140        // y = smin(x, 65535)3141        auto MaxVal = MIRBuilder.buildConstant(3142            WideTy, APInt::getAllOnes(ShortBits).zext(WideBits));3143        NewDst = MIRBuilder.buildUMin(WideTy, ExtReg, MaxVal).getReg(0);3144      }3145      MIRBuilder.buildTrunc(OldDst, NewDst);3146    } else3147      widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_FPEXT);3148 3149    Observer.changedInstr(MI);3150    return Legalized;3151  case TargetOpcode::G_LOAD:3152  case TargetOpcode::G_SEXTLOAD:3153  case TargetOpcode::G_ZEXTLOAD:3154    Observer.changingInstr(MI);3155    widenScalarDst(MI, WideTy);3156    Observer.changedInstr(MI);3157    return Legalized;3158 3159  case TargetOpcode::G_STORE: {3160    if (TypeIdx != 0)3161      return UnableToLegalize;3162 3163    LLT Ty = MRI.getType(MI.getOperand(0).getReg());3164    assert(!Ty.isPointerOrPointerVector() && "Can't widen type");3165    if (!Ty.isScalar()) {3166      // We need to widen the vector element type.3167      Observer.changingInstr(MI);3168      widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ANYEXT);3169      // We also need to adjust the MMO to turn this into a truncating store.3170      MachineMemOperand &MMO = **MI.memoperands_begin();3171      MachineFunction &MF = MIRBuilder.getMF();3172      auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), Ty);3173      MI.setMemRefs(MF, {NewMMO});3174      Observer.changedInstr(MI);3175      return Legalized;3176    }3177 3178    Observer.changingInstr(MI);3179 3180    unsigned ExtType = Ty.getScalarSizeInBits() == 1 ?3181      TargetOpcode::G_ZEXT : TargetOpcode::G_ANYEXT;3182    widenScalarSrc(MI, WideTy, 0, ExtType);3183 3184    Observer.changedInstr(MI);3185    return Legalized;3186  }3187  case TargetOpcode::G_CONSTANT: {3188    MachineOperand &SrcMO = MI.getOperand(1);3189    LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();3190    unsigned ExtOpc = LI.getExtOpcodeForWideningConstant(3191        MRI.getType(MI.getOperand(0).getReg()));3192    assert((ExtOpc == TargetOpcode::G_ZEXT || ExtOpc == TargetOpcode::G_SEXT ||3193            ExtOpc == TargetOpcode::G_ANYEXT) &&3194           "Illegal Extend");3195    const APInt &SrcVal = SrcMO.getCImm()->getValue();3196    const APInt &Val = (ExtOpc == TargetOpcode::G_SEXT)3197                           ? SrcVal.sext(WideTy.getSizeInBits())3198                           : SrcVal.zext(WideTy.getSizeInBits());3199    Observer.changingInstr(MI);3200    SrcMO.setCImm(ConstantInt::get(Ctx, Val));3201 3202    widenScalarDst(MI, WideTy);3203    Observer.changedInstr(MI);3204    return Legalized;3205  }3206  case TargetOpcode::G_FCONSTANT: {3207    // To avoid changing the bits of the constant due to extension to a larger3208    // type and then using G_FPTRUNC, we simply convert to a G_CONSTANT.3209    MachineOperand &SrcMO = MI.getOperand(1);3210    APInt Val = SrcMO.getFPImm()->getValueAPF().bitcastToAPInt();3211    MIRBuilder.setInstrAndDebugLoc(MI);3212    auto IntCst = MIRBuilder.buildConstant(MI.getOperand(0).getReg(), Val);3213    widenScalarDst(*IntCst, WideTy, 0, TargetOpcode::G_TRUNC);3214    MI.eraseFromParent();3215    return Legalized;3216  }3217  case TargetOpcode::G_IMPLICIT_DEF: {3218    Observer.changingInstr(MI);3219    widenScalarDst(MI, WideTy);3220    Observer.changedInstr(MI);3221    return Legalized;3222  }3223  case TargetOpcode::G_BRCOND:3224    Observer.changingInstr(MI);3225    widenScalarSrc(MI, WideTy, 0, MIRBuilder.getBoolExtOp(false, false));3226    Observer.changedInstr(MI);3227    return Legalized;3228 3229  case TargetOpcode::G_FCMP:3230    Observer.changingInstr(MI);3231    if (TypeIdx == 0)3232      widenScalarDst(MI, WideTy);3233    else {3234      widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_FPEXT);3235      widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_FPEXT);3236    }3237    Observer.changedInstr(MI);3238    return Legalized;3239 3240  case TargetOpcode::G_ICMP:3241    Observer.changingInstr(MI);3242    if (TypeIdx == 0)3243      widenScalarDst(MI, WideTy);3244    else {3245      LLT SrcTy = MRI.getType(MI.getOperand(2).getReg());3246      CmpInst::Predicate Pred =3247          static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());3248 3249      auto &Ctx = MIRBuilder.getMF().getFunction().getContext();3250      unsigned ExtOpcode =3251          (CmpInst::isSigned(Pred) ||3252           TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(SrcTy, Ctx),3253                                     getApproximateEVTForLLT(WideTy, Ctx)))3254              ? TargetOpcode::G_SEXT3255              : TargetOpcode::G_ZEXT;3256      widenScalarSrc(MI, WideTy, 2, ExtOpcode);3257      widenScalarSrc(MI, WideTy, 3, ExtOpcode);3258    }3259    Observer.changedInstr(MI);3260    return Legalized;3261 3262  case TargetOpcode::G_PTR_ADD:3263    assert(TypeIdx == 1 && "unable to legalize pointer of G_PTR_ADD");3264    Observer.changingInstr(MI);3265    widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);3266    Observer.changedInstr(MI);3267    return Legalized;3268 3269  case TargetOpcode::G_PHI: {3270    assert(TypeIdx == 0 && "Expecting only Idx 0");3271 3272    Observer.changingInstr(MI);3273    for (unsigned I = 1; I < MI.getNumOperands(); I += 2) {3274      MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();3275      MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());3276      widenScalarSrc(MI, WideTy, I, TargetOpcode::G_ANYEXT);3277    }3278 3279    MachineBasicBlock &MBB = *MI.getParent();3280    MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());3281    widenScalarDst(MI, WideTy);3282    Observer.changedInstr(MI);3283    return Legalized;3284  }3285  case TargetOpcode::G_EXTRACT_VECTOR_ELT: {3286    if (TypeIdx == 0) {3287      Register VecReg = MI.getOperand(1).getReg();3288      LLT VecTy = MRI.getType(VecReg);3289      Observer.changingInstr(MI);3290 3291      widenScalarSrc(3292          MI, LLT::vector(VecTy.getElementCount(), WideTy.getSizeInBits()), 1,3293          TargetOpcode::G_ANYEXT);3294 3295      widenScalarDst(MI, WideTy, 0);3296      Observer.changedInstr(MI);3297      return Legalized;3298    }3299 3300    if (TypeIdx != 2)3301      return UnableToLegalize;3302    Observer.changingInstr(MI);3303    widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);3304    Observer.changedInstr(MI);3305    return Legalized;3306  }3307  case TargetOpcode::G_INSERT_VECTOR_ELT: {3308    if (TypeIdx == 0) {3309      Observer.changingInstr(MI);3310      const LLT WideEltTy = WideTy.getElementType();3311 3312      widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);3313      widenScalarSrc(MI, WideEltTy, 2, TargetOpcode::G_ANYEXT);3314      widenScalarDst(MI, WideTy, 0);3315      Observer.changedInstr(MI);3316      return Legalized;3317    }3318 3319    if (TypeIdx == 1) {3320      Observer.changingInstr(MI);3321 3322      Register VecReg = MI.getOperand(1).getReg();3323      LLT VecTy = MRI.getType(VecReg);3324      LLT WideVecTy = LLT::vector(VecTy.getElementCount(), WideTy);3325 3326      widenScalarSrc(MI, WideVecTy, 1, TargetOpcode::G_ANYEXT);3327      widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);3328      widenScalarDst(MI, WideVecTy, 0);3329      Observer.changedInstr(MI);3330      return Legalized;3331    }3332 3333    if (TypeIdx == 2) {3334      Observer.changingInstr(MI);3335      widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);3336      Observer.changedInstr(MI);3337      return Legalized;3338    }3339 3340    return UnableToLegalize;3341  }3342  case TargetOpcode::G_FADD:3343  case TargetOpcode::G_FMUL:3344  case TargetOpcode::G_FSUB:3345  case TargetOpcode::G_FMA:3346  case TargetOpcode::G_FMAD:3347  case TargetOpcode::G_FNEG:3348  case TargetOpcode::G_FABS:3349  case TargetOpcode::G_FCANONICALIZE:3350  case TargetOpcode::G_FMINNUM:3351  case TargetOpcode::G_FMAXNUM:3352  case TargetOpcode::G_FMINNUM_IEEE:3353  case TargetOpcode::G_FMAXNUM_IEEE:3354  case TargetOpcode::G_FMINIMUM:3355  case TargetOpcode::G_FMAXIMUM:3356  case TargetOpcode::G_FMINIMUMNUM:3357  case TargetOpcode::G_FMAXIMUMNUM:3358  case TargetOpcode::G_FDIV:3359  case TargetOpcode::G_FREM:3360  case TargetOpcode::G_FCEIL:3361  case TargetOpcode::G_FFLOOR:3362  case TargetOpcode::G_FCOS:3363  case TargetOpcode::G_FSIN:3364  case TargetOpcode::G_FTAN:3365  case TargetOpcode::G_FACOS:3366  case TargetOpcode::G_FASIN:3367  case TargetOpcode::G_FATAN:3368  case TargetOpcode::G_FATAN2:3369  case TargetOpcode::G_FCOSH:3370  case TargetOpcode::G_FSINH:3371  case TargetOpcode::G_FTANH:3372  case TargetOpcode::G_FLOG10:3373  case TargetOpcode::G_FLOG:3374  case TargetOpcode::G_FLOG2:3375  case TargetOpcode::G_FRINT:3376  case TargetOpcode::G_FNEARBYINT:3377  case TargetOpcode::G_FSQRT:3378  case TargetOpcode::G_FEXP:3379  case TargetOpcode::G_FEXP2:3380  case TargetOpcode::G_FEXP10:3381  case TargetOpcode::G_FPOW:3382  case TargetOpcode::G_INTRINSIC_TRUNC:3383  case TargetOpcode::G_INTRINSIC_ROUND:3384  case TargetOpcode::G_INTRINSIC_ROUNDEVEN:3385    assert(TypeIdx == 0);3386    Observer.changingInstr(MI);3387 3388    for (unsigned I = 1, E = MI.getNumOperands(); I != E; ++I)3389      widenScalarSrc(MI, WideTy, I, TargetOpcode::G_FPEXT);3390 3391    widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);3392    Observer.changedInstr(MI);3393    return Legalized;3394  case TargetOpcode::G_FMODF: {3395    Observer.changingInstr(MI);3396    widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_FPEXT);3397 3398    widenScalarDst(MI, WideTy, 1, TargetOpcode::G_FPTRUNC);3399    MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());3400    widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);3401    Observer.changedInstr(MI);3402    return Legalized;3403  }3404  case TargetOpcode::G_FPOWI:3405  case TargetOpcode::G_FLDEXP:3406  case TargetOpcode::G_STRICT_FLDEXP: {3407    if (TypeIdx == 0) {3408      if (Opcode == TargetOpcode::G_STRICT_FLDEXP)3409        return UnableToLegalize;3410 3411      Observer.changingInstr(MI);3412      widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_FPEXT);3413      widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);3414      Observer.changedInstr(MI);3415      return Legalized;3416    }3417 3418    if (TypeIdx == 1) {3419      // For some reason SelectionDAG tries to promote to a libcall without3420      // actually changing the integer type for promotion.3421      Observer.changingInstr(MI);3422      widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);3423      Observer.changedInstr(MI);3424      return Legalized;3425    }3426 3427    return UnableToLegalize;3428  }3429  case TargetOpcode::G_FFREXP: {3430    Observer.changingInstr(MI);3431 3432    if (TypeIdx == 0) {3433      widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_FPEXT);3434      widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);3435    } else {3436      widenScalarDst(MI, WideTy, 1);3437    }3438 3439    Observer.changedInstr(MI);3440    return Legalized;3441  }3442  case TargetOpcode::G_LROUND:3443  case TargetOpcode::G_LLROUND:3444    Observer.changingInstr(MI);3445 3446    if (TypeIdx == 0)3447      widenScalarDst(MI, WideTy);3448    else3449      widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_FPEXT);3450 3451    Observer.changedInstr(MI);3452    return Legalized;3453 3454  case TargetOpcode::G_INTTOPTR:3455    if (TypeIdx != 1)3456      return UnableToLegalize;3457 3458    Observer.changingInstr(MI);3459    widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);3460    Observer.changedInstr(MI);3461    return Legalized;3462  case TargetOpcode::G_PTRTOINT:3463    if (TypeIdx != 0)3464      return UnableToLegalize;3465 3466    Observer.changingInstr(MI);3467    widenScalarDst(MI, WideTy, 0);3468    Observer.changedInstr(MI);3469    return Legalized;3470  case TargetOpcode::G_BUILD_VECTOR: {3471    Observer.changingInstr(MI);3472 3473    const LLT WideEltTy = TypeIdx == 1 ? WideTy : WideTy.getElementType();3474    for (int I = 1, E = MI.getNumOperands(); I != E; ++I)3475      widenScalarSrc(MI, WideEltTy, I, TargetOpcode::G_ANYEXT);3476 3477    // Avoid changing the result vector type if the source element type was3478    // requested.3479    if (TypeIdx == 1) {3480      MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::G_BUILD_VECTOR_TRUNC));3481    } else {3482      widenScalarDst(MI, WideTy, 0);3483    }3484 3485    Observer.changedInstr(MI);3486    return Legalized;3487  }3488  case TargetOpcode::G_SEXT_INREG:3489    if (TypeIdx != 0)3490      return UnableToLegalize;3491 3492    Observer.changingInstr(MI);3493    widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);3494    widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);3495    Observer.changedInstr(MI);3496    return Legalized;3497  case TargetOpcode::G_PTRMASK: {3498    if (TypeIdx != 1)3499      return UnableToLegalize;3500    Observer.changingInstr(MI);3501    widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);3502    Observer.changedInstr(MI);3503    return Legalized;3504  }3505  case TargetOpcode::G_VECREDUCE_ADD: {3506    if (TypeIdx != 1)3507      return UnableToLegalize;3508    Observer.changingInstr(MI);3509    widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);3510    widenScalarDst(MI, WideTy.getScalarType(), 0, TargetOpcode::G_TRUNC);3511    Observer.changedInstr(MI);3512    return Legalized;3513  }3514  case TargetOpcode::G_VECREDUCE_FADD:3515  case TargetOpcode::G_VECREDUCE_FMUL:3516  case TargetOpcode::G_VECREDUCE_FMIN:3517  case TargetOpcode::G_VECREDUCE_FMAX:3518  case TargetOpcode::G_VECREDUCE_FMINIMUM:3519  case TargetOpcode::G_VECREDUCE_FMAXIMUM: {3520    if (TypeIdx != 0)3521      return UnableToLegalize;3522    Observer.changingInstr(MI);3523    Register VecReg = MI.getOperand(1).getReg();3524    LLT VecTy = MRI.getType(VecReg);3525    LLT WideVecTy = VecTy.isVector()3526                        ? LLT::vector(VecTy.getElementCount(), WideTy)3527                        : WideTy;3528    widenScalarSrc(MI, WideVecTy, 1, TargetOpcode::G_FPEXT);3529    widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);3530    Observer.changedInstr(MI);3531    return Legalized;3532  }3533  case TargetOpcode::G_VSCALE: {3534    MachineOperand &SrcMO = MI.getOperand(1);3535    LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();3536    const APInt &SrcVal = SrcMO.getCImm()->getValue();3537    // The CImm is always a signed value3538    const APInt Val = SrcVal.sext(WideTy.getSizeInBits());3539    Observer.changingInstr(MI);3540    SrcMO.setCImm(ConstantInt::get(Ctx, Val));3541    widenScalarDst(MI, WideTy);3542    Observer.changedInstr(MI);3543    return Legalized;3544  }3545  case TargetOpcode::G_SPLAT_VECTOR: {3546    if (TypeIdx != 1)3547      return UnableToLegalize;3548 3549    Observer.changingInstr(MI);3550    widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);3551    Observer.changedInstr(MI);3552    return Legalized;3553  }3554  case TargetOpcode::G_INSERT_SUBVECTOR: {3555    if (TypeIdx != 0)3556      return UnableToLegalize;3557 3558    GInsertSubvector &IS = cast<GInsertSubvector>(MI);3559    Register BigVec = IS.getBigVec();3560    Register SubVec = IS.getSubVec();3561 3562    LLT SubVecTy = MRI.getType(SubVec);3563    LLT SubVecWideTy = SubVecTy.changeElementType(WideTy.getElementType());3564 3565    // Widen the G_INSERT_SUBVECTOR3566    auto BigZExt = MIRBuilder.buildZExt(WideTy, BigVec);3567    auto SubZExt = MIRBuilder.buildZExt(SubVecWideTy, SubVec);3568    auto WideInsert = MIRBuilder.buildInsertSubvector(WideTy, BigZExt, SubZExt,3569                                                      IS.getIndexImm());3570 3571    // Truncate back down3572    auto SplatZero = MIRBuilder.buildSplatVector(3573        WideTy, MIRBuilder.buildConstant(WideTy.getElementType(), 0));3574    MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, IS.getReg(0), WideInsert,3575                         SplatZero);3576 3577    MI.eraseFromParent();3578 3579    return Legalized;3580  }3581  }3582}3583 3584static void getUnmergePieces(SmallVectorImpl<Register> &Pieces,3585                             MachineIRBuilder &B, Register Src, LLT Ty) {3586  auto Unmerge = B.buildUnmerge(Ty, Src);3587  for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)3588    Pieces.push_back(Unmerge.getReg(I));3589}3590 3591static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal,3592                                     MachineIRBuilder &MIRBuilder) {3593  MachineRegisterInfo &MRI = *MIRBuilder.getMRI();3594  MachineFunction &MF = MIRBuilder.getMF();3595  const DataLayout &DL = MIRBuilder.getDataLayout();3596  unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();3597  LLT AddrPtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));3598  LLT DstLLT = MRI.getType(DstReg);3599 3600  Align Alignment(DL.getABITypeAlign(ConstVal->getType()));3601 3602  auto Addr = MIRBuilder.buildConstantPool(3603      AddrPtrTy,3604      MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));3605 3606  MachineMemOperand *MMO =3607      MF.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF),3608                              MachineMemOperand::MOLoad, DstLLT, Alignment);3609 3610  MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, DstReg, Addr, *MMO);3611}3612 3613LegalizerHelper::LegalizeResult3614LegalizerHelper::lowerConstant(MachineInstr &MI) {3615  const MachineOperand &ConstOperand = MI.getOperand(1);3616  const Constant *ConstantVal = ConstOperand.getCImm();3617 3618  emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);3619  MI.eraseFromParent();3620 3621  return Legalized;3622}3623 3624LegalizerHelper::LegalizeResult3625LegalizerHelper::lowerFConstant(MachineInstr &MI) {3626  const MachineOperand &ConstOperand = MI.getOperand(1);3627  const Constant *ConstantVal = ConstOperand.getFPImm();3628 3629  emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);3630  MI.eraseFromParent();3631 3632  return Legalized;3633}3634 3635LegalizerHelper::LegalizeResult3636LegalizerHelper::lowerBitcast(MachineInstr &MI) {3637  auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();3638  if (SrcTy.isVector()) {3639    LLT SrcEltTy = SrcTy.getElementType();3640    SmallVector<Register, 8> SrcRegs;3641 3642    if (DstTy.isVector()) {3643      int NumDstElt = DstTy.getNumElements();3644      int NumSrcElt = SrcTy.getNumElements();3645 3646      LLT DstEltTy = DstTy.getElementType();3647      LLT DstCastTy = DstEltTy; // Intermediate bitcast result type3648      LLT SrcPartTy = SrcEltTy; // Original unmerge result type.3649 3650      // If there's an element size mismatch, insert intermediate casts to match3651      // the result element type.3652      if (NumSrcElt < NumDstElt) { // Source element type is larger.3653        // %1:_(<4 x s8>) = G_BITCAST %0:_(<2 x s16>)3654        //3655        // =>3656        //3657        // %2:_(s16), %3:_(s16) = G_UNMERGE_VALUES %03658        // %3:_(<2 x s8>) = G_BITCAST %23659        // %4:_(<2 x s8>) = G_BITCAST %33660        // %1:_(<4 x s16>) = G_CONCAT_VECTORS %3, %43661        DstCastTy = LLT::fixed_vector(NumDstElt / NumSrcElt, DstEltTy);3662        SrcPartTy = SrcEltTy;3663      } else if (NumSrcElt > NumDstElt) { // Source element type is smaller.3664        //3665        // %1:_(<2 x s16>) = G_BITCAST %0:_(<4 x s8>)3666        //3667        // =>3668        //3669        // %2:_(<2 x s8>), %3:_(<2 x s8>) = G_UNMERGE_VALUES %03670        // %3:_(s16) = G_BITCAST %23671        // %4:_(s16) = G_BITCAST %33672        // %1:_(<2 x s16>) = G_BUILD_VECTOR %3, %43673        SrcPartTy = LLT::fixed_vector(NumSrcElt / NumDstElt, SrcEltTy);3674        DstCastTy = DstEltTy;3675      }3676 3677      getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcPartTy);3678      for (Register &SrcReg : SrcRegs)3679        SrcReg = MIRBuilder.buildBitcast(DstCastTy, SrcReg).getReg(0);3680    } else3681      getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcEltTy);3682 3683    MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);3684    MI.eraseFromParent();3685    return Legalized;3686  }3687 3688  if (DstTy.isVector()) {3689    SmallVector<Register, 8> SrcRegs;3690    getUnmergePieces(SrcRegs, MIRBuilder, Src, DstTy.getElementType());3691    MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);3692    MI.eraseFromParent();3693    return Legalized;3694  }3695 3696  return UnableToLegalize;3697}3698 3699/// Figure out the bit offset into a register when coercing a vector index for3700/// the wide element type. This is only for the case when promoting vector to3701/// one with larger elements.3702//3703///3704/// %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))3705/// %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)3706static Register getBitcastWiderVectorElementOffset(MachineIRBuilder &B,3707                                                   Register Idx,3708                                                   unsigned NewEltSize,3709                                                   unsigned OldEltSize) {3710  const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);3711  LLT IdxTy = B.getMRI()->getType(Idx);3712 3713  // Now figure out the amount we need to shift to get the target bits.3714  auto OffsetMask = B.buildConstant(3715      IdxTy, ~(APInt::getAllOnes(IdxTy.getSizeInBits()) << Log2EltRatio));3716  auto OffsetIdx = B.buildAnd(IdxTy, Idx, OffsetMask);3717  return B.buildShl(IdxTy, OffsetIdx,3718                    B.buildConstant(IdxTy, Log2_32(OldEltSize))).getReg(0);3719}3720 3721/// Perform a G_EXTRACT_VECTOR_ELT in a different sized vector element. If this3722/// is casting to a vector with a smaller element size, perform multiple element3723/// extracts and merge the results. If this is coercing to a vector with larger3724/// elements, index the bitcasted vector and extract the target element with bit3725/// operations. This is intended to force the indexing in the native register3726/// size for architectures that can dynamically index the register file.3727LegalizerHelper::LegalizeResult3728LegalizerHelper::bitcastExtractVectorElt(MachineInstr &MI, unsigned TypeIdx,3729                                         LLT CastTy) {3730  if (TypeIdx != 1)3731    return UnableToLegalize;3732 3733  auto [Dst, DstTy, SrcVec, SrcVecTy, Idx, IdxTy] = MI.getFirst3RegLLTs();3734 3735  LLT SrcEltTy = SrcVecTy.getElementType();3736  unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;3737  unsigned OldNumElts = SrcVecTy.getNumElements();3738 3739  LLT NewEltTy = CastTy.isVector() ? CastTy.getElementType() : CastTy;3740  Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);3741 3742  const unsigned NewEltSize = NewEltTy.getSizeInBits();3743  const unsigned OldEltSize = SrcEltTy.getSizeInBits();3744  if (NewNumElts > OldNumElts) {3745    // Decreasing the vector element size3746    //3747    // e.g. i64 = extract_vector_elt x:v2i64, y:i323748    //  =>3749    //  v4i32:castx = bitcast x:v2i643750    //3751    // i64 = bitcast3752    //   (v2i32 build_vector (i32 (extract_vector_elt castx, (2 * y))),3753    //                       (i32 (extract_vector_elt castx, (2 * y + 1)))3754    //3755    if (NewNumElts % OldNumElts != 0)3756      return UnableToLegalize;3757 3758    // Type of the intermediate result vector.3759    const unsigned NewEltsPerOldElt = NewNumElts / OldNumElts;3760    LLT MidTy =3761        LLT::scalarOrVector(ElementCount::getFixed(NewEltsPerOldElt), NewEltTy);3762 3763    auto NewEltsPerOldEltK = MIRBuilder.buildConstant(IdxTy, NewEltsPerOldElt);3764 3765    SmallVector<Register, 8> NewOps(NewEltsPerOldElt);3766    auto NewBaseIdx = MIRBuilder.buildMul(IdxTy, Idx, NewEltsPerOldEltK);3767 3768    for (unsigned I = 0; I < NewEltsPerOldElt; ++I) {3769      auto IdxOffset = MIRBuilder.buildConstant(IdxTy, I);3770      auto TmpIdx = MIRBuilder.buildAdd(IdxTy, NewBaseIdx, IdxOffset);3771      auto Elt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec, TmpIdx);3772      NewOps[I] = Elt.getReg(0);3773    }3774 3775    auto NewVec = MIRBuilder.buildBuildVector(MidTy, NewOps);3776    MIRBuilder.buildBitcast(Dst, NewVec);3777    MI.eraseFromParent();3778    return Legalized;3779  }3780 3781  if (NewNumElts < OldNumElts) {3782    if (NewEltSize % OldEltSize != 0)3783      return UnableToLegalize;3784 3785    // This only depends on powers of 2 because we use bit tricks to figure out3786    // the bit offset we need to shift to get the target element. A general3787    // expansion could emit division/multiply.3788    if (!isPowerOf2_32(NewEltSize / OldEltSize))3789      return UnableToLegalize;3790 3791    // Increasing the vector element size.3792    // %elt:_(small_elt) = G_EXTRACT_VECTOR_ELT %vec:_(<N x small_elt>), %idx3793    //3794    //   =>3795    //3796    // %cast = G_BITCAST %vec3797    // %scaled_idx = G_LSHR %idx, Log2(DstEltSize / SrcEltSize)3798    // %wide_elt  = G_EXTRACT_VECTOR_ELT %cast, %scaled_idx3799    // %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))3800    // %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)3801    // %elt_bits = G_LSHR %wide_elt, %offset_bits3802    // %elt = G_TRUNC %elt_bits3803 3804    const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);3805    auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);3806 3807    // Divide to get the index in the wider element type.3808    auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);3809 3810    Register WideElt = CastVec;3811    if (CastTy.isVector()) {3812      WideElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,3813                                                     ScaledIdx).getReg(0);3814    }3815 3816    // Compute the bit offset into the register of the target element.3817    Register OffsetBits = getBitcastWiderVectorElementOffset(3818      MIRBuilder, Idx, NewEltSize, OldEltSize);3819 3820    // Shift the wide element to get the target element.3821    auto ExtractedBits = MIRBuilder.buildLShr(NewEltTy, WideElt, OffsetBits);3822    MIRBuilder.buildTrunc(Dst, ExtractedBits);3823    MI.eraseFromParent();3824    return Legalized;3825  }3826 3827  return UnableToLegalize;3828}3829 3830/// Emit code to insert \p InsertReg into \p TargetRet at \p OffsetBits in \p3831/// TargetReg, while preserving other bits in \p TargetReg.3832///3833/// (InsertReg << Offset) | (TargetReg & ~(-1 >> InsertReg.size()) << Offset)3834static Register buildBitFieldInsert(MachineIRBuilder &B,3835                                    Register TargetReg, Register InsertReg,3836                                    Register OffsetBits) {3837  LLT TargetTy = B.getMRI()->getType(TargetReg);3838  LLT InsertTy = B.getMRI()->getType(InsertReg);3839  auto ZextVal = B.buildZExt(TargetTy, InsertReg);3840  auto ShiftedInsertVal = B.buildShl(TargetTy, ZextVal, OffsetBits);3841 3842  // Produce a bitmask of the value to insert3843  auto EltMask = B.buildConstant(3844    TargetTy, APInt::getLowBitsSet(TargetTy.getSizeInBits(),3845                                   InsertTy.getSizeInBits()));3846  // Shift it into position3847  auto ShiftedMask = B.buildShl(TargetTy, EltMask, OffsetBits);3848  auto InvShiftedMask = B.buildNot(TargetTy, ShiftedMask);3849 3850  // Clear out the bits in the wide element3851  auto MaskedOldElt = B.buildAnd(TargetTy, TargetReg, InvShiftedMask);3852 3853  // The value to insert has all zeros already, so stick it into the masked3854  // wide element.3855  return B.buildOr(TargetTy, MaskedOldElt, ShiftedInsertVal).getReg(0);3856}3857 3858/// Perform a G_INSERT_VECTOR_ELT in a different sized vector element. If this3859/// is increasing the element size, perform the indexing in the target element3860/// type, and use bit operations to insert at the element position. This is3861/// intended for architectures that can dynamically index the register file and3862/// want to force indexing in the native register size.3863LegalizerHelper::LegalizeResult3864LegalizerHelper::bitcastInsertVectorElt(MachineInstr &MI, unsigned TypeIdx,3865                                        LLT CastTy) {3866  if (TypeIdx != 0)3867    return UnableToLegalize;3868 3869  auto [Dst, DstTy, SrcVec, SrcVecTy, Val, ValTy, Idx, IdxTy] =3870      MI.getFirst4RegLLTs();3871  LLT VecTy = DstTy;3872 3873  LLT VecEltTy = VecTy.getElementType();3874  LLT NewEltTy = CastTy.isVector() ? CastTy.getElementType() : CastTy;3875  const unsigned NewEltSize = NewEltTy.getSizeInBits();3876  const unsigned OldEltSize = VecEltTy.getSizeInBits();3877 3878  unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;3879  unsigned OldNumElts = VecTy.getNumElements();3880 3881  Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);3882  if (NewNumElts < OldNumElts) {3883    if (NewEltSize % OldEltSize != 0)3884      return UnableToLegalize;3885 3886    // This only depends on powers of 2 because we use bit tricks to figure out3887    // the bit offset we need to shift to get the target element. A general3888    // expansion could emit division/multiply.3889    if (!isPowerOf2_32(NewEltSize / OldEltSize))3890      return UnableToLegalize;3891 3892    const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);3893    auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);3894 3895    // Divide to get the index in the wider element type.3896    auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);3897 3898    Register ExtractedElt = CastVec;3899    if (CastTy.isVector()) {3900      ExtractedElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,3901                                                          ScaledIdx).getReg(0);3902    }3903 3904    // Compute the bit offset into the register of the target element.3905    Register OffsetBits = getBitcastWiderVectorElementOffset(3906      MIRBuilder, Idx, NewEltSize, OldEltSize);3907 3908    Register InsertedElt = buildBitFieldInsert(MIRBuilder, ExtractedElt,3909                                               Val, OffsetBits);3910    if (CastTy.isVector()) {3911      InsertedElt = MIRBuilder.buildInsertVectorElement(3912        CastTy, CastVec, InsertedElt, ScaledIdx).getReg(0);3913    }3914 3915    MIRBuilder.buildBitcast(Dst, InsertedElt);3916    MI.eraseFromParent();3917    return Legalized;3918  }3919 3920  return UnableToLegalize;3921}3922 3923// This attempts to handle G_CONCAT_VECTORS with illegal operands, particularly3924// those that have smaller than legal operands.3925//3926// <16 x s8> = G_CONCAT_VECTORS <4 x s8>, <4 x s8>, <4 x s8>, <4 x s8>3927//3928// ===>3929//3930// s32 = G_BITCAST <4 x s8>3931// s32 = G_BITCAST <4 x s8>3932// s32 = G_BITCAST <4 x s8>3933// s32 = G_BITCAST <4 x s8>3934// <4 x s32> = G_BUILD_VECTOR s32, s32, s32, s323935// <16 x s8> = G_BITCAST <4 x s32>3936LegalizerHelper::LegalizeResult3937LegalizerHelper::bitcastConcatVector(MachineInstr &MI, unsigned TypeIdx,3938                                     LLT CastTy) {3939  // Convert it to CONCAT instruction3940  auto ConcatMI = dyn_cast<GConcatVectors>(&MI);3941  if (!ConcatMI) {3942    return UnableToLegalize;3943  }3944 3945  // Check if bitcast is Legal3946  auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();3947  LLT SrcScalTy = LLT::scalar(SrcTy.getSizeInBits());3948 3949  // Check if the build vector is Legal3950  if (!LI.isLegal({TargetOpcode::G_BUILD_VECTOR, {CastTy, SrcScalTy}})) {3951    return UnableToLegalize;3952  }3953 3954  // Bitcast the sources3955  SmallVector<Register> BitcastRegs;3956  for (unsigned i = 0; i < ConcatMI->getNumSources(); i++) {3957    BitcastRegs.push_back(3958        MIRBuilder.buildBitcast(SrcScalTy, ConcatMI->getSourceReg(i))3959            .getReg(0));3960  }3961 3962  // Build the scalar values into a vector3963  Register BuildReg =3964      MIRBuilder.buildBuildVector(CastTy, BitcastRegs).getReg(0);3965  MIRBuilder.buildBitcast(DstReg, BuildReg);3966 3967  MI.eraseFromParent();3968  return Legalized;3969}3970 3971// This bitcasts a shuffle vector to a different type currently of the same3972// element size. Mostly used to legalize ptr vectors, where ptrtoint/inttoptr3973// will be used instead.3974//3975// <16 x p0> = G_CONCAT_VECTORS <4 x p0>, <4 x p0>, mask3976// ===>3977// <4 x s64> = G_PTRTOINT <4 x p0>3978// <4 x s64> = G_PTRTOINT <4 x p0>3979// <16 x s64> = G_CONCAT_VECTORS <4 x s64>, <4 x s64>, mask3980// <16 x p0> = G_INTTOPTR <16 x s64>3981LegalizerHelper::LegalizeResult3982LegalizerHelper::bitcastShuffleVector(MachineInstr &MI, unsigned TypeIdx,3983                                      LLT CastTy) {3984  auto ShuffleMI = cast<GShuffleVector>(&MI);3985  LLT DstTy = MRI.getType(ShuffleMI->getReg(0));3986  LLT SrcTy = MRI.getType(ShuffleMI->getReg(1));3987 3988  // We currently only handle vectors of the same size.3989  if (TypeIdx != 0 ||3990      CastTy.getScalarSizeInBits() != DstTy.getScalarSizeInBits() ||3991      CastTy.getElementCount() != DstTy.getElementCount())3992    return UnableToLegalize;3993 3994  LLT NewSrcTy = SrcTy.changeElementType(CastTy.getScalarType());3995 3996  auto Inp1 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(1));3997  auto Inp2 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(2));3998  auto Shuf =3999      MIRBuilder.buildShuffleVector(CastTy, Inp1, Inp2, ShuffleMI->getMask());4000  MIRBuilder.buildCast(ShuffleMI->getReg(0), Shuf);4001 4002  MI.eraseFromParent();4003  return Legalized;4004}4005 4006/// This attempts to bitcast G_EXTRACT_SUBVECTOR to CastTy.4007///4008///  <vscale x 8 x i1> = G_EXTRACT_SUBVECTOR <vscale x 16 x i1>, N4009///4010/// ===>4011///4012///  <vscale x 2 x i1> = G_BITCAST <vscale x 16 x i1>4013///  <vscale x 1 x i8> = G_EXTRACT_SUBVECTOR <vscale x 2 x i1>, N / 84014///  <vscale x 8 x i1> = G_BITCAST <vscale x 1 x i8>4015LegalizerHelper::LegalizeResult4016LegalizerHelper::bitcastExtractSubvector(MachineInstr &MI, unsigned TypeIdx,4017                                         LLT CastTy) {4018  auto ES = cast<GExtractSubvector>(&MI);4019 4020  if (!CastTy.isVector())4021    return UnableToLegalize;4022 4023  if (TypeIdx != 0)4024    return UnableToLegalize;4025 4026  Register Dst = ES->getReg(0);4027  Register Src = ES->getSrcVec();4028  uint64_t Idx = ES->getIndexImm();4029 4030  MachineRegisterInfo &MRI = *MIRBuilder.getMRI();4031 4032  LLT DstTy = MRI.getType(Dst);4033  LLT SrcTy = MRI.getType(Src);4034  ElementCount DstTyEC = DstTy.getElementCount();4035  ElementCount SrcTyEC = SrcTy.getElementCount();4036  auto DstTyMinElts = DstTyEC.getKnownMinValue();4037  auto SrcTyMinElts = SrcTyEC.getKnownMinValue();4038 4039  if (DstTy == CastTy)4040    return Legalized;4041 4042  if (DstTy.getSizeInBits() != CastTy.getSizeInBits())4043    return UnableToLegalize;4044 4045  unsigned CastEltSize = CastTy.getElementType().getSizeInBits();4046  unsigned DstEltSize = DstTy.getElementType().getSizeInBits();4047  if (CastEltSize < DstEltSize)4048    return UnableToLegalize;4049 4050  auto AdjustAmt = CastEltSize / DstEltSize;4051  if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||4052      SrcTyMinElts % AdjustAmt != 0)4053    return UnableToLegalize;4054 4055  Idx /= AdjustAmt;4056  SrcTy = LLT::vector(SrcTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);4057  auto CastVec = MIRBuilder.buildBitcast(SrcTy, Src);4058  auto PromotedES = MIRBuilder.buildExtractSubvector(CastTy, CastVec, Idx);4059  MIRBuilder.buildBitcast(Dst, PromotedES);4060 4061  ES->eraseFromParent();4062  return Legalized;4063}4064 4065/// This attempts to bitcast G_INSERT_SUBVECTOR to CastTy.4066///4067///  <vscale x 16 x i1> = G_INSERT_SUBVECTOR <vscale x 16 x i1>,4068///                                          <vscale x 8 x i1>,4069///                                          N4070///4071/// ===>4072///4073///  <vscale x 2 x i8> = G_BITCAST <vscale x 16 x i1>4074///  <vscale x 1 x i8> = G_BITCAST <vscale x 8 x i1>4075///  <vscale x 2 x i8> = G_INSERT_SUBVECTOR <vscale x 2 x i8>,4076///                                         <vscale x 1 x i8>, N / 84077///  <vscale x 16 x i1> = G_BITCAST <vscale x 2 x i8>4078LegalizerHelper::LegalizeResult4079LegalizerHelper::bitcastInsertSubvector(MachineInstr &MI, unsigned TypeIdx,4080                                        LLT CastTy) {4081  auto ES = cast<GInsertSubvector>(&MI);4082 4083  if (!CastTy.isVector())4084    return UnableToLegalize;4085 4086  if (TypeIdx != 0)4087    return UnableToLegalize;4088 4089  Register Dst = ES->getReg(0);4090  Register BigVec = ES->getBigVec();4091  Register SubVec = ES->getSubVec();4092  uint64_t Idx = ES->getIndexImm();4093 4094  MachineRegisterInfo &MRI = *MIRBuilder.getMRI();4095 4096  LLT DstTy = MRI.getType(Dst);4097  LLT BigVecTy = MRI.getType(BigVec);4098  LLT SubVecTy = MRI.getType(SubVec);4099 4100  if (DstTy == CastTy)4101    return Legalized;4102 4103  if (DstTy.getSizeInBits() != CastTy.getSizeInBits())4104    return UnableToLegalize;4105 4106  ElementCount DstTyEC = DstTy.getElementCount();4107  ElementCount BigVecTyEC = BigVecTy.getElementCount();4108  ElementCount SubVecTyEC = SubVecTy.getElementCount();4109  auto DstTyMinElts = DstTyEC.getKnownMinValue();4110  auto BigVecTyMinElts = BigVecTyEC.getKnownMinValue();4111  auto SubVecTyMinElts = SubVecTyEC.getKnownMinValue();4112 4113  unsigned CastEltSize = CastTy.getElementType().getSizeInBits();4114  unsigned DstEltSize = DstTy.getElementType().getSizeInBits();4115  if (CastEltSize < DstEltSize)4116    return UnableToLegalize;4117 4118  auto AdjustAmt = CastEltSize / DstEltSize;4119  if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||4120      BigVecTyMinElts % AdjustAmt != 0 || SubVecTyMinElts % AdjustAmt != 0)4121    return UnableToLegalize;4122 4123  Idx /= AdjustAmt;4124  BigVecTy = LLT::vector(BigVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);4125  SubVecTy = LLT::vector(SubVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);4126  auto CastBigVec = MIRBuilder.buildBitcast(BigVecTy, BigVec);4127  auto CastSubVec = MIRBuilder.buildBitcast(SubVecTy, SubVec);4128  auto PromotedIS =4129      MIRBuilder.buildInsertSubvector(CastTy, CastBigVec, CastSubVec, Idx);4130  MIRBuilder.buildBitcast(Dst, PromotedIS);4131 4132  ES->eraseFromParent();4133  return Legalized;4134}4135 4136LegalizerHelper::LegalizeResult LegalizerHelper::lowerLoad(GAnyLoad &LoadMI) {4137  // Lower to a memory-width G_LOAD and a G_SEXT/G_ZEXT/G_ANYEXT4138  Register DstReg = LoadMI.getDstReg();4139  Register PtrReg = LoadMI.getPointerReg();4140  LLT DstTy = MRI.getType(DstReg);4141  MachineMemOperand &MMO = LoadMI.getMMO();4142  LLT MemTy = MMO.getMemoryType();4143  MachineFunction &MF = MIRBuilder.getMF();4144 4145  unsigned MemSizeInBits = MemTy.getSizeInBits();4146  unsigned MemStoreSizeInBits = 8 * MemTy.getSizeInBytes();4147 4148  if (MemSizeInBits != MemStoreSizeInBits) {4149    if (MemTy.isVector())4150      return UnableToLegalize;4151 4152    // Promote to a byte-sized load if not loading an integral number of4153    // bytes.  For example, promote EXTLOAD:i20 -> EXTLOAD:i24.4154    LLT WideMemTy = LLT::scalar(MemStoreSizeInBits);4155    MachineMemOperand *NewMMO =4156        MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideMemTy);4157 4158    Register LoadReg = DstReg;4159    LLT LoadTy = DstTy;4160 4161    // If this wasn't already an extending load, we need to widen the result4162    // register to avoid creating a load with a narrower result than the source.4163    if (MemStoreSizeInBits > DstTy.getSizeInBits()) {4164      LoadTy = WideMemTy;4165      LoadReg = MRI.createGenericVirtualRegister(WideMemTy);4166    }4167 4168    if (isa<GSExtLoad>(LoadMI)) {4169      auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);4170      MIRBuilder.buildSExtInReg(LoadReg, NewLoad, MemSizeInBits);4171    } else if (isa<GZExtLoad>(LoadMI) || WideMemTy == LoadTy) {4172      auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);4173      // The extra bits are guaranteed to be zero, since we stored them that4174      // way.  A zext load from Wide thus automatically gives zext from MemVT.4175      MIRBuilder.buildAssertZExt(LoadReg, NewLoad, MemSizeInBits);4176    } else {4177      MIRBuilder.buildLoad(LoadReg, PtrReg, *NewMMO);4178    }4179 4180    if (DstTy != LoadTy)4181      MIRBuilder.buildTrunc(DstReg, LoadReg);4182 4183    LoadMI.eraseFromParent();4184    return Legalized;4185  }4186 4187  // Big endian lowering not implemented.4188  if (MIRBuilder.getDataLayout().isBigEndian())4189    return UnableToLegalize;4190 4191  // This load needs splitting into power of 2 sized loads.4192  //4193  // Our strategy here is to generate anyextending loads for the smaller4194  // types up to next power-2 result type, and then combine the two larger4195  // result values together, before truncating back down to the non-pow-24196  // type.4197  // E.g. v1 = i24 load =>4198  // v2 = i32 zextload (2 byte)4199  // v3 = i32 load (1 byte)4200  // v4 = i32 shl v3, 164201  // v5 = i32 or v4, v24202  // v1 = i24 trunc v54203  // By doing this we generate the correct truncate which should get4204  // combined away as an artifact with a matching extend.4205 4206  uint64_t LargeSplitSize, SmallSplitSize;4207 4208  if (!isPowerOf2_32(MemSizeInBits)) {4209    // This load needs splitting into power of 2 sized loads.4210    LargeSplitSize = llvm::bit_floor(MemSizeInBits);4211    SmallSplitSize = MemSizeInBits - LargeSplitSize;4212  } else {4213    // This is already a power of 2, but we still need to split this in half.4214    //4215    // Assume we're being asked to decompose an unaligned load.4216    // TODO: If this requires multiple splits, handle them all at once.4217    auto &Ctx = MF.getFunction().getContext();4218    if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))4219      return UnableToLegalize;4220 4221    SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;4222  }4223 4224  if (MemTy.isVector()) {4225    // TODO: Handle vector extloads4226    if (MemTy != DstTy)4227      return UnableToLegalize;4228 4229    Align Alignment = LoadMI.getAlign();4230    // Given an alignment larger than the size of the memory, we can increase4231    // the size of the load without needing to scalarize it.4232    if (Alignment.value() * 8 > MemSizeInBits &&4233        isPowerOf2_64(DstTy.getScalarSizeInBits())) {4234      LLT MoreTy = LLT::fixed_vector(NextPowerOf2(DstTy.getNumElements()),4235                                     DstTy.getElementType());4236      MachineMemOperand *NewMMO = MF.getMachineMemOperand(&MMO, 0, MoreTy);4237      auto NewLoad = MIRBuilder.buildLoad(MoreTy, PtrReg, *NewMMO);4238      MIRBuilder.buildDeleteTrailingVectorElements(LoadMI.getReg(0),4239                                                   NewLoad.getReg(0));4240      LoadMI.eraseFromParent();4241      return Legalized;4242    }4243 4244    // TODO: We can do better than scalarizing the vector and at least split it4245    // in half.4246    return reduceLoadStoreWidth(LoadMI, 0, DstTy.getElementType());4247  }4248 4249  MachineMemOperand *LargeMMO =4250      MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);4251  MachineMemOperand *SmallMMO =4252      MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);4253 4254  LLT PtrTy = MRI.getType(PtrReg);4255  unsigned AnyExtSize = PowerOf2Ceil(DstTy.getSizeInBits());4256  LLT AnyExtTy = LLT::scalar(AnyExtSize);4257  auto LargeLoad = MIRBuilder.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, AnyExtTy,4258                                             PtrReg, *LargeMMO);4259 4260  auto OffsetCst = MIRBuilder.buildConstant(LLT::scalar(PtrTy.getSizeInBits()),4261                                            LargeSplitSize / 8);4262  Register PtrAddReg = MRI.createGenericVirtualRegister(PtrTy);4263  auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrAddReg, PtrReg, OffsetCst);4264  auto SmallLoad = MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), AnyExtTy,4265                                             SmallPtr, *SmallMMO);4266 4267  auto ShiftAmt = MIRBuilder.buildConstant(AnyExtTy, LargeSplitSize);4268  auto Shift = MIRBuilder.buildShl(AnyExtTy, SmallLoad, ShiftAmt);4269 4270  if (AnyExtTy == DstTy)4271    MIRBuilder.buildOr(DstReg, Shift, LargeLoad);4272  else if (AnyExtTy.getSizeInBits() != DstTy.getSizeInBits()) {4273    auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);4274    MIRBuilder.buildTrunc(DstReg, {Or});4275  } else {4276    assert(DstTy.isPointer() && "expected pointer");4277    auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);4278 4279    // FIXME: We currently consider this to be illegal for non-integral address4280    // spaces, but we need still need a way to reinterpret the bits.4281    MIRBuilder.buildIntToPtr(DstReg, Or);4282  }4283 4284  LoadMI.eraseFromParent();4285  return Legalized;4286}4287 4288LegalizerHelper::LegalizeResult LegalizerHelper::lowerStore(GStore &StoreMI) {4289  // Lower a non-power of 2 store into multiple pow-2 stores.4290  // E.g. split an i24 store into an i16 store + i8 store.4291  // We do this by first extending the stored value to the next largest power4292  // of 2 type, and then using truncating stores to store the components.4293  // By doing this, likewise with G_LOAD, generate an extend that can be4294  // artifact-combined away instead of leaving behind extracts.4295  Register SrcReg = StoreMI.getValueReg();4296  Register PtrReg = StoreMI.getPointerReg();4297  LLT SrcTy = MRI.getType(SrcReg);4298  MachineFunction &MF = MIRBuilder.getMF();4299  MachineMemOperand &MMO = **StoreMI.memoperands_begin();4300  LLT MemTy = MMO.getMemoryType();4301 4302  unsigned StoreWidth = MemTy.getSizeInBits();4303  unsigned StoreSizeInBits = 8 * MemTy.getSizeInBytes();4304 4305  if (StoreWidth != StoreSizeInBits && !SrcTy.isVector()) {4306    // Promote to a byte-sized store with upper bits zero if not4307    // storing an integral number of bytes.  For example, promote4308    // TRUNCSTORE:i1 X -> TRUNCSTORE:i8 (and X, 1)4309    LLT WideTy = LLT::scalar(StoreSizeInBits);4310 4311    if (StoreSizeInBits > SrcTy.getSizeInBits()) {4312      // Avoid creating a store with a narrower source than result.4313      SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);4314      SrcTy = WideTy;4315    }4316 4317    auto ZextInReg = MIRBuilder.buildZExtInReg(SrcTy, SrcReg, StoreWidth);4318 4319    MachineMemOperand *NewMMO =4320        MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideTy);4321    MIRBuilder.buildStore(ZextInReg, PtrReg, *NewMMO);4322    StoreMI.eraseFromParent();4323    return Legalized;4324  }4325 4326  if (MemTy.isVector()) {4327    if (MemTy != SrcTy)4328      return scalarizeVectorBooleanStore(StoreMI);4329 4330    // TODO: We can do better than scalarizing the vector and at least split it4331    // in half.4332    return reduceLoadStoreWidth(StoreMI, 0, SrcTy.getElementType());4333  }4334 4335  unsigned MemSizeInBits = MemTy.getSizeInBits();4336  uint64_t LargeSplitSize, SmallSplitSize;4337 4338  if (!isPowerOf2_32(MemSizeInBits)) {4339    LargeSplitSize = llvm::bit_floor<uint64_t>(MemTy.getSizeInBits());4340    SmallSplitSize = MemTy.getSizeInBits() - LargeSplitSize;4341  } else {4342    auto &Ctx = MF.getFunction().getContext();4343    if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))4344      return UnableToLegalize; // Don't know what we're being asked to do.4345 4346    SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;4347  }4348 4349  // Extend to the next pow-2. If this store was itself the result of lowering,4350  // e.g. an s56 store being broken into s32 + s24, we might have a stored type4351  // that's wider than the stored size.4352  unsigned AnyExtSize = PowerOf2Ceil(MemTy.getSizeInBits());4353  const LLT NewSrcTy = LLT::scalar(AnyExtSize);4354 4355  if (SrcTy.isPointer()) {4356    const LLT IntPtrTy = LLT::scalar(SrcTy.getSizeInBits());4357    SrcReg = MIRBuilder.buildPtrToInt(IntPtrTy, SrcReg).getReg(0);4358  }4359 4360  auto ExtVal = MIRBuilder.buildAnyExtOrTrunc(NewSrcTy, SrcReg);4361 4362  // Obtain the smaller value by shifting away the larger value.4363  auto ShiftAmt = MIRBuilder.buildConstant(NewSrcTy, LargeSplitSize);4364  auto SmallVal = MIRBuilder.buildLShr(NewSrcTy, ExtVal, ShiftAmt);4365 4366  // Generate the PtrAdd and truncating stores.4367  LLT PtrTy = MRI.getType(PtrReg);4368  auto OffsetCst = MIRBuilder.buildConstant(4369    LLT::scalar(PtrTy.getSizeInBits()), LargeSplitSize / 8);4370  auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrTy, PtrReg, OffsetCst);4371 4372  MachineMemOperand *LargeMMO =4373    MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);4374  MachineMemOperand *SmallMMO =4375    MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);4376  MIRBuilder.buildStore(ExtVal, PtrReg, *LargeMMO);4377  MIRBuilder.buildStore(SmallVal, SmallPtr, *SmallMMO);4378  StoreMI.eraseFromParent();4379  return Legalized;4380}4381 4382LegalizerHelper::LegalizeResult4383LegalizerHelper::scalarizeVectorBooleanStore(GStore &StoreMI) {4384  Register SrcReg = StoreMI.getValueReg();4385  Register PtrReg = StoreMI.getPointerReg();4386  LLT SrcTy = MRI.getType(SrcReg);4387  MachineMemOperand &MMO = **StoreMI.memoperands_begin();4388  LLT MemTy = MMO.getMemoryType();4389  LLT MemScalarTy = MemTy.getElementType();4390  MachineFunction &MF = MIRBuilder.getMF();4391 4392  assert(SrcTy.isVector() && "Expect a vector store type");4393 4394  if (!MemScalarTy.isByteSized()) {4395    // We need to build an integer scalar of the vector bit pattern.4396    // It's not legal for us to add padding when storing a vector.4397    unsigned NumBits = MemTy.getSizeInBits();4398    LLT IntTy = LLT::scalar(NumBits);4399    auto CurrVal = MIRBuilder.buildConstant(IntTy, 0);4400    LLT IdxTy = TLI.getVectorIdxLLT(MF.getDataLayout());4401 4402    for (unsigned I = 0, E = MemTy.getNumElements(); I < E; ++I) {4403      auto Elt = MIRBuilder.buildExtractVectorElement(4404          SrcTy.getElementType(), SrcReg, MIRBuilder.buildConstant(IdxTy, I));4405      auto Trunc = MIRBuilder.buildTrunc(MemScalarTy, Elt);4406      auto ZExt = MIRBuilder.buildZExt(IntTy, Trunc);4407      unsigned ShiftIntoIdx = MF.getDataLayout().isBigEndian()4408                                  ? (MemTy.getNumElements() - 1) - I4409                                  : I;4410      auto ShiftAmt = MIRBuilder.buildConstant(4411          IntTy, ShiftIntoIdx * MemScalarTy.getSizeInBits());4412      auto Shifted = MIRBuilder.buildShl(IntTy, ZExt, ShiftAmt);4413      CurrVal = MIRBuilder.buildOr(IntTy, CurrVal, Shifted);4414    }4415    auto PtrInfo = MMO.getPointerInfo();4416    auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, IntTy);4417    MIRBuilder.buildStore(CurrVal, PtrReg, *NewMMO);4418    StoreMI.eraseFromParent();4419    return Legalized;4420  }4421 4422  // TODO: implement simple scalarization.4423  return UnableToLegalize;4424}4425 4426LegalizerHelper::LegalizeResult4427LegalizerHelper::bitcast(MachineInstr &MI, unsigned TypeIdx, LLT CastTy) {4428  switch (MI.getOpcode()) {4429  case TargetOpcode::G_LOAD: {4430    if (TypeIdx != 0)4431      return UnableToLegalize;4432    MachineMemOperand &MMO = **MI.memoperands_begin();4433 4434    // Not sure how to interpret a bitcast of an extending load.4435    if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())4436      return UnableToLegalize;4437 4438    Observer.changingInstr(MI);4439    bitcastDst(MI, CastTy, 0);4440    MMO.setType(CastTy);4441    // The range metadata is no longer valid when reinterpreted as a different4442    // type.4443    MMO.clearRanges();4444    Observer.changedInstr(MI);4445    return Legalized;4446  }4447  case TargetOpcode::G_STORE: {4448    if (TypeIdx != 0)4449      return UnableToLegalize;4450 4451    MachineMemOperand &MMO = **MI.memoperands_begin();4452 4453    // Not sure how to interpret a bitcast of a truncating store.4454    if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())4455      return UnableToLegalize;4456 4457    Observer.changingInstr(MI);4458    bitcastSrc(MI, CastTy, 0);4459    MMO.setType(CastTy);4460    Observer.changedInstr(MI);4461    return Legalized;4462  }4463  case TargetOpcode::G_SELECT: {4464    if (TypeIdx != 0)4465      return UnableToLegalize;4466 4467    if (MRI.getType(MI.getOperand(1).getReg()).isVector()) {4468      LLVM_DEBUG(4469          dbgs() << "bitcast action not implemented for vector select\n");4470      return UnableToLegalize;4471    }4472 4473    Observer.changingInstr(MI);4474    bitcastSrc(MI, CastTy, 2);4475    bitcastSrc(MI, CastTy, 3);4476    bitcastDst(MI, CastTy, 0);4477    Observer.changedInstr(MI);4478    return Legalized;4479  }4480  case TargetOpcode::G_AND:4481  case TargetOpcode::G_OR:4482  case TargetOpcode::G_XOR: {4483    Observer.changingInstr(MI);4484    bitcastSrc(MI, CastTy, 1);4485    bitcastSrc(MI, CastTy, 2);4486    bitcastDst(MI, CastTy, 0);4487    Observer.changedInstr(MI);4488    return Legalized;4489  }4490  case TargetOpcode::G_EXTRACT_VECTOR_ELT:4491    return bitcastExtractVectorElt(MI, TypeIdx, CastTy);4492  case TargetOpcode::G_INSERT_VECTOR_ELT:4493    return bitcastInsertVectorElt(MI, TypeIdx, CastTy);4494  case TargetOpcode::G_CONCAT_VECTORS:4495    return bitcastConcatVector(MI, TypeIdx, CastTy);4496  case TargetOpcode::G_SHUFFLE_VECTOR:4497    return bitcastShuffleVector(MI, TypeIdx, CastTy);4498  case TargetOpcode::G_EXTRACT_SUBVECTOR:4499    return bitcastExtractSubvector(MI, TypeIdx, CastTy);4500  case TargetOpcode::G_INSERT_SUBVECTOR:4501    return bitcastInsertSubvector(MI, TypeIdx, CastTy);4502  default:4503    return UnableToLegalize;4504  }4505}4506 4507// Legalize an instruction by changing the opcode in place.4508void LegalizerHelper::changeOpcode(MachineInstr &MI, unsigned NewOpcode) {4509    Observer.changingInstr(MI);4510    MI.setDesc(MIRBuilder.getTII().get(NewOpcode));4511    Observer.changedInstr(MI);4512}4513 4514LegalizerHelper::LegalizeResult4515LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {4516  using namespace TargetOpcode;4517 4518  switch(MI.getOpcode()) {4519  default:4520    return UnableToLegalize;4521  case TargetOpcode::G_FCONSTANT:4522    return lowerFConstant(MI);4523  case TargetOpcode::G_BITCAST:4524    return lowerBitcast(MI);4525  case TargetOpcode::G_SREM:4526  case TargetOpcode::G_UREM: {4527    LLT Ty = MRI.getType(MI.getOperand(0).getReg());4528    auto Quot =4529        MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV, {Ty},4530                              {MI.getOperand(1), MI.getOperand(2)});4531 4532    auto Prod = MIRBuilder.buildMul(Ty, Quot, MI.getOperand(2));4533    MIRBuilder.buildSub(MI.getOperand(0), MI.getOperand(1), Prod);4534    MI.eraseFromParent();4535    return Legalized;4536  }4537  case TargetOpcode::G_SADDO:4538  case TargetOpcode::G_SSUBO:4539    return lowerSADDO_SSUBO(MI);4540  case TargetOpcode::G_SADDE:4541    return lowerSADDE(MI);4542  case TargetOpcode::G_SSUBE:4543    return lowerSSUBE(MI);4544  case TargetOpcode::G_UMULH:4545  case TargetOpcode::G_SMULH:4546    return lowerSMULH_UMULH(MI);4547  case TargetOpcode::G_SMULO:4548  case TargetOpcode::G_UMULO: {4549    // Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the4550    // result.4551    auto [Res, Overflow, LHS, RHS] = MI.getFirst4Regs();4552    LLT Ty = MRI.getType(Res);4553 4554    unsigned Opcode = MI.getOpcode() == TargetOpcode::G_SMULO4555                          ? TargetOpcode::G_SMULH4556                          : TargetOpcode::G_UMULH;4557 4558    Observer.changingInstr(MI);4559    const auto &TII = MIRBuilder.getTII();4560    MI.setDesc(TII.get(TargetOpcode::G_MUL));4561    MI.removeOperand(1);4562    Observer.changedInstr(MI);4563 4564    auto HiPart = MIRBuilder.buildInstr(Opcode, {Ty}, {LHS, RHS});4565    auto Zero = MIRBuilder.buildConstant(Ty, 0);4566 4567    // Move insert point forward so we can use the Res register if needed.4568    MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());4569 4570    // For *signed* multiply, overflow is detected by checking:4571    // (hi != (lo >> bitwidth-1))4572    if (Opcode == TargetOpcode::G_SMULH) {4573      auto ShiftAmt = MIRBuilder.buildConstant(Ty, Ty.getSizeInBits() - 1);4574      auto Shifted = MIRBuilder.buildAShr(Ty, Res, ShiftAmt);4575      MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Shifted);4576    } else {4577      MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);4578    }4579    return Legalized;4580  }4581  case TargetOpcode::G_FNEG: {4582    auto [Res, SubByReg] = MI.getFirst2Regs();4583    LLT Ty = MRI.getType(Res);4584 4585    auto SignMask = MIRBuilder.buildConstant(4586        Ty, APInt::getSignMask(Ty.getScalarSizeInBits()));4587    MIRBuilder.buildXor(Res, SubByReg, SignMask);4588    MI.eraseFromParent();4589    return Legalized;4590  }4591  case TargetOpcode::G_FSUB:4592  case TargetOpcode::G_STRICT_FSUB: {4593    auto [Res, LHS, RHS] = MI.getFirst3Regs();4594    LLT Ty = MRI.getType(Res);4595 4596    // Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)).4597    auto Neg = MIRBuilder.buildFNeg(Ty, RHS);4598 4599    if (MI.getOpcode() == TargetOpcode::G_STRICT_FSUB)4600      MIRBuilder.buildStrictFAdd(Res, LHS, Neg, MI.getFlags());4601    else4602      MIRBuilder.buildFAdd(Res, LHS, Neg, MI.getFlags());4603 4604    MI.eraseFromParent();4605    return Legalized;4606  }4607  case TargetOpcode::G_FMAD:4608    return lowerFMad(MI);4609  case TargetOpcode::G_FFLOOR:4610    return lowerFFloor(MI);4611  case TargetOpcode::G_LROUND:4612  case TargetOpcode::G_LLROUND: {4613    Register DstReg = MI.getOperand(0).getReg();4614    Register SrcReg = MI.getOperand(1).getReg();4615    LLT SrcTy = MRI.getType(SrcReg);4616    auto Round = MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_ROUND, {SrcTy},4617                                       {SrcReg});4618    MIRBuilder.buildFPTOSI(DstReg, Round);4619    MI.eraseFromParent();4620    return Legalized;4621  }4622  case TargetOpcode::G_INTRINSIC_ROUND:4623    return lowerIntrinsicRound(MI);4624  case TargetOpcode::G_FRINT: {4625    // Since round even is the assumed rounding mode for unconstrained FP4626    // operations, rint and roundeven are the same operation.4627    changeOpcode(MI, TargetOpcode::G_INTRINSIC_ROUNDEVEN);4628    return Legalized;4629  }4630  case TargetOpcode::G_INTRINSIC_LRINT:4631  case TargetOpcode::G_INTRINSIC_LLRINT: {4632    Register DstReg = MI.getOperand(0).getReg();4633    Register SrcReg = MI.getOperand(1).getReg();4634    LLT SrcTy = MRI.getType(SrcReg);4635    auto Round =4636        MIRBuilder.buildInstr(TargetOpcode::G_FRINT, {SrcTy}, {SrcReg});4637    MIRBuilder.buildFPTOSI(DstReg, Round);4638    MI.eraseFromParent();4639    return Legalized;4640  }4641  case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {4642    auto [OldValRes, SuccessRes, Addr, CmpVal, NewVal] = MI.getFirst5Regs();4643    Register NewOldValRes = MRI.cloneVirtualRegister(OldValRes);4644    MIRBuilder.buildAtomicCmpXchg(NewOldValRes, Addr, CmpVal, NewVal,4645                                  **MI.memoperands_begin());4646    MIRBuilder.buildICmp(CmpInst::ICMP_EQ, SuccessRes, NewOldValRes, CmpVal);4647    MIRBuilder.buildCopy(OldValRes, NewOldValRes);4648    MI.eraseFromParent();4649    return Legalized;4650  }4651  case TargetOpcode::G_LOAD:4652  case TargetOpcode::G_SEXTLOAD:4653  case TargetOpcode::G_ZEXTLOAD:4654    return lowerLoad(cast<GAnyLoad>(MI));4655  case TargetOpcode::G_STORE:4656    return lowerStore(cast<GStore>(MI));4657  case TargetOpcode::G_CTLZ_ZERO_UNDEF:4658  case TargetOpcode::G_CTTZ_ZERO_UNDEF:4659  case TargetOpcode::G_CTLZ:4660  case TargetOpcode::G_CTTZ:4661  case TargetOpcode::G_CTPOP:4662    return lowerBitCount(MI);4663  case G_UADDO: {4664    auto [Res, CarryOut, LHS, RHS] = MI.getFirst4Regs();4665 4666    Register NewRes = MRI.cloneVirtualRegister(Res);4667 4668    MIRBuilder.buildAdd(NewRes, LHS, RHS);4669    MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CarryOut, NewRes, RHS);4670 4671    MIRBuilder.buildCopy(Res, NewRes);4672 4673    MI.eraseFromParent();4674    return Legalized;4675  }4676  case G_UADDE: {4677    auto [Res, CarryOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();4678    const LLT CondTy = MRI.getType(CarryOut);4679    const LLT Ty = MRI.getType(Res);4680 4681    Register NewRes = MRI.cloneVirtualRegister(Res);4682 4683    // Initial add of the two operands.4684    auto TmpRes = MIRBuilder.buildAdd(Ty, LHS, RHS);4685 4686    // Initial check for carry.4687    auto Carry = MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CondTy, TmpRes, LHS);4688 4689    // Add the sum and the carry.4690    auto ZExtCarryIn = MIRBuilder.buildZExt(Ty, CarryIn);4691    MIRBuilder.buildAdd(NewRes, TmpRes, ZExtCarryIn);4692 4693    // Second check for carry. We can only carry if the initial sum is all 1s4694    // and the carry is set, resulting in a new sum of 0.4695    auto Zero = MIRBuilder.buildConstant(Ty, 0);4696    auto ResEqZero =4697        MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, NewRes, Zero);4698    auto Carry2 = MIRBuilder.buildAnd(CondTy, ResEqZero, CarryIn);4699    MIRBuilder.buildOr(CarryOut, Carry, Carry2);4700 4701    MIRBuilder.buildCopy(Res, NewRes);4702 4703    MI.eraseFromParent();4704    return Legalized;4705  }4706  case G_USUBO: {4707    auto [Res, BorrowOut, LHS, RHS] = MI.getFirst4Regs();4708 4709    MIRBuilder.buildSub(Res, LHS, RHS);4710    MIRBuilder.buildICmp(CmpInst::ICMP_ULT, BorrowOut, LHS, RHS);4711 4712    MI.eraseFromParent();4713    return Legalized;4714  }4715  case G_USUBE: {4716    auto [Res, BorrowOut, LHS, RHS, BorrowIn] = MI.getFirst5Regs();4717    const LLT CondTy = MRI.getType(BorrowOut);4718    const LLT Ty = MRI.getType(Res);4719 4720    // Initial subtract of the two operands.4721    auto TmpRes = MIRBuilder.buildSub(Ty, LHS, RHS);4722 4723    // Initial check for borrow.4724    auto Borrow = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, CondTy, TmpRes, LHS);4725 4726    // Subtract the borrow from the first subtract.4727    auto ZExtBorrowIn = MIRBuilder.buildZExt(Ty, BorrowIn);4728    MIRBuilder.buildSub(Res, TmpRes, ZExtBorrowIn);4729 4730    // Second check for borrow. We can only borrow if the initial difference is4731    // 0 and the borrow is set, resulting in a new difference of all 1s.4732    auto Zero = MIRBuilder.buildConstant(Ty, 0);4733    auto TmpResEqZero =4734        MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, TmpRes, Zero);4735    auto Borrow2 = MIRBuilder.buildAnd(CondTy, TmpResEqZero, BorrowIn);4736    MIRBuilder.buildOr(BorrowOut, Borrow, Borrow2);4737 4738    MI.eraseFromParent();4739    return Legalized;4740  }4741  case G_UITOFP:4742    return lowerUITOFP(MI);4743  case G_SITOFP:4744    return lowerSITOFP(MI);4745  case G_FPTOUI:4746    return lowerFPTOUI(MI);4747  case G_FPTOSI:4748    return lowerFPTOSI(MI);4749  case G_FPTOUI_SAT:4750  case G_FPTOSI_SAT:4751    return lowerFPTOINT_SAT(MI);4752  case G_FPTRUNC:4753    return lowerFPTRUNC(MI);4754  case G_FPOWI:4755    return lowerFPOWI(MI);4756  case G_SMIN:4757  case G_SMAX:4758  case G_UMIN:4759  case G_UMAX:4760    return lowerMinMax(MI);4761  case G_SCMP:4762  case G_UCMP:4763    return lowerThreewayCompare(MI);4764  case G_FCOPYSIGN:4765    return lowerFCopySign(MI);4766  case G_FMINNUM:4767  case G_FMAXNUM:4768  case G_FMINIMUMNUM:4769  case G_FMAXIMUMNUM:4770    return lowerFMinNumMaxNum(MI);4771  case G_FMINIMUM:4772  case G_FMAXIMUM:4773    return lowerFMinimumMaximum(MI);4774  case G_MERGE_VALUES:4775    return lowerMergeValues(MI);4776  case G_UNMERGE_VALUES:4777    return lowerUnmergeValues(MI);4778  case TargetOpcode::G_SEXT_INREG: {4779    assert(MI.getOperand(2).isImm() && "Expected immediate");4780    int64_t SizeInBits = MI.getOperand(2).getImm();4781 4782    auto [DstReg, SrcReg] = MI.getFirst2Regs();4783    LLT DstTy = MRI.getType(DstReg);4784    Register TmpRes = MRI.createGenericVirtualRegister(DstTy);4785 4786    auto MIBSz = MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - SizeInBits);4787    MIRBuilder.buildShl(TmpRes, SrcReg, MIBSz->getOperand(0));4788    MIRBuilder.buildAShr(DstReg, TmpRes, MIBSz->getOperand(0));4789    MI.eraseFromParent();4790    return Legalized;4791  }4792  case G_EXTRACT_VECTOR_ELT:4793  case G_INSERT_VECTOR_ELT:4794    return lowerExtractInsertVectorElt(MI);4795  case G_SHUFFLE_VECTOR:4796    return lowerShuffleVector(MI);4797  case G_VECTOR_COMPRESS:4798    return lowerVECTOR_COMPRESS(MI);4799  case G_DYN_STACKALLOC:4800    return lowerDynStackAlloc(MI);4801  case G_STACKSAVE:4802    return lowerStackSave(MI);4803  case G_STACKRESTORE:4804    return lowerStackRestore(MI);4805  case G_EXTRACT:4806    return lowerExtract(MI);4807  case G_INSERT:4808    return lowerInsert(MI);4809  case G_BSWAP:4810    return lowerBswap(MI);4811  case G_BITREVERSE:4812    return lowerBitreverse(MI);4813  case G_READ_REGISTER:4814  case G_WRITE_REGISTER:4815    return lowerReadWriteRegister(MI);4816  case G_UADDSAT:4817  case G_USUBSAT: {4818    // Try to make a reasonable guess about which lowering strategy to use. The4819    // target can override this with custom lowering and calling the4820    // implementation functions.4821    LLT Ty = MRI.getType(MI.getOperand(0).getReg());4822    if (LI.isLegalOrCustom({G_UMIN, Ty}))4823      return lowerAddSubSatToMinMax(MI);4824    return lowerAddSubSatToAddoSubo(MI);4825  }4826  case G_SADDSAT:4827  case G_SSUBSAT: {4828    LLT Ty = MRI.getType(MI.getOperand(0).getReg());4829 4830    // FIXME: It would probably make more sense to see if G_SADDO is preferred,4831    // since it's a shorter expansion. However, we would need to figure out the4832    // preferred boolean type for the carry out for the query.4833    if (LI.isLegalOrCustom({G_SMIN, Ty}) && LI.isLegalOrCustom({G_SMAX, Ty}))4834      return lowerAddSubSatToMinMax(MI);4835    return lowerAddSubSatToAddoSubo(MI);4836  }4837  case G_SSHLSAT:4838  case G_USHLSAT:4839    return lowerShlSat(MI);4840  case G_ABS:4841    return lowerAbsToAddXor(MI);4842  case G_ABDS:4843  case G_ABDU: {4844    bool IsSigned = MI.getOpcode() == G_ABDS;4845    LLT Ty = MRI.getType(MI.getOperand(0).getReg());4846    if ((IsSigned && LI.isLegal({G_SMIN, Ty}) && LI.isLegal({G_SMAX, Ty})) ||4847        (!IsSigned && LI.isLegal({G_UMIN, Ty}) && LI.isLegal({G_UMAX, Ty}))) {4848      return lowerAbsDiffToMinMax(MI);4849    }4850    return lowerAbsDiffToSelect(MI);4851  }4852  case G_FABS:4853    return lowerFAbs(MI);4854  case G_SELECT:4855    return lowerSelect(MI);4856  case G_IS_FPCLASS:4857    return lowerISFPCLASS(MI);4858  case G_SDIVREM:4859  case G_UDIVREM:4860    return lowerDIVREM(MI);4861  case G_FSHL:4862  case G_FSHR:4863    return lowerFunnelShift(MI);4864  case G_ROTL:4865  case G_ROTR:4866    return lowerRotate(MI);4867  case G_MEMSET:4868  case G_MEMCPY:4869  case G_MEMMOVE:4870    return lowerMemCpyFamily(MI);4871  case G_MEMCPY_INLINE:4872    return lowerMemcpyInline(MI);4873  case G_ZEXT:4874  case G_SEXT:4875  case G_ANYEXT:4876    return lowerEXT(MI);4877  case G_TRUNC:4878    return lowerTRUNC(MI);4879  GISEL_VECREDUCE_CASES_NONSEQ4880    return lowerVectorReduction(MI);4881  case G_VAARG:4882    return lowerVAArg(MI);4883  case G_ATOMICRMW_SUB: {4884    auto [Ret, Mem, Val] = MI.getFirst3Regs();4885    const LLT ValTy = MRI.getType(Val);4886    MachineMemOperand *MMO = *MI.memoperands_begin();4887 4888    auto VNeg = MIRBuilder.buildNeg(ValTy, Val);4889    MIRBuilder.buildAtomicRMW(G_ATOMICRMW_ADD, Ret, Mem, VNeg, *MMO);4890    MI.eraseFromParent();4891    return Legalized;4892  }4893  }4894}4895 4896Align LegalizerHelper::getStackTemporaryAlignment(LLT Ty,4897                                                  Align MinAlign) const {4898  // FIXME: We're missing a way to go back from LLT to llvm::Type to query the4899  // datalayout for the preferred alignment. Also there should be a target hook4900  // for this to allow targets to reduce the alignment and ignore the4901  // datalayout. e.g. AMDGPU should always use a 4-byte alignment, regardless of4902  // the type.4903  return std::max(Align(PowerOf2Ceil(Ty.getSizeInBytes())), MinAlign);4904}4905 4906MachineInstrBuilder4907LegalizerHelper::createStackTemporary(TypeSize Bytes, Align Alignment,4908                                      MachinePointerInfo &PtrInfo) {4909  MachineFunction &MF = MIRBuilder.getMF();4910  const DataLayout &DL = MIRBuilder.getDataLayout();4911  int FrameIdx = MF.getFrameInfo().CreateStackObject(Bytes, Alignment, false);4912 4913  unsigned AddrSpace = DL.getAllocaAddrSpace();4914  LLT FramePtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));4915 4916  PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIdx);4917  return MIRBuilder.buildFrameIndex(FramePtrTy, FrameIdx);4918}4919 4920MachineInstrBuilder LegalizerHelper::createStackStoreLoad(const DstOp &Res,4921                                                          const SrcOp &Val) {4922  LLT SrcTy = Val.getLLTTy(MRI);4923  Align StackTypeAlign =4924      std::max(getStackTemporaryAlignment(SrcTy),4925               getStackTemporaryAlignment(Res.getLLTTy(MRI)));4926  MachinePointerInfo PtrInfo;4927  auto StackTemp =4928      createStackTemporary(SrcTy.getSizeInBytes(), StackTypeAlign, PtrInfo);4929 4930  MIRBuilder.buildStore(Val, StackTemp, PtrInfo, StackTypeAlign);4931  return MIRBuilder.buildLoad(Res, StackTemp, PtrInfo, StackTypeAlign);4932}4933 4934static Register clampVectorIndex(MachineIRBuilder &B, Register IdxReg,4935                                 LLT VecTy) {4936  LLT IdxTy = B.getMRI()->getType(IdxReg);4937  unsigned NElts = VecTy.getNumElements();4938 4939  int64_t IdxVal;4940  if (mi_match(IdxReg, *B.getMRI(), m_ICst(IdxVal))) {4941    if (IdxVal < VecTy.getNumElements())4942      return IdxReg;4943    // If a constant index would be out of bounds, clamp it as well.4944  }4945 4946  if (isPowerOf2_32(NElts)) {4947    APInt Imm = APInt::getLowBitsSet(IdxTy.getSizeInBits(), Log2_32(NElts));4948    return B.buildAnd(IdxTy, IdxReg, B.buildConstant(IdxTy, Imm)).getReg(0);4949  }4950 4951  return B.buildUMin(IdxTy, IdxReg, B.buildConstant(IdxTy, NElts - 1))4952      .getReg(0);4953}4954 4955Register LegalizerHelper::getVectorElementPointer(Register VecPtr, LLT VecTy,4956                                                  Register Index) {4957  LLT EltTy = VecTy.getElementType();4958 4959  // Calculate the element offset and add it to the pointer.4960  unsigned EltSize = EltTy.getSizeInBits() / 8; // FIXME: should be ABI size.4961  assert(EltSize * 8 == EltTy.getSizeInBits() &&4962         "Converting bits to bytes lost precision");4963 4964  Index = clampVectorIndex(MIRBuilder, Index, VecTy);4965 4966  // Convert index to the correct size for the address space.4967  const DataLayout &DL = MIRBuilder.getDataLayout();4968  unsigned AS = MRI.getType(VecPtr).getAddressSpace();4969  unsigned IndexSizeInBits = DL.getIndexSize(AS) * 8;4970  LLT IdxTy = MRI.getType(Index).changeElementSize(IndexSizeInBits);4971  if (IdxTy != MRI.getType(Index))4972    Index = MIRBuilder.buildSExtOrTrunc(IdxTy, Index).getReg(0);4973 4974  auto Mul = MIRBuilder.buildMul(IdxTy, Index,4975                                 MIRBuilder.buildConstant(IdxTy, EltSize));4976 4977  LLT PtrTy = MRI.getType(VecPtr);4978  return MIRBuilder.buildPtrAdd(PtrTy, VecPtr, Mul).getReg(0);4979}4980 4981#ifndef NDEBUG4982/// Check that all vector operands have same number of elements. Other operands4983/// should be listed in NonVecOp.4984static bool hasSameNumEltsOnAllVectorOperands(4985    GenericMachineInstr &MI, MachineRegisterInfo &MRI,4986    std::initializer_list<unsigned> NonVecOpIndices) {4987  if (MI.getNumMemOperands() != 0)4988    return false;4989 4990  LLT VecTy = MRI.getType(MI.getReg(0));4991  if (!VecTy.isVector())4992    return false;4993  unsigned NumElts = VecTy.getNumElements();4994 4995  for (unsigned OpIdx = 1; OpIdx < MI.getNumOperands(); ++OpIdx) {4996    MachineOperand &Op = MI.getOperand(OpIdx);4997    if (!Op.isReg()) {4998      if (!is_contained(NonVecOpIndices, OpIdx))4999        return false;5000      continue;5001    }5002 5003    LLT Ty = MRI.getType(Op.getReg());5004    if (!Ty.isVector()) {5005      if (!is_contained(NonVecOpIndices, OpIdx))5006        return false;5007      continue;5008    }5009 5010    if (Ty.getNumElements() != NumElts)5011      return false;5012  }5013 5014  return true;5015}5016#endif5017 5018/// Fill \p DstOps with DstOps that have same number of elements combined as5019/// the Ty. These DstOps have either scalar type when \p NumElts = 1 or are5020/// vectors with \p NumElts elements. When Ty.getNumElements() is not multiple5021/// of \p NumElts last DstOp (leftover) has fewer then \p NumElts elements.5022static void makeDstOps(SmallVectorImpl<DstOp> &DstOps, LLT Ty,5023                       unsigned NumElts) {5024  LLT LeftoverTy;5025  assert(Ty.isVector() && "Expected vector type");5026  LLT EltTy = Ty.getElementType();5027  LLT NarrowTy = (NumElts == 1) ? EltTy : LLT::fixed_vector(NumElts, EltTy);5028  int NumParts, NumLeftover;5029  std::tie(NumParts, NumLeftover) =5030      getNarrowTypeBreakDown(Ty, NarrowTy, LeftoverTy);5031 5032  assert(NumParts > 0 && "Error in getNarrowTypeBreakDown");5033  for (int i = 0; i < NumParts; ++i) {5034    DstOps.push_back(NarrowTy);5035  }5036 5037  if (LeftoverTy.isValid()) {5038    assert(NumLeftover == 1 && "expected exactly one leftover");5039    DstOps.push_back(LeftoverTy);5040  }5041}5042 5043/// Operand \p Op is used on \p N sub-instructions. Fill \p Ops with \p N SrcOps5044/// made from \p Op depending on operand type.5045static void broadcastSrcOp(SmallVectorImpl<SrcOp> &Ops, unsigned N,5046                           MachineOperand &Op) {5047  for (unsigned i = 0; i < N; ++i) {5048    if (Op.isReg())5049      Ops.push_back(Op.getReg());5050    else if (Op.isImm())5051      Ops.push_back(Op.getImm());5052    else if (Op.isPredicate())5053      Ops.push_back(static_cast<CmpInst::Predicate>(Op.getPredicate()));5054    else5055      llvm_unreachable("Unsupported type");5056  }5057}5058 5059// Handle splitting vector operations which need to have the same number of5060// elements in each type index, but each type index may have a different element5061// type.5062//5063// e.g.  <4 x s64> = G_SHL <4 x s64>, <4 x s32> ->5064//       <2 x s64> = G_SHL <2 x s64>, <2 x s32>5065//       <2 x s64> = G_SHL <2 x s64>, <2 x s32>5066//5067// Also handles some irregular breakdown cases, e.g.5068// e.g.  <3 x s64> = G_SHL <3 x s64>, <3 x s32> ->5069//       <2 x s64> = G_SHL <2 x s64>, <2 x s32>5070//             s64 = G_SHL s64, s325071LegalizerHelper::LegalizeResult5072LegalizerHelper::fewerElementsVectorMultiEltType(5073    GenericMachineInstr &MI, unsigned NumElts,5074    std::initializer_list<unsigned> NonVecOpIndices) {5075  assert(hasSameNumEltsOnAllVectorOperands(MI, MRI, NonVecOpIndices) &&5076         "Non-compatible opcode or not specified non-vector operands");5077  unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();5078 5079  unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();5080  unsigned NumDefs = MI.getNumDefs();5081 5082  // Create DstOps (sub-vectors with NumElts elts + Leftover) for each output.5083  // Build instructions with DstOps to use instruction found by CSE directly.5084  // CSE copies found instruction into given vreg when building with vreg dest.5085  SmallVector<SmallVector<DstOp, 8>, 2> OutputOpsPieces(NumDefs);5086  // Output registers will be taken from created instructions.5087  SmallVector<SmallVector<Register, 8>, 2> OutputRegs(NumDefs);5088  for (unsigned i = 0; i < NumDefs; ++i) {5089    makeDstOps(OutputOpsPieces[i], MRI.getType(MI.getReg(i)), NumElts);5090  }5091 5092  // Split vector input operands into sub-vectors with NumElts elts + Leftover.5093  // Operands listed in NonVecOpIndices will be used as is without splitting;5094  // examples: compare predicate in icmp and fcmp (op 1), vector select with i15095  // scalar condition (op 1), immediate in sext_inreg (op 2).5096  SmallVector<SmallVector<SrcOp, 8>, 3> InputOpsPieces(NumInputs);5097  for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();5098       ++UseIdx, ++UseNo) {5099    if (is_contained(NonVecOpIndices, UseIdx)) {5100      broadcastSrcOp(InputOpsPieces[UseNo], OutputOpsPieces[0].size(),5101                     MI.getOperand(UseIdx));5102    } else {5103      SmallVector<Register, 8> SplitPieces;5104      extractVectorParts(MI.getReg(UseIdx), NumElts, SplitPieces, MIRBuilder,5105                         MRI);5106      llvm::append_range(InputOpsPieces[UseNo], SplitPieces);5107    }5108  }5109 5110  unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;5111 5112  // Take i-th piece of each input operand split and build sub-vector/scalar5113  // instruction. Set i-th DstOp(s) from OutputOpsPieces as destination(s).5114  for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {5115    SmallVector<DstOp, 2> Defs;5116    for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)5117      Defs.push_back(OutputOpsPieces[DstNo][i]);5118 5119    SmallVector<SrcOp, 3> Uses;5120    for (unsigned InputNo = 0; InputNo < NumInputs; ++InputNo)5121      Uses.push_back(InputOpsPieces[InputNo][i]);5122 5123    auto I = MIRBuilder.buildInstr(MI.getOpcode(), Defs, Uses, MI.getFlags());5124    for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)5125      OutputRegs[DstNo].push_back(I.getReg(DstNo));5126  }5127 5128  // Merge small outputs into MI's output for each def operand.5129  if (NumLeftovers) {5130    for (unsigned i = 0; i < NumDefs; ++i)5131      mergeMixedSubvectors(MI.getReg(i), OutputRegs[i]);5132  } else {5133    for (unsigned i = 0; i < NumDefs; ++i)5134      MIRBuilder.buildMergeLikeInstr(MI.getReg(i), OutputRegs[i]);5135  }5136 5137  MI.eraseFromParent();5138  return Legalized;5139}5140 5141LegalizerHelper::LegalizeResult5142LegalizerHelper::fewerElementsVectorPhi(GenericMachineInstr &MI,5143                                        unsigned NumElts) {5144  unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();5145 5146  unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();5147  unsigned NumDefs = MI.getNumDefs();5148 5149  SmallVector<DstOp, 8> OutputOpsPieces;5150  SmallVector<Register, 8> OutputRegs;5151  makeDstOps(OutputOpsPieces, MRI.getType(MI.getReg(0)), NumElts);5152 5153  // Instructions that perform register split will be inserted in basic block5154  // where register is defined (basic block is in the next operand).5155  SmallVector<SmallVector<Register, 8>, 3> InputOpsPieces(NumInputs / 2);5156  for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();5157       UseIdx += 2, ++UseNo) {5158    MachineBasicBlock &OpMBB = *MI.getOperand(UseIdx + 1).getMBB();5159    MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());5160    extractVectorParts(MI.getReg(UseIdx), NumElts, InputOpsPieces[UseNo],5161                       MIRBuilder, MRI);5162  }5163 5164  // Build PHIs with fewer elements.5165  unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;5166  MIRBuilder.setInsertPt(*MI.getParent(), MI);5167  for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {5168    auto Phi = MIRBuilder.buildInstr(TargetOpcode::G_PHI);5169    Phi.addDef(5170        MRI.createGenericVirtualRegister(OutputOpsPieces[i].getLLTTy(MRI)));5171    OutputRegs.push_back(Phi.getReg(0));5172 5173    for (unsigned j = 0; j < NumInputs / 2; ++j) {5174      Phi.addUse(InputOpsPieces[j][i]);5175      Phi.add(MI.getOperand(1 + j * 2 + 1));5176    }5177  }5178 5179  // Set the insert point after the existing PHIs5180  MachineBasicBlock &MBB = *MI.getParent();5181  MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());5182 5183  // Merge small outputs into MI's def.5184  if (NumLeftovers) {5185    mergeMixedSubvectors(MI.getReg(0), OutputRegs);5186  } else {5187    MIRBuilder.buildMergeLikeInstr(MI.getReg(0), OutputRegs);5188  }5189 5190  MI.eraseFromParent();5191  return Legalized;5192}5193 5194LegalizerHelper::LegalizeResult5195LegalizerHelper::fewerElementsVectorUnmergeValues(MachineInstr &MI,5196                                                  unsigned TypeIdx,5197                                                  LLT NarrowTy) {5198  const int NumDst = MI.getNumOperands() - 1;5199  const Register SrcReg = MI.getOperand(NumDst).getReg();5200  LLT DstTy = MRI.getType(MI.getOperand(0).getReg());5201  LLT SrcTy = MRI.getType(SrcReg);5202 5203  if (TypeIdx != 1 || NarrowTy == DstTy)5204    return UnableToLegalize;5205 5206  // Requires compatible types. Otherwise SrcReg should have been defined by5207  // merge-like instruction that would get artifact combined. Most likely5208  // instruction that defines SrcReg has to perform more/fewer elements5209  // legalization compatible with NarrowTy.5210  assert(SrcTy.isVector() && NarrowTy.isVector() && "Expected vector types");5211  assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");5212 5213  if ((SrcTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||5214      (NarrowTy.getSizeInBits() % DstTy.getSizeInBits() != 0))5215    return UnableToLegalize;5216 5217  // This is most likely DstTy (smaller then register size) packed in SrcTy5218  // (larger then register size) and since unmerge was not combined it will be5219  // lowered to bit sequence extracts from register. Unpack SrcTy to NarrowTy5220  // (register size) pieces first. Then unpack each of NarrowTy pieces to DstTy.5221 5222  // %1:_(DstTy), %2, %3, %4 = G_UNMERGE_VALUES %0:_(SrcTy)5223  //5224  // %5:_(NarrowTy), %6 = G_UNMERGE_VALUES %0:_(SrcTy) - reg sequence5225  // %1:_(DstTy), %2 = G_UNMERGE_VALUES %5:_(NarrowTy) - sequence of bits in reg5226  // %3:_(DstTy), %4 = G_UNMERGE_VALUES %6:_(NarrowTy)5227  auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);5228  const int NumUnmerge = Unmerge->getNumOperands() - 1;5229  const int PartsPerUnmerge = NumDst / NumUnmerge;5230 5231  for (int I = 0; I != NumUnmerge; ++I) {5232    auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);5233 5234    for (int J = 0; J != PartsPerUnmerge; ++J)5235      MIB.addDef(MI.getOperand(I * PartsPerUnmerge + J).getReg());5236    MIB.addUse(Unmerge.getReg(I));5237  }5238 5239  MI.eraseFromParent();5240  return Legalized;5241}5242 5243LegalizerHelper::LegalizeResult5244LegalizerHelper::fewerElementsVectorMerge(MachineInstr &MI, unsigned TypeIdx,5245                                          LLT NarrowTy) {5246  auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();5247  // Requires compatible types. Otherwise user of DstReg did not perform unmerge5248  // that should have been artifact combined. Most likely instruction that uses5249  // DstReg has to do more/fewer elements legalization compatible with NarrowTy.5250  assert(DstTy.isVector() && NarrowTy.isVector() && "Expected vector types");5251  assert((DstTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");5252  if (NarrowTy == SrcTy)5253    return UnableToLegalize;5254 5255  // This attempts to lower part of LCMTy merge/unmerge sequence. Intended use5256  // is for old mir tests. Since the changes to more/fewer elements it should no5257  // longer be possible to generate MIR like this when starting from llvm-ir5258  // because LCMTy approach was replaced with merge/unmerge to vector elements.5259  if (TypeIdx == 1) {5260    assert(SrcTy.isVector() && "Expected vector types");5261    assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");5262    if ((DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||5263        (NarrowTy.getNumElements() >= SrcTy.getNumElements()))5264      return UnableToLegalize;5265    // %2:_(DstTy) = G_CONCAT_VECTORS %0:_(SrcTy), %1:_(SrcTy)5266    //5267    // %3:_(EltTy), %4, %5 = G_UNMERGE_VALUES %0:_(SrcTy)5268    // %6:_(EltTy), %7, %8 = G_UNMERGE_VALUES %1:_(SrcTy)5269    // %9:_(NarrowTy) = G_BUILD_VECTOR %3:_(EltTy), %45270    // %10:_(NarrowTy) = G_BUILD_VECTOR %5:_(EltTy), %65271    // %11:_(NarrowTy) = G_BUILD_VECTOR %7:_(EltTy), %85272    // %2:_(DstTy) = G_CONCAT_VECTORS %9:_(NarrowTy), %10, %115273 5274    SmallVector<Register, 8> Elts;5275    LLT EltTy = MRI.getType(MI.getOperand(1).getReg()).getScalarType();5276    for (unsigned i = 1; i < MI.getNumOperands(); ++i) {5277      auto Unmerge = MIRBuilder.buildUnmerge(EltTy, MI.getOperand(i).getReg());5278      for (unsigned j = 0; j < Unmerge->getNumDefs(); ++j)5279        Elts.push_back(Unmerge.getReg(j));5280    }5281 5282    SmallVector<Register, 8> NarrowTyElts;5283    unsigned NumNarrowTyElts = NarrowTy.getNumElements();5284    unsigned NumNarrowTyPieces = DstTy.getNumElements() / NumNarrowTyElts;5285    for (unsigned i = 0, Offset = 0; i < NumNarrowTyPieces;5286         ++i, Offset += NumNarrowTyElts) {5287      ArrayRef<Register> Pieces(&Elts[Offset], NumNarrowTyElts);5288      NarrowTyElts.push_back(5289          MIRBuilder.buildMergeLikeInstr(NarrowTy, Pieces).getReg(0));5290    }5291 5292    MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);5293    MI.eraseFromParent();5294    return Legalized;5295  }5296 5297  assert(TypeIdx == 0 && "Bad type index");5298  if ((NarrowTy.getSizeInBits() % SrcTy.getSizeInBits() != 0) ||5299      (DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0))5300    return UnableToLegalize;5301 5302  // This is most likely SrcTy (smaller then register size) packed in DstTy5303  // (larger then register size) and since merge was not combined it will be5304  // lowered to bit sequence packing into register. Merge SrcTy to NarrowTy5305  // (register size) pieces first. Then merge each of NarrowTy pieces to DstTy.5306 5307  // %0:_(DstTy) = G_MERGE_VALUES %1:_(SrcTy), %2, %3, %45308  //5309  // %5:_(NarrowTy) = G_MERGE_VALUES %1:_(SrcTy), %2 - sequence of bits in reg5310  // %6:_(NarrowTy) = G_MERGE_VALUES %3:_(SrcTy), %45311  // %0:_(DstTy)  = G_MERGE_VALUES %5:_(NarrowTy), %6 - reg sequence5312  SmallVector<Register, 8> NarrowTyElts;5313  unsigned NumParts = DstTy.getNumElements() / NarrowTy.getNumElements();5314  unsigned NumSrcElts = SrcTy.isVector() ? SrcTy.getNumElements() : 1;5315  unsigned NumElts = NarrowTy.getNumElements() / NumSrcElts;5316  for (unsigned i = 0; i < NumParts; ++i) {5317    SmallVector<Register, 8> Sources;5318    for (unsigned j = 0; j < NumElts; ++j)5319      Sources.push_back(MI.getOperand(1 + i * NumElts + j).getReg());5320    NarrowTyElts.push_back(5321        MIRBuilder.buildMergeLikeInstr(NarrowTy, Sources).getReg(0));5322  }5323 5324  MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);5325  MI.eraseFromParent();5326  return Legalized;5327}5328 5329LegalizerHelper::LegalizeResult5330LegalizerHelper::fewerElementsVectorExtractInsertVectorElt(MachineInstr &MI,5331                                                           unsigned TypeIdx,5332                                                           LLT NarrowVecTy) {5333  auto [DstReg, SrcVec] = MI.getFirst2Regs();5334  Register InsertVal;5335  bool IsInsert = MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT;5336 5337  assert((IsInsert ? TypeIdx == 0 : TypeIdx == 1) && "not a vector type index");5338  if (IsInsert)5339    InsertVal = MI.getOperand(2).getReg();5340 5341  Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();5342  LLT VecTy = MRI.getType(SrcVec);5343 5344  // If the index is a constant, we can really break this down as you would5345  // expect, and index into the target size pieces.5346  auto MaybeCst = getIConstantVRegValWithLookThrough(Idx, MRI);5347  if (MaybeCst) {5348    uint64_t IdxVal = MaybeCst->Value.getZExtValue();5349    // Avoid out of bounds indexing the pieces.5350    if (IdxVal >= VecTy.getNumElements()) {5351      MIRBuilder.buildUndef(DstReg);5352      MI.eraseFromParent();5353      return Legalized;5354    }5355 5356    if (!NarrowVecTy.isVector()) {5357      SmallVector<Register, 8> SplitPieces;5358      extractParts(MI.getOperand(1).getReg(), NarrowVecTy,5359                   VecTy.getNumElements(), SplitPieces, MIRBuilder, MRI);5360      if (IsInsert) {5361        SplitPieces[IdxVal] = InsertVal;5362        MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), SplitPieces);5363      } else {5364        MIRBuilder.buildCopy(MI.getOperand(0).getReg(), SplitPieces[IdxVal]);5365      }5366    } else {5367      SmallVector<Register, 8> VecParts;5368      LLT GCDTy = extractGCDType(VecParts, VecTy, NarrowVecTy, SrcVec);5369 5370      // Build a sequence of NarrowTy pieces in VecParts for this operand.5371      LLT LCMTy = buildLCMMergePieces(VecTy, NarrowVecTy, GCDTy, VecParts,5372                                      TargetOpcode::G_ANYEXT);5373 5374      unsigned NewNumElts = NarrowVecTy.getNumElements();5375 5376      LLT IdxTy = MRI.getType(Idx);5377      int64_t PartIdx = IdxVal / NewNumElts;5378      auto NewIdx =5379          MIRBuilder.buildConstant(IdxTy, IdxVal - NewNumElts * PartIdx);5380 5381      if (IsInsert) {5382        LLT PartTy = MRI.getType(VecParts[PartIdx]);5383 5384        // Use the adjusted index to insert into one of the subvectors.5385        auto InsertPart = MIRBuilder.buildInsertVectorElement(5386            PartTy, VecParts[PartIdx], InsertVal, NewIdx);5387        VecParts[PartIdx] = InsertPart.getReg(0);5388 5389        // Recombine the inserted subvector with the others to reform the result5390        // vector.5391        buildWidenedRemergeToDst(DstReg, LCMTy, VecParts);5392      } else {5393        MIRBuilder.buildExtractVectorElement(DstReg, VecParts[PartIdx], NewIdx);5394      }5395    }5396 5397    MI.eraseFromParent();5398    return Legalized;5399  }5400 5401  // With a variable index, we can't perform the operation in a smaller type, so5402  // we're forced to expand this.5403  //5404  // TODO: We could emit a chain of compare/select to figure out which piece to5405  // index.5406  return lowerExtractInsertVectorElt(MI);5407}5408 5409LegalizerHelper::LegalizeResult5410LegalizerHelper::reduceLoadStoreWidth(GLoadStore &LdStMI, unsigned TypeIdx,5411                                      LLT NarrowTy) {5412  // FIXME: Don't know how to handle secondary types yet.5413  if (TypeIdx != 0)5414    return UnableToLegalize;5415 5416  if (!NarrowTy.isByteSized()) {5417    LLVM_DEBUG(dbgs() << "Can't narrow load/store to non-byte-sized type\n");5418    return UnableToLegalize;5419  }5420 5421  // This implementation doesn't work for atomics. Give up instead of doing5422  // something invalid.5423  if (LdStMI.isAtomic())5424    return UnableToLegalize;5425 5426  bool IsLoad = isa<GLoad>(LdStMI);5427  Register ValReg = LdStMI.getReg(0);5428  Register AddrReg = LdStMI.getPointerReg();5429  LLT ValTy = MRI.getType(ValReg);5430 5431  // FIXME: Do we need a distinct NarrowMemory legalize action?5432  if (ValTy.getSizeInBits() != 8 * LdStMI.getMemSize().getValue()) {5433    LLVM_DEBUG(dbgs() << "Can't narrow extload/truncstore\n");5434    return UnableToLegalize;5435  }5436 5437  int NumParts = -1;5438  int NumLeftover = -1;5439  LLT LeftoverTy;5440  SmallVector<Register, 8> NarrowRegs, NarrowLeftoverRegs;5441  if (IsLoad) {5442    std::tie(NumParts, NumLeftover) = getNarrowTypeBreakDown(ValTy, NarrowTy, LeftoverTy);5443  } else {5444    if (extractParts(ValReg, ValTy, NarrowTy, LeftoverTy, NarrowRegs,5445                     NarrowLeftoverRegs, MIRBuilder, MRI)) {5446      NumParts = NarrowRegs.size();5447      NumLeftover = NarrowLeftoverRegs.size();5448    }5449  }5450 5451  if (NumParts == -1)5452    return UnableToLegalize;5453 5454  LLT PtrTy = MRI.getType(AddrReg);5455  const LLT OffsetTy = LLT::scalar(PtrTy.getSizeInBits());5456 5457  unsigned TotalSize = ValTy.getSizeInBits();5458 5459  // Split the load/store into PartTy sized pieces starting at Offset. If this5460  // is a load, return the new registers in ValRegs. For a store, each elements5461  // of ValRegs should be PartTy. Returns the next offset that needs to be5462  // handled.5463  bool isBigEndian = MIRBuilder.getDataLayout().isBigEndian();5464  auto MMO = LdStMI.getMMO();5465  auto splitTypePieces = [=](LLT PartTy, SmallVectorImpl<Register> &ValRegs,5466                             unsigned NumParts, unsigned Offset) -> unsigned {5467    MachineFunction &MF = MIRBuilder.getMF();5468    unsigned PartSize = PartTy.getSizeInBits();5469    for (unsigned Idx = 0, E = NumParts; Idx != E && Offset < TotalSize;5470         ++Idx) {5471      unsigned ByteOffset = Offset / 8;5472      Register NewAddrReg;5473 5474      MIRBuilder.materializeObjectPtrOffset(NewAddrReg, AddrReg, OffsetTy,5475                                            ByteOffset);5476 5477      MachineMemOperand *NewMMO =5478          MF.getMachineMemOperand(&MMO, ByteOffset, PartTy);5479 5480      if (IsLoad) {5481        Register Dst = MRI.createGenericVirtualRegister(PartTy);5482        ValRegs.push_back(Dst);5483        MIRBuilder.buildLoad(Dst, NewAddrReg, *NewMMO);5484      } else {5485        MIRBuilder.buildStore(ValRegs[Idx], NewAddrReg, *NewMMO);5486      }5487      Offset = isBigEndian ? Offset - PartSize : Offset + PartSize;5488    }5489 5490    return Offset;5491  };5492 5493  unsigned Offset = isBigEndian ? TotalSize - NarrowTy.getSizeInBits() : 0;5494  unsigned HandledOffset =5495      splitTypePieces(NarrowTy, NarrowRegs, NumParts, Offset);5496 5497  // Handle the rest of the register if this isn't an even type breakdown.5498  if (LeftoverTy.isValid())5499    splitTypePieces(LeftoverTy, NarrowLeftoverRegs, NumLeftover, HandledOffset);5500 5501  if (IsLoad) {5502    insertParts(ValReg, ValTy, NarrowTy, NarrowRegs,5503                LeftoverTy, NarrowLeftoverRegs);5504  }5505 5506  LdStMI.eraseFromParent();5507  return Legalized;5508}5509 5510LegalizerHelper::LegalizeResult5511LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,5512                                     LLT NarrowTy) {5513  using namespace TargetOpcode;5514  GenericMachineInstr &GMI = cast<GenericMachineInstr>(MI);5515  unsigned NumElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;5516 5517  switch (MI.getOpcode()) {5518  case G_IMPLICIT_DEF:5519  case G_TRUNC:5520  case G_AND:5521  case G_OR:5522  case G_XOR:5523  case G_ADD:5524  case G_SUB:5525  case G_MUL:5526  case G_PTR_ADD:5527  case G_SMULH:5528  case G_UMULH:5529  case G_FADD:5530  case G_FMUL:5531  case G_FSUB:5532  case G_FNEG:5533  case G_FABS:5534  case G_FCANONICALIZE:5535  case G_FDIV:5536  case G_FREM:5537  case G_FMA:5538  case G_FMAD:5539  case G_FPOW:5540  case G_FEXP:5541  case G_FEXP2:5542  case G_FEXP10:5543  case G_FLOG:5544  case G_FLOG2:5545  case G_FLOG10:5546  case G_FLDEXP:5547  case G_FNEARBYINT:5548  case G_FCEIL:5549  case G_FFLOOR:5550  case G_FRINT:5551  case G_INTRINSIC_LRINT:5552  case G_INTRINSIC_LLRINT:5553  case G_INTRINSIC_ROUND:5554  case G_INTRINSIC_ROUNDEVEN:5555  case G_LROUND:5556  case G_LLROUND:5557  case G_INTRINSIC_TRUNC:5558  case G_FMODF:5559  case G_FCOS:5560  case G_FSIN:5561  case G_FTAN:5562  case G_FACOS:5563  case G_FASIN:5564  case G_FATAN:5565  case G_FATAN2:5566  case G_FCOSH:5567  case G_FSINH:5568  case G_FTANH:5569  case G_FSQRT:5570  case G_BSWAP:5571  case G_BITREVERSE:5572  case G_SDIV:5573  case G_UDIV:5574  case G_SREM:5575  case G_UREM:5576  case G_SDIVREM:5577  case G_UDIVREM:5578  case G_SMIN:5579  case G_SMAX:5580  case G_UMIN:5581  case G_UMAX:5582  case G_ABS:5583  case G_FMINNUM:5584  case G_FMAXNUM:5585  case G_FMINNUM_IEEE:5586  case G_FMAXNUM_IEEE:5587  case G_FMINIMUM:5588  case G_FMAXIMUM:5589  case G_FMINIMUMNUM:5590  case G_FMAXIMUMNUM:5591  case G_FSHL:5592  case G_FSHR:5593  case G_ROTL:5594  case G_ROTR:5595  case G_FREEZE:5596  case G_SADDSAT:5597  case G_SSUBSAT:5598  case G_UADDSAT:5599  case G_USUBSAT:5600  case G_UMULO:5601  case G_SMULO:5602  case G_SHL:5603  case G_LSHR:5604  case G_ASHR:5605  case G_SSHLSAT:5606  case G_USHLSAT:5607  case G_CTLZ:5608  case G_CTLZ_ZERO_UNDEF:5609  case G_CTTZ:5610  case G_CTTZ_ZERO_UNDEF:5611  case G_CTPOP:5612  case G_FCOPYSIGN:5613  case G_ZEXT:5614  case G_SEXT:5615  case G_ANYEXT:5616  case G_FPEXT:5617  case G_FPTRUNC:5618  case G_SITOFP:5619  case G_UITOFP:5620  case G_FPTOSI:5621  case G_FPTOUI:5622  case G_FPTOSI_SAT:5623  case G_FPTOUI_SAT:5624  case G_INTTOPTR:5625  case G_PTRTOINT:5626  case G_ADDRSPACE_CAST:5627  case G_UADDO:5628  case G_USUBO:5629  case G_UADDE:5630  case G_USUBE:5631  case G_SADDO:5632  case G_SSUBO:5633  case G_SADDE:5634  case G_SSUBE:5635  case G_STRICT_FADD:5636  case G_STRICT_FSUB:5637  case G_STRICT_FMUL:5638  case G_STRICT_FMA:5639  case G_STRICT_FLDEXP:5640  case G_FFREXP:5641    return fewerElementsVectorMultiEltType(GMI, NumElts);5642  case G_ICMP:5643  case G_FCMP:5644    return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*cpm predicate*/});5645  case G_IS_FPCLASS:5646    return fewerElementsVectorMultiEltType(GMI, NumElts, {2, 3 /*mask,fpsem*/});5647  case G_SELECT:5648    if (MRI.getType(MI.getOperand(1).getReg()).isVector())5649      return fewerElementsVectorMultiEltType(GMI, NumElts);5650    return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*scalar cond*/});5651  case G_PHI:5652    return fewerElementsVectorPhi(GMI, NumElts);5653  case G_UNMERGE_VALUES:5654    return fewerElementsVectorUnmergeValues(MI, TypeIdx, NarrowTy);5655  case G_BUILD_VECTOR:5656    assert(TypeIdx == 0 && "not a vector type index");5657    return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);5658  case G_CONCAT_VECTORS:5659    if (TypeIdx != 1) // TODO: This probably does work as expected already.5660      return UnableToLegalize;5661    return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);5662  case G_EXTRACT_VECTOR_ELT:5663  case G_INSERT_VECTOR_ELT:5664    return fewerElementsVectorExtractInsertVectorElt(MI, TypeIdx, NarrowTy);5665  case G_LOAD:5666  case G_STORE:5667    return reduceLoadStoreWidth(cast<GLoadStore>(MI), TypeIdx, NarrowTy);5668  case G_SEXT_INREG:5669    return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*imm*/});5670  GISEL_VECREDUCE_CASES_NONSEQ5671    return fewerElementsVectorReductions(MI, TypeIdx, NarrowTy);5672  case TargetOpcode::G_VECREDUCE_SEQ_FADD:5673  case TargetOpcode::G_VECREDUCE_SEQ_FMUL:5674    return fewerElementsVectorSeqReductions(MI, TypeIdx, NarrowTy);5675  case G_SHUFFLE_VECTOR:5676    return fewerElementsVectorShuffle(MI, TypeIdx, NarrowTy);5677  case G_FPOWI:5678    return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*pow*/});5679  case G_BITCAST:5680    return fewerElementsBitcast(MI, TypeIdx, NarrowTy);5681  case G_INTRINSIC_FPTRUNC_ROUND:5682    return fewerElementsVectorMultiEltType(GMI, NumElts, {2});5683  default:5684    return UnableToLegalize;5685  }5686}5687 5688LegalizerHelper::LegalizeResult5689LegalizerHelper::fewerElementsBitcast(MachineInstr &MI, unsigned int TypeIdx,5690                                      LLT NarrowTy) {5691  assert(MI.getOpcode() == TargetOpcode::G_BITCAST &&5692         "Not a bitcast operation");5693 5694  if (TypeIdx != 0)5695    return UnableToLegalize;5696 5697  auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();5698 5699  unsigned NewElemCount =5700      NarrowTy.getSizeInBits() / SrcTy.getScalarSizeInBits();5701  SmallVector<Register> SrcVRegs, BitcastVRegs;5702  if (NewElemCount == 1) {5703    LLT SrcNarrowTy = SrcTy.getElementType();5704 5705    auto Unmerge = MIRBuilder.buildUnmerge(SrcNarrowTy, SrcReg);5706    getUnmergeResults(SrcVRegs, *Unmerge);5707  } else {5708    LLT SrcNarrowTy = LLT::fixed_vector(NewElemCount, SrcTy.getElementType());5709 5710    // Split the Src and Dst Reg into smaller registers5711    if (extractGCDType(SrcVRegs, DstTy, SrcNarrowTy, SrcReg) != SrcNarrowTy)5712      return UnableToLegalize;5713  }5714 5715  // Build new smaller bitcast instructions5716  // Not supporting Leftover types for now but will have to5717  for (Register Reg : SrcVRegs)5718    BitcastVRegs.push_back(MIRBuilder.buildBitcast(NarrowTy, Reg).getReg(0));5719 5720  MIRBuilder.buildMergeLikeInstr(DstReg, BitcastVRegs);5721  MI.eraseFromParent();5722  return Legalized;5723}5724 5725LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorShuffle(5726    MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {5727  assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);5728  if (TypeIdx != 0)5729    return UnableToLegalize;5730 5731  auto [DstReg, DstTy, Src1Reg, Src1Ty, Src2Reg, Src2Ty] =5732      MI.getFirst3RegLLTs();5733  ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();5734  // The shuffle should be canonicalized by now.5735  if (DstTy != Src1Ty)5736    return UnableToLegalize;5737  if (DstTy != Src2Ty)5738    return UnableToLegalize;5739 5740  if (!isPowerOf2_32(DstTy.getNumElements()))5741    return UnableToLegalize;5742 5743  // We only support splitting a shuffle into 2, so adjust NarrowTy accordingly.5744  // Further legalization attempts will be needed to do split further.5745  NarrowTy =5746      DstTy.changeElementCount(DstTy.getElementCount().divideCoefficientBy(2));5747  unsigned NewElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;5748 5749  SmallVector<Register> SplitSrc1Regs, SplitSrc2Regs;5750  extractParts(Src1Reg, NarrowTy, 2, SplitSrc1Regs, MIRBuilder, MRI);5751  extractParts(Src2Reg, NarrowTy, 2, SplitSrc2Regs, MIRBuilder, MRI);5752  Register Inputs[4] = {SplitSrc1Regs[0], SplitSrc1Regs[1], SplitSrc2Regs[0],5753                        SplitSrc2Regs[1]};5754 5755  Register Hi, Lo;5756 5757  // If Lo or Hi uses elements from at most two of the four input vectors, then5758  // express it as a vector shuffle of those two inputs.  Otherwise extract the5759  // input elements by hand and construct the Lo/Hi output using a BUILD_VECTOR.5760  SmallVector<int, 16> Ops;5761  for (unsigned High = 0; High < 2; ++High) {5762    Register &Output = High ? Hi : Lo;5763 5764    // Build a shuffle mask for the output, discovering on the fly which5765    // input vectors to use as shuffle operands (recorded in InputUsed).5766    // If building a suitable shuffle vector proves too hard, then bail5767    // out with useBuildVector set.5768    unsigned InputUsed[2] = {-1U, -1U}; // Not yet discovered.5769    unsigned FirstMaskIdx = High * NewElts;5770    bool UseBuildVector = false;5771    for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {5772      // The mask element.  This indexes into the input.5773      int Idx = Mask[FirstMaskIdx + MaskOffset];5774 5775      // The input vector this mask element indexes into.5776      unsigned Input = (unsigned)Idx / NewElts;5777 5778      if (Input >= std::size(Inputs)) {5779        // The mask element does not index into any input vector.5780        Ops.push_back(-1);5781        continue;5782      }5783 5784      // Turn the index into an offset from the start of the input vector.5785      Idx -= Input * NewElts;5786 5787      // Find or create a shuffle vector operand to hold this input.5788      unsigned OpNo;5789      for (OpNo = 0; OpNo < std::size(InputUsed); ++OpNo) {5790        if (InputUsed[OpNo] == Input) {5791          // This input vector is already an operand.5792          break;5793        } else if (InputUsed[OpNo] == -1U) {5794          // Create a new operand for this input vector.5795          InputUsed[OpNo] = Input;5796          break;5797        }5798      }5799 5800      if (OpNo >= std::size(InputUsed)) {5801        // More than two input vectors used!  Give up on trying to create a5802        // shuffle vector.  Insert all elements into a BUILD_VECTOR instead.5803        UseBuildVector = true;5804        break;5805      }5806 5807      // Add the mask index for the new shuffle vector.5808      Ops.push_back(Idx + OpNo * NewElts);5809    }5810 5811    if (UseBuildVector) {5812      LLT EltTy = NarrowTy.getElementType();5813      SmallVector<Register, 16> SVOps;5814 5815      // Extract the input elements by hand.5816      for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {5817        // The mask element.  This indexes into the input.5818        int Idx = Mask[FirstMaskIdx + MaskOffset];5819 5820        // The input vector this mask element indexes into.5821        unsigned Input = (unsigned)Idx / NewElts;5822 5823        if (Input >= std::size(Inputs)) {5824          // The mask element is "undef" or indexes off the end of the input.5825          SVOps.push_back(MIRBuilder.buildUndef(EltTy).getReg(0));5826          continue;5827        }5828 5829        // Turn the index into an offset from the start of the input vector.5830        Idx -= Input * NewElts;5831 5832        // Extract the vector element by hand.5833        SVOps.push_back(MIRBuilder5834                            .buildExtractVectorElement(5835                                EltTy, Inputs[Input],5836                                MIRBuilder.buildConstant(LLT::scalar(32), Idx))5837                            .getReg(0));5838      }5839 5840      // Construct the Lo/Hi output using a G_BUILD_VECTOR.5841      Output = MIRBuilder.buildBuildVector(NarrowTy, SVOps).getReg(0);5842    } else if (InputUsed[0] == -1U) {5843      // No input vectors were used! The result is undefined.5844      Output = MIRBuilder.buildUndef(NarrowTy).getReg(0);5845    } else if (NewElts == 1) {5846      Output = MIRBuilder.buildCopy(NarrowTy, Inputs[InputUsed[0]]).getReg(0);5847    } else {5848      Register Op0 = Inputs[InputUsed[0]];5849      // If only one input was used, use an undefined vector for the other.5850      Register Op1 = InputUsed[1] == -1U5851                         ? MIRBuilder.buildUndef(NarrowTy).getReg(0)5852                         : Inputs[InputUsed[1]];5853      // At least one input vector was used. Create a new shuffle vector.5854      Output = MIRBuilder.buildShuffleVector(NarrowTy, Op0, Op1, Ops).getReg(0);5855    }5856 5857    Ops.clear();5858  }5859 5860  MIRBuilder.buildMergeLikeInstr(DstReg, {Lo, Hi});5861  MI.eraseFromParent();5862  return Legalized;5863}5864 5865LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorReductions(5866    MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {5867  auto &RdxMI = cast<GVecReduce>(MI);5868 5869  if (TypeIdx != 1)5870    return UnableToLegalize;5871 5872  // The semantics of the normal non-sequential reductions allow us to freely5873  // re-associate the operation.5874  auto [DstReg, DstTy, SrcReg, SrcTy] = RdxMI.getFirst2RegLLTs();5875 5876  if (NarrowTy.isVector() &&5877      (SrcTy.getNumElements() % NarrowTy.getNumElements() != 0))5878    return UnableToLegalize;5879 5880  unsigned ScalarOpc = RdxMI.getScalarOpcForReduction();5881  SmallVector<Register> SplitSrcs;5882  // If NarrowTy is a scalar then we're being asked to scalarize.5883  const unsigned NumParts =5884      NarrowTy.isVector() ? SrcTy.getNumElements() / NarrowTy.getNumElements()5885                          : SrcTy.getNumElements();5886 5887  extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);5888  if (NarrowTy.isScalar()) {5889    if (DstTy != NarrowTy)5890      return UnableToLegalize; // FIXME: handle implicit extensions.5891 5892    if (isPowerOf2_32(NumParts)) {5893      // Generate a tree of scalar operations to reduce the critical path.5894      SmallVector<Register> PartialResults;5895      unsigned NumPartsLeft = NumParts;5896      while (NumPartsLeft > 1) {5897        for (unsigned Idx = 0; Idx < NumPartsLeft - 1; Idx += 2) {5898          PartialResults.emplace_back(5899              MIRBuilder5900                  .buildInstr(ScalarOpc, {NarrowTy},5901                              {SplitSrcs[Idx], SplitSrcs[Idx + 1]})5902                  .getReg(0));5903        }5904        SplitSrcs = PartialResults;5905        PartialResults.clear();5906        NumPartsLeft = SplitSrcs.size();5907      }5908      assert(SplitSrcs.size() == 1);5909      MIRBuilder.buildCopy(DstReg, SplitSrcs[0]);5910      MI.eraseFromParent();5911      return Legalized;5912    }5913    // If we can't generate a tree, then just do sequential operations.5914    Register Acc = SplitSrcs[0];5915    for (unsigned Idx = 1; Idx < NumParts; ++Idx)5916      Acc = MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[Idx]})5917                .getReg(0);5918    MIRBuilder.buildCopy(DstReg, Acc);5919    MI.eraseFromParent();5920    return Legalized;5921  }5922  SmallVector<Register> PartialReductions;5923  for (unsigned Part = 0; Part < NumParts; ++Part) {5924    PartialReductions.push_back(5925        MIRBuilder.buildInstr(RdxMI.getOpcode(), {DstTy}, {SplitSrcs[Part]})5926            .getReg(0));5927  }5928 5929  // If the types involved are powers of 2, we can generate intermediate vector5930  // ops, before generating a final reduction operation.5931  if (isPowerOf2_32(SrcTy.getNumElements()) &&5932      isPowerOf2_32(NarrowTy.getNumElements())) {5933    return tryNarrowPow2Reduction(MI, SrcReg, SrcTy, NarrowTy, ScalarOpc);5934  }5935 5936  Register Acc = PartialReductions[0];5937  for (unsigned Part = 1; Part < NumParts; ++Part) {5938    if (Part == NumParts - 1) {5939      MIRBuilder.buildInstr(ScalarOpc, {DstReg},5940                            {Acc, PartialReductions[Part]});5941    } else {5942      Acc = MIRBuilder5943                .buildInstr(ScalarOpc, {DstTy}, {Acc, PartialReductions[Part]})5944                .getReg(0);5945    }5946  }5947  MI.eraseFromParent();5948  return Legalized;5949}5950 5951LegalizerHelper::LegalizeResult5952LegalizerHelper::fewerElementsVectorSeqReductions(MachineInstr &MI,5953                                                  unsigned int TypeIdx,5954                                                  LLT NarrowTy) {5955  auto [DstReg, DstTy, ScalarReg, ScalarTy, SrcReg, SrcTy] =5956      MI.getFirst3RegLLTs();5957  if (!NarrowTy.isScalar() || TypeIdx != 2 || DstTy != ScalarTy ||5958      DstTy != NarrowTy)5959    return UnableToLegalize;5960 5961  assert((MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD ||5962          MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FMUL) &&5963         "Unexpected vecreduce opcode");5964  unsigned ScalarOpc = MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD5965                           ? TargetOpcode::G_FADD5966                           : TargetOpcode::G_FMUL;5967 5968  SmallVector<Register> SplitSrcs;5969  unsigned NumParts = SrcTy.getNumElements();5970  extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);5971  Register Acc = ScalarReg;5972  for (unsigned i = 0; i < NumParts; i++)5973    Acc = MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[i]})5974              .getReg(0);5975 5976  MIRBuilder.buildCopy(DstReg, Acc);5977  MI.eraseFromParent();5978  return Legalized;5979}5980 5981LegalizerHelper::LegalizeResult5982LegalizerHelper::tryNarrowPow2Reduction(MachineInstr &MI, Register SrcReg,5983                                        LLT SrcTy, LLT NarrowTy,5984                                        unsigned ScalarOpc) {5985  SmallVector<Register> SplitSrcs;5986  // Split the sources into NarrowTy size pieces.5987  extractParts(SrcReg, NarrowTy,5988               SrcTy.getNumElements() / NarrowTy.getNumElements(), SplitSrcs,5989               MIRBuilder, MRI);5990  // We're going to do a tree reduction using vector operations until we have5991  // one NarrowTy size value left.5992  while (SplitSrcs.size() > 1) {5993    SmallVector<Register> PartialRdxs;5994    for (unsigned Idx = 0; Idx < SplitSrcs.size()-1; Idx += 2) {5995      Register LHS = SplitSrcs[Idx];5996      Register RHS = SplitSrcs[Idx + 1];5997      // Create the intermediate vector op.5998      Register Res =5999          MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {LHS, RHS}).getReg(0);6000      PartialRdxs.push_back(Res);6001    }6002    SplitSrcs = std::move(PartialRdxs);6003  }6004  // Finally generate the requested NarrowTy based reduction.6005  Observer.changingInstr(MI);6006  MI.getOperand(1).setReg(SplitSrcs[0]);6007  Observer.changedInstr(MI);6008  return Legalized;6009}6010 6011LegalizerHelper::LegalizeResult6012LegalizerHelper::narrowScalarShiftByConstant(MachineInstr &MI, const APInt &Amt,6013                                             const LLT HalfTy, const LLT AmtTy) {6014 6015  Register InL = MRI.createGenericVirtualRegister(HalfTy);6016  Register InH = MRI.createGenericVirtualRegister(HalfTy);6017  MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));6018 6019  if (Amt.isZero()) {6020    MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {InL, InH});6021    MI.eraseFromParent();6022    return Legalized;6023  }6024 6025  LLT NVT = HalfTy;6026  unsigned NVTBits = HalfTy.getSizeInBits();6027  unsigned VTBits = 2 * NVTBits;6028 6029  SrcOp Lo(Register(0)), Hi(Register(0));6030  if (MI.getOpcode() == TargetOpcode::G_SHL) {6031    if (Amt.ugt(VTBits)) {6032      Lo = Hi = MIRBuilder.buildConstant(NVT, 0);6033    } else if (Amt.ugt(NVTBits)) {6034      Lo = MIRBuilder.buildConstant(NVT, 0);6035      Hi = MIRBuilder.buildShl(NVT, InL,6036                               MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));6037    } else if (Amt == NVTBits) {6038      Lo = MIRBuilder.buildConstant(NVT, 0);6039      Hi = InL;6040    } else {6041      Lo = MIRBuilder.buildShl(NVT, InL, MIRBuilder.buildConstant(AmtTy, Amt));6042      auto OrLHS =6043          MIRBuilder.buildShl(NVT, InH, MIRBuilder.buildConstant(AmtTy, Amt));6044      auto OrRHS = MIRBuilder.buildLShr(6045          NVT, InL, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));6046      Hi = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);6047    }6048  } else if (MI.getOpcode() == TargetOpcode::G_LSHR) {6049    if (Amt.ugt(VTBits)) {6050      Lo = Hi = MIRBuilder.buildConstant(NVT, 0);6051    } else if (Amt.ugt(NVTBits)) {6052      Lo = MIRBuilder.buildLShr(NVT, InH,6053                                MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));6054      Hi = MIRBuilder.buildConstant(NVT, 0);6055    } else if (Amt == NVTBits) {6056      Lo = InH;6057      Hi = MIRBuilder.buildConstant(NVT, 0);6058    } else {6059      auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);6060 6061      auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);6062      auto OrRHS = MIRBuilder.buildShl(6063          NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));6064 6065      Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);6066      Hi = MIRBuilder.buildLShr(NVT, InH, ShiftAmtConst);6067    }6068  } else {6069    if (Amt.ugt(VTBits)) {6070      Hi = Lo = MIRBuilder.buildAShr(6071          NVT, InH, MIRBuilder.buildConstant(AmtTy, NVTBits - 1));6072    } else if (Amt.ugt(NVTBits)) {6073      Lo = MIRBuilder.buildAShr(NVT, InH,6074                                MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));6075      Hi = MIRBuilder.buildAShr(NVT, InH,6076                                MIRBuilder.buildConstant(AmtTy, NVTBits - 1));6077    } else if (Amt == NVTBits) {6078      Lo = InH;6079      Hi = MIRBuilder.buildAShr(NVT, InH,6080                                MIRBuilder.buildConstant(AmtTy, NVTBits - 1));6081    } else {6082      auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);6083 6084      auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);6085      auto OrRHS = MIRBuilder.buildShl(6086          NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));6087 6088      Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);6089      Hi = MIRBuilder.buildAShr(NVT, InH, ShiftAmtConst);6090    }6091  }6092 6093  MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {Lo, Hi});6094  MI.eraseFromParent();6095 6096  return Legalized;6097}6098 6099LegalizerHelper::LegalizeResult6100LegalizerHelper::narrowScalarShift(MachineInstr &MI, unsigned TypeIdx,6101                                   LLT RequestedTy) {6102  if (TypeIdx == 1) {6103    Observer.changingInstr(MI);6104    narrowScalarSrc(MI, RequestedTy, 2);6105    Observer.changedInstr(MI);6106    return Legalized;6107  }6108 6109  Register DstReg = MI.getOperand(0).getReg();6110  LLT DstTy = MRI.getType(DstReg);6111  if (DstTy.isVector())6112    return UnableToLegalize;6113 6114  Register Amt = MI.getOperand(2).getReg();6115  LLT ShiftAmtTy = MRI.getType(Amt);6116  const unsigned DstEltSize = DstTy.getScalarSizeInBits();6117  if (DstEltSize % 2 != 0)6118    return UnableToLegalize;6119 6120  // Check if we should use multi-way splitting instead of recursive binary6121  // splitting.6122  //6123  // Multi-way splitting directly decomposes wide shifts (e.g., 128-bit ->6124  // 4×32-bit) in a single legalization step, avoiding the recursive overhead6125  // and dependency chains created by usual binary splitting approach6126  // (128->64->32).6127  //6128  // The >= 8 parts threshold ensures we only use this optimization when binary6129  // splitting would require multiple recursive passes, avoiding overhead for6130  // simple 2-way splits where binary approach is sufficient.6131  if (RequestedTy.isValid() && RequestedTy.isScalar() &&6132      DstEltSize % RequestedTy.getSizeInBits() == 0) {6133    const unsigned NumParts = DstEltSize / RequestedTy.getSizeInBits();6134    // Use multiway if we have 8 or more parts (i.e., would need 3+ recursive6135    // steps).6136    if (NumParts >= 8)6137      return narrowScalarShiftMultiway(MI, RequestedTy);6138  }6139 6140  // Fall back to binary splitting:6141  // Ignore the input type. We can only go to exactly half the size of the6142  // input. If that isn't small enough, the resulting pieces will be further6143  // legalized.6144  const unsigned NewBitSize = DstEltSize / 2;6145  const LLT HalfTy = LLT::scalar(NewBitSize);6146  const LLT CondTy = LLT::scalar(1);6147 6148  if (auto VRegAndVal = getIConstantVRegValWithLookThrough(Amt, MRI)) {6149    return narrowScalarShiftByConstant(MI, VRegAndVal->Value, HalfTy,6150                                       ShiftAmtTy);6151  }6152 6153  // TODO: Expand with known bits.6154 6155  // Handle the fully general expansion by an unknown amount.6156  auto NewBits = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize);6157 6158  Register InL = MRI.createGenericVirtualRegister(HalfTy);6159  Register InH = MRI.createGenericVirtualRegister(HalfTy);6160  MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));6161 6162  auto AmtExcess = MIRBuilder.buildSub(ShiftAmtTy, Amt, NewBits);6163  auto AmtLack = MIRBuilder.buildSub(ShiftAmtTy, NewBits, Amt);6164 6165  auto Zero = MIRBuilder.buildConstant(ShiftAmtTy, 0);6166  auto IsShort = MIRBuilder.buildICmp(ICmpInst::ICMP_ULT, CondTy, Amt, NewBits);6167  auto IsZero = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, CondTy, Amt, Zero);6168 6169  Register ResultRegs[2];6170  switch (MI.getOpcode()) {6171  case TargetOpcode::G_SHL: {6172    // Short: ShAmt < NewBitSize6173    auto LoS = MIRBuilder.buildShl(HalfTy, InL, Amt);6174 6175    auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, AmtLack);6176    auto HiOr = MIRBuilder.buildShl(HalfTy, InH, Amt);6177    auto HiS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);6178 6179    // Long: ShAmt >= NewBitSize6180    auto LoL = MIRBuilder.buildConstant(HalfTy, 0);         // Lo part is zero.6181    auto HiL = MIRBuilder.buildShl(HalfTy, InL, AmtExcess); // Hi from Lo part.6182 6183    auto Lo = MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL);6184    auto Hi = MIRBuilder.buildSelect(6185        HalfTy, IsZero, InH, MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL));6186 6187    ResultRegs[0] = Lo.getReg(0);6188    ResultRegs[1] = Hi.getReg(0);6189    break;6190  }6191  case TargetOpcode::G_LSHR:6192  case TargetOpcode::G_ASHR: {6193    // Short: ShAmt < NewBitSize6194    auto HiS = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy}, {InH, Amt});6195 6196    auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, Amt);6197    auto HiOr = MIRBuilder.buildShl(HalfTy, InH, AmtLack);6198    auto LoS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);6199 6200    // Long: ShAmt >= NewBitSize6201    MachineInstrBuilder HiL;6202    if (MI.getOpcode() == TargetOpcode::G_LSHR) {6203      HiL = MIRBuilder.buildConstant(HalfTy, 0);            // Hi part is zero.6204    } else {6205      auto ShiftAmt = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize - 1);6206      HiL = MIRBuilder.buildAShr(HalfTy, InH, ShiftAmt);    // Sign of Hi part.6207    }6208    auto LoL = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy},6209                                     {InH, AmtExcess});     // Lo from Hi part.6210 6211    auto Lo = MIRBuilder.buildSelect(6212        HalfTy, IsZero, InL, MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL));6213 6214    auto Hi = MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL);6215 6216    ResultRegs[0] = Lo.getReg(0);6217    ResultRegs[1] = Hi.getReg(0);6218    break;6219  }6220  default:6221    llvm_unreachable("not a shift");6222  }6223 6224  MIRBuilder.buildMergeLikeInstr(DstReg, ResultRegs);6225  MI.eraseFromParent();6226  return Legalized;6227}6228 6229Register LegalizerHelper::buildConstantShiftPart(unsigned Opcode,6230                                                 unsigned PartIdx,6231                                                 unsigned NumParts,6232                                                 ArrayRef<Register> SrcParts,6233                                                 const ShiftParams &Params,6234                                                 LLT TargetTy, LLT ShiftAmtTy) {6235  auto WordShiftConst = getIConstantVRegVal(Params.WordShift, MRI);6236  auto BitShiftConst = getIConstantVRegVal(Params.BitShift, MRI);6237  assert(WordShiftConst && BitShiftConst && "Expected constants");6238 6239  const unsigned ShiftWords = WordShiftConst->getZExtValue();6240  const unsigned ShiftBits = BitShiftConst->getZExtValue();6241  const bool NeedsInterWordShift = ShiftBits != 0;6242 6243  switch (Opcode) {6244  case TargetOpcode::G_SHL: {6245    // Data moves from lower indices to higher indices6246    // If this part would come from a source beyond our range, it's zero6247    if (PartIdx < ShiftWords)6248      return Params.Zero;6249 6250    unsigned SrcIdx = PartIdx - ShiftWords;6251    if (!NeedsInterWordShift)6252      return SrcParts[SrcIdx];6253 6254    // Combine shifted main part with carry from previous part6255    auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx], Params.BitShift);6256    if (SrcIdx > 0) {6257      auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx - 1],6258                                     Params.InvBitShift);6259      return MIRBuilder.buildOr(TargetTy, Hi, Lo).getReg(0);6260    }6261    return Hi.getReg(0);6262  }6263 6264  case TargetOpcode::G_LSHR: {6265    unsigned SrcIdx = PartIdx + ShiftWords;6266    if (SrcIdx >= NumParts)6267      return Params.Zero;6268    if (!NeedsInterWordShift)6269      return SrcParts[SrcIdx];6270 6271    // Combine shifted main part with carry from next part6272    auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);6273    if (SrcIdx + 1 < NumParts) {6274      auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx + 1],6275                                    Params.InvBitShift);6276      return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);6277    }6278    return Lo.getReg(0);6279  }6280 6281  case TargetOpcode::G_ASHR: {6282    // Like LSHR but preserves sign bit6283    unsigned SrcIdx = PartIdx + ShiftWords;6284    if (SrcIdx >= NumParts)6285      return Params.SignBit;6286    if (!NeedsInterWordShift)6287      return SrcParts[SrcIdx];6288 6289    // Only the original MSB part uses arithmetic shift to preserve sign. All6290    // other parts use logical shift since they're just moving data bits.6291    auto Lo =6292        (SrcIdx == NumParts - 1)6293            ? MIRBuilder.buildAShr(TargetTy, SrcParts[SrcIdx], Params.BitShift)6294            : MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);6295    Register HiSrc =6296        (SrcIdx + 1 < NumParts) ? SrcParts[SrcIdx + 1] : Params.SignBit;6297    auto Hi = MIRBuilder.buildShl(TargetTy, HiSrc, Params.InvBitShift);6298    return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);6299  }6300 6301  default:6302    llvm_unreachable("not a shift");6303  }6304}6305 6306Register LegalizerHelper::buildVariableShiftPart(unsigned Opcode,6307                                                 Register MainOperand,6308                                                 Register ShiftAmt,6309                                                 LLT TargetTy,6310                                                 Register CarryOperand) {6311  // This helper generates a single output part for variable shifts by combining6312  // the main operand (shifted by BitShift) with carry bits from an adjacent6313  // part.6314 6315  // For G_ASHR, individual parts don't have their own sign bit, only the6316  // complete value does. So we use LSHR for the main operand shift in ASHR6317  // context.6318  unsigned MainOpcode =6319      (Opcode == TargetOpcode::G_ASHR) ? TargetOpcode::G_LSHR : Opcode;6320 6321  // Perform the primary shift on the main operand6322  Register MainShifted =6323      MIRBuilder.buildInstr(MainOpcode, {TargetTy}, {MainOperand, ShiftAmt})6324          .getReg(0);6325 6326  // No carry operand available6327  if (!CarryOperand.isValid())6328    return MainShifted;6329 6330  // If BitShift is 0 (word-aligned shift), no inter-word bit movement occurs,6331  // so carry bits aren't needed.6332  LLT ShiftAmtTy = MRI.getType(ShiftAmt);6333  auto ZeroConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);6334  LLT BoolTy = LLT::scalar(1);6335  auto IsZeroBitShift =6336      MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, ShiftAmt, ZeroConst);6337 6338  // Extract bits from the adjacent part that will "carry over" into this part.6339  // The carry direction is opposite to the main shift direction, so we can6340  // align the two shifted values before combining them with OR.6341 6342  // Determine the carry shift opcode (opposite direction)6343  unsigned CarryOpcode = (Opcode == TargetOpcode::G_SHL) ? TargetOpcode::G_LSHR6344                                                         : TargetOpcode::G_SHL;6345 6346  // Calculate inverse shift amount: BitWidth - ShiftAmt6347  auto TargetBitsConst =6348      MIRBuilder.buildConstant(ShiftAmtTy, TargetTy.getScalarSizeInBits());6349  auto InvShiftAmt = MIRBuilder.buildSub(ShiftAmtTy, TargetBitsConst, ShiftAmt);6350 6351  // Shift the carry operand6352  Register CarryBits =6353      MIRBuilder6354          .buildInstr(CarryOpcode, {TargetTy}, {CarryOperand, InvShiftAmt})6355          .getReg(0);6356 6357  // If BitShift is 0, don't include carry bits (InvShiftAmt would equal6358  // TargetBits which would be poison for the individual carry shift operation).6359  auto ZeroReg = MIRBuilder.buildConstant(TargetTy, 0);6360  Register SafeCarryBits =6361      MIRBuilder.buildSelect(TargetTy, IsZeroBitShift, ZeroReg, CarryBits)6362          .getReg(0);6363 6364  // Combine the main shifted part with the carry bits6365  return MIRBuilder.buildOr(TargetTy, MainShifted, SafeCarryBits).getReg(0);6366}6367 6368LegalizerHelper::LegalizeResult6369LegalizerHelper::narrowScalarShiftByConstantMultiway(MachineInstr &MI,6370                                                     const APInt &Amt,6371                                                     LLT TargetTy,6372                                                     LLT ShiftAmtTy) {6373  // Any wide shift can be decomposed into WordShift + BitShift components.6374  // When shift amount is known constant, directly compute the decomposition6375  // values and generate constant registers.6376  Register DstReg = MI.getOperand(0).getReg();6377  Register SrcReg = MI.getOperand(1).getReg();6378  LLT DstTy = MRI.getType(DstReg);6379 6380  const unsigned DstBits = DstTy.getScalarSizeInBits();6381  const unsigned TargetBits = TargetTy.getScalarSizeInBits();6382  const unsigned NumParts = DstBits / TargetBits;6383 6384  assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");6385 6386  // When the shift amount is known at compile time, we just calculate which6387  // source parts contribute to each output part.6388 6389  SmallVector<Register, 8> SrcParts;6390  extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);6391 6392  if (Amt.isZero()) {6393    // No shift needed, just copy6394    MIRBuilder.buildMergeLikeInstr(DstReg, SrcParts);6395    MI.eraseFromParent();6396    return Legalized;6397  }6398 6399  ShiftParams Params;6400  const unsigned ShiftWords = Amt.getZExtValue() / TargetBits;6401  const unsigned ShiftBits = Amt.getZExtValue() % TargetBits;6402 6403  // Generate constants and values needed by all shift types6404  Params.WordShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftWords).getReg(0);6405  Params.BitShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftBits).getReg(0);6406  Params.InvBitShift =6407      MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - ShiftBits).getReg(0);6408  Params.Zero = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);6409 6410  // For ASHR, we need the sign-extended value to fill shifted-out positions6411  if (MI.getOpcode() == TargetOpcode::G_ASHR)6412    Params.SignBit =6413        MIRBuilder6414            .buildAShr(TargetTy, SrcParts[SrcParts.size() - 1],6415                       MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1))6416            .getReg(0);6417 6418  SmallVector<Register, 8> DstParts(NumParts);6419  for (unsigned I = 0; I < NumParts; ++I)6420    DstParts[I] = buildConstantShiftPart(MI.getOpcode(), I, NumParts, SrcParts,6421                                         Params, TargetTy, ShiftAmtTy);6422 6423  MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);6424  MI.eraseFromParent();6425  return Legalized;6426}6427 6428LegalizerHelper::LegalizeResult6429LegalizerHelper::narrowScalarShiftMultiway(MachineInstr &MI, LLT TargetTy) {6430  Register DstReg = MI.getOperand(0).getReg();6431  Register SrcReg = MI.getOperand(1).getReg();6432  Register AmtReg = MI.getOperand(2).getReg();6433  LLT DstTy = MRI.getType(DstReg);6434  LLT ShiftAmtTy = MRI.getType(AmtReg);6435 6436  const unsigned DstBits = DstTy.getScalarSizeInBits();6437  const unsigned TargetBits = TargetTy.getScalarSizeInBits();6438  const unsigned NumParts = DstBits / TargetBits;6439 6440  assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");6441  assert(isPowerOf2_32(TargetBits) && "Target bit width must be power of 2");6442 6443  // If the shift amount is known at compile time, we can use direct indexing6444  // instead of generating select chains in the general case.6445  if (auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI))6446    return narrowScalarShiftByConstantMultiway(MI, VRegAndVal->Value, TargetTy,6447                                               ShiftAmtTy);6448 6449  // For runtime-variable shift amounts, we must generate a more complex6450  // sequence that handles all possible shift values using select chains.6451 6452  // Split the input into target-sized pieces6453  SmallVector<Register, 8> SrcParts;6454  extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);6455 6456  // Shifting by zero should be a no-op.6457  auto ZeroAmtConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);6458  LLT BoolTy = LLT::scalar(1);6459  auto IsZeroShift =6460      MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, AmtReg, ZeroAmtConst);6461 6462  // Any wide shift can be decomposed into two components:6463  // 1. WordShift: number of complete target-sized words to shift6464  // 2. BitShift: number of bits to shift within each word6465  //6466  // Example: 128-bit >> 50 with 32-bit target:6467  //   WordShift = 50 / 32 = 1 (shift right by 1 complete word)6468  //   BitShift = 50 % 32 = 18 (shift each word right by 18 bits)6469  unsigned TargetBitsLog2 = Log2_32(TargetBits);6470  auto TargetBitsLog2Const =6471      MIRBuilder.buildConstant(ShiftAmtTy, TargetBitsLog2);6472  auto TargetBitsMask = MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);6473 6474  Register WordShift =6475      MIRBuilder.buildLShr(ShiftAmtTy, AmtReg, TargetBitsLog2Const).getReg(0);6476  Register BitShift =6477      MIRBuilder.buildAnd(ShiftAmtTy, AmtReg, TargetBitsMask).getReg(0);6478 6479  // Fill values:6480  // - SHL/LSHR: fill with zeros6481  // - ASHR: fill with sign-extended MSB6482  Register ZeroReg = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);6483 6484  Register FillValue;6485  if (MI.getOpcode() == TargetOpcode::G_ASHR) {6486    auto TargetBitsMinusOneConst =6487        MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);6488    FillValue = MIRBuilder6489                    .buildAShr(TargetTy, SrcParts[NumParts - 1],6490                               TargetBitsMinusOneConst)6491                    .getReg(0);6492  } else {6493    FillValue = ZeroReg;6494  }6495 6496  SmallVector<Register, 8> DstParts(NumParts);6497 6498  // For each output part, generate a select chain that chooses the correct6499  // result based on the runtime WordShift value. This handles all possible6500  // word shift amounts by pre-calculating what each would produce.6501  for (unsigned I = 0; I < NumParts; ++I) {6502    // Initialize with appropriate default value for this shift type6503    Register InBoundsResult = FillValue;6504 6505    // clang-format off6506    // Build a branchless select chain by pre-computing results for all possible6507    // WordShift values (0 to NumParts-1). Each iteration nests a new select:6508    //6509    // K=0: select(WordShift==0, result0, FillValue)6510    // K=1: select(WordShift==1, result1, select(WordShift==0, result0, FillValue))6511    // K=2: select(WordShift==2, result2, select(WordShift==1, result1, select(...)))6512    // clang-format on6513    for (unsigned K = 0; K < NumParts; ++K) {6514      auto WordShiftKConst = MIRBuilder.buildConstant(ShiftAmtTy, K);6515      auto IsWordShiftK = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy,6516                                               WordShift, WordShiftKConst);6517 6518      // Calculate source indices for this word shift6519      //6520      // For 4-part 128-bit value with K=1 word shift:6521      // SHL:  [3][2][1][0] << K  =>  [2][1][0][Z]6522      //     -> (MainIdx = I-K, CarryIdx = I-K-1)6523      // LSHR: [3][2][1][0] >> K  =>  [Z][3][2][1]6524      //     -> (MainIdx = I+K, CarryIdx = I+K+1)6525      int MainSrcIdx;6526      int CarrySrcIdx; // Index for the word that provides the carried-in bits.6527 6528      switch (MI.getOpcode()) {6529      case TargetOpcode::G_SHL:6530        MainSrcIdx = (int)I - (int)K;6531        CarrySrcIdx = MainSrcIdx - 1;6532        break;6533      case TargetOpcode::G_LSHR:6534      case TargetOpcode::G_ASHR:6535        MainSrcIdx = (int)I + (int)K;6536        CarrySrcIdx = MainSrcIdx + 1;6537        break;6538      default:6539        llvm_unreachable("Not a shift");6540      }6541 6542      // Check bounds and build the result for this word shift6543      Register ResultForK;6544      if (MainSrcIdx >= 0 && MainSrcIdx < (int)NumParts) {6545        Register MainOp = SrcParts[MainSrcIdx];6546        Register CarryOp;6547 6548        // Determine carry operand with bounds checking6549        if (CarrySrcIdx >= 0 && CarrySrcIdx < (int)NumParts)6550          CarryOp = SrcParts[CarrySrcIdx];6551        else if (MI.getOpcode() == TargetOpcode::G_ASHR &&6552                 CarrySrcIdx >= (int)NumParts)6553          CarryOp = FillValue; // Use sign extension6554 6555        ResultForK = buildVariableShiftPart(MI.getOpcode(), MainOp, BitShift,6556                                            TargetTy, CarryOp);6557      } else {6558        // Out of bounds - use fill value for this k6559        ResultForK = FillValue;6560      }6561 6562      // Select this result if WordShift equals k6563      InBoundsResult =6564          MIRBuilder6565              .buildSelect(TargetTy, IsWordShiftK, ResultForK, InBoundsResult)6566              .getReg(0);6567    }6568 6569    // Handle zero-shift special case: if shift is 0, use original input6570    DstParts[I] =6571        MIRBuilder6572            .buildSelect(TargetTy, IsZeroShift, SrcParts[I], InBoundsResult)6573            .getReg(0);6574  }6575 6576  MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);6577  MI.eraseFromParent();6578  return Legalized;6579}6580 6581LegalizerHelper::LegalizeResult6582LegalizerHelper::moreElementsVectorPhi(MachineInstr &MI, unsigned TypeIdx,6583                                       LLT MoreTy) {6584  assert(TypeIdx == 0 && "Expecting only Idx 0");6585 6586  Observer.changingInstr(MI);6587  for (unsigned I = 1, E = MI.getNumOperands(); I != E; I += 2) {6588    MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();6589    MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator());6590    moreElementsVectorSrc(MI, MoreTy, I);6591  }6592 6593  MachineBasicBlock &MBB = *MI.getParent();6594  MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());6595  moreElementsVectorDst(MI, MoreTy, 0);6596  Observer.changedInstr(MI);6597  return Legalized;6598}6599 6600MachineInstrBuilder LegalizerHelper::getNeutralElementForVecReduce(6601    unsigned Opcode, MachineIRBuilder &MIRBuilder, LLT Ty) {6602  assert(Ty.isScalar() && "Expected scalar type to make neutral element for");6603 6604  switch (Opcode) {6605  default:6606    llvm_unreachable(6607        "getNeutralElementForVecReduce called with invalid opcode!");6608  case TargetOpcode::G_VECREDUCE_ADD:6609  case TargetOpcode::G_VECREDUCE_OR:6610  case TargetOpcode::G_VECREDUCE_XOR:6611  case TargetOpcode::G_VECREDUCE_UMAX:6612    return MIRBuilder.buildConstant(Ty, 0);6613  case TargetOpcode::G_VECREDUCE_MUL:6614    return MIRBuilder.buildConstant(Ty, 1);6615  case TargetOpcode::G_VECREDUCE_AND:6616  case TargetOpcode::G_VECREDUCE_UMIN:6617    return MIRBuilder.buildConstant(6618        Ty, APInt::getAllOnes(Ty.getScalarSizeInBits()));6619  case TargetOpcode::G_VECREDUCE_SMAX:6620    return MIRBuilder.buildConstant(6621        Ty, APInt::getSignedMinValue(Ty.getSizeInBits()));6622  case TargetOpcode::G_VECREDUCE_SMIN:6623    return MIRBuilder.buildConstant(6624        Ty, APInt::getSignedMaxValue(Ty.getSizeInBits()));6625  case TargetOpcode::G_VECREDUCE_FADD:6626    return MIRBuilder.buildFConstant(Ty, -0.0);6627  case TargetOpcode::G_VECREDUCE_FMUL:6628    return MIRBuilder.buildFConstant(Ty, 1.0);6629  case TargetOpcode::G_VECREDUCE_FMINIMUM:6630  case TargetOpcode::G_VECREDUCE_FMAXIMUM:6631    assert(false && "getNeutralElementForVecReduce unimplemented for "6632                    "G_VECREDUCE_FMINIMUM and G_VECREDUCE_FMAXIMUM!");6633  }6634  llvm_unreachable("switch expected to return!");6635}6636 6637LegalizerHelper::LegalizeResult6638LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx,6639                                    LLT MoreTy) {6640  unsigned Opc = MI.getOpcode();6641  switch (Opc) {6642  case TargetOpcode::G_IMPLICIT_DEF:6643  case TargetOpcode::G_LOAD: {6644    if (TypeIdx != 0)6645      return UnableToLegalize;6646    Observer.changingInstr(MI);6647    moreElementsVectorDst(MI, MoreTy, 0);6648    Observer.changedInstr(MI);6649    return Legalized;6650  }6651  case TargetOpcode::G_STORE:6652    if (TypeIdx != 0)6653      return UnableToLegalize;6654    Observer.changingInstr(MI);6655    moreElementsVectorSrc(MI, MoreTy, 0);6656    Observer.changedInstr(MI);6657    return Legalized;6658  case TargetOpcode::G_AND:6659  case TargetOpcode::G_OR:6660  case TargetOpcode::G_XOR:6661  case TargetOpcode::G_ADD:6662  case TargetOpcode::G_SUB:6663  case TargetOpcode::G_MUL:6664  case TargetOpcode::G_FADD:6665  case TargetOpcode::G_FSUB:6666  case TargetOpcode::G_FMUL:6667  case TargetOpcode::G_FDIV:6668  case TargetOpcode::G_FCOPYSIGN:6669  case TargetOpcode::G_UADDSAT:6670  case TargetOpcode::G_USUBSAT:6671  case TargetOpcode::G_SADDSAT:6672  case TargetOpcode::G_SSUBSAT:6673  case TargetOpcode::G_SMIN:6674  case TargetOpcode::G_SMAX:6675  case TargetOpcode::G_UMIN:6676  case TargetOpcode::G_UMAX:6677  case TargetOpcode::G_FMINNUM:6678  case TargetOpcode::G_FMAXNUM:6679  case TargetOpcode::G_FMINNUM_IEEE:6680  case TargetOpcode::G_FMAXNUM_IEEE:6681  case TargetOpcode::G_FMINIMUM:6682  case TargetOpcode::G_FMAXIMUM:6683  case TargetOpcode::G_FMINIMUMNUM:6684  case TargetOpcode::G_FMAXIMUMNUM:6685  case TargetOpcode::G_STRICT_FADD:6686  case TargetOpcode::G_STRICT_FSUB:6687  case TargetOpcode::G_STRICT_FMUL:6688  case TargetOpcode::G_SHL:6689  case TargetOpcode::G_ASHR:6690  case TargetOpcode::G_LSHR: {6691    Observer.changingInstr(MI);6692    moreElementsVectorSrc(MI, MoreTy, 1);6693    moreElementsVectorSrc(MI, MoreTy, 2);6694    moreElementsVectorDst(MI, MoreTy, 0);6695    Observer.changedInstr(MI);6696    return Legalized;6697  }6698  case TargetOpcode::G_FMA:6699  case TargetOpcode::G_STRICT_FMA:6700  case TargetOpcode::G_FSHR:6701  case TargetOpcode::G_FSHL: {6702    Observer.changingInstr(MI);6703    moreElementsVectorSrc(MI, MoreTy, 1);6704    moreElementsVectorSrc(MI, MoreTy, 2);6705    moreElementsVectorSrc(MI, MoreTy, 3);6706    moreElementsVectorDst(MI, MoreTy, 0);6707    Observer.changedInstr(MI);6708    return Legalized;6709  }6710  case TargetOpcode::G_EXTRACT_VECTOR_ELT:6711  case TargetOpcode::G_EXTRACT:6712    if (TypeIdx != 1)6713      return UnableToLegalize;6714    Observer.changingInstr(MI);6715    moreElementsVectorSrc(MI, MoreTy, 1);6716    Observer.changedInstr(MI);6717    return Legalized;6718  case TargetOpcode::G_INSERT:6719  case TargetOpcode::G_INSERT_VECTOR_ELT:6720  case TargetOpcode::G_FREEZE:6721  case TargetOpcode::G_FNEG:6722  case TargetOpcode::G_FABS:6723  case TargetOpcode::G_FSQRT:6724  case TargetOpcode::G_FCEIL:6725  case TargetOpcode::G_FFLOOR:6726  case TargetOpcode::G_FNEARBYINT:6727  case TargetOpcode::G_FRINT:6728  case TargetOpcode::G_INTRINSIC_ROUND:6729  case TargetOpcode::G_INTRINSIC_ROUNDEVEN:6730  case TargetOpcode::G_INTRINSIC_TRUNC:6731  case TargetOpcode::G_BITREVERSE:6732  case TargetOpcode::G_BSWAP:6733  case TargetOpcode::G_FCANONICALIZE:6734  case TargetOpcode::G_SEXT_INREG:6735  case TargetOpcode::G_ABS:6736  case TargetOpcode::G_CTLZ:6737  case TargetOpcode::G_CTPOP:6738    if (TypeIdx != 0)6739      return UnableToLegalize;6740    Observer.changingInstr(MI);6741    moreElementsVectorSrc(MI, MoreTy, 1);6742    moreElementsVectorDst(MI, MoreTy, 0);6743    Observer.changedInstr(MI);6744    return Legalized;6745  case TargetOpcode::G_SELECT: {6746    auto [DstReg, DstTy, CondReg, CondTy] = MI.getFirst2RegLLTs();6747    if (TypeIdx == 1) {6748      if (!CondTy.isScalar() ||6749          DstTy.getElementCount() != MoreTy.getElementCount())6750        return UnableToLegalize;6751 6752      // This is turning a scalar select of vectors into a vector6753      // select. Broadcast the select condition.6754      auto ShufSplat = MIRBuilder.buildShuffleSplat(MoreTy, CondReg);6755      Observer.changingInstr(MI);6756      MI.getOperand(1).setReg(ShufSplat.getReg(0));6757      Observer.changedInstr(MI);6758      return Legalized;6759    }6760 6761    if (CondTy.isVector())6762      return UnableToLegalize;6763 6764    Observer.changingInstr(MI);6765    moreElementsVectorSrc(MI, MoreTy, 2);6766    moreElementsVectorSrc(MI, MoreTy, 3);6767    moreElementsVectorDst(MI, MoreTy, 0);6768    Observer.changedInstr(MI);6769    return Legalized;6770  }6771  case TargetOpcode::G_UNMERGE_VALUES:6772    return UnableToLegalize;6773  case TargetOpcode::G_PHI:6774    return moreElementsVectorPhi(MI, TypeIdx, MoreTy);6775  case TargetOpcode::G_SHUFFLE_VECTOR:6776    return moreElementsVectorShuffle(MI, TypeIdx, MoreTy);6777  case TargetOpcode::G_BUILD_VECTOR: {6778    SmallVector<SrcOp, 8> Elts;6779    for (auto Op : MI.uses()) {6780      Elts.push_back(Op.getReg());6781    }6782 6783    for (unsigned i = Elts.size(); i < MoreTy.getNumElements(); ++i) {6784      Elts.push_back(MIRBuilder.buildUndef(MoreTy.getScalarType()));6785    }6786 6787    MIRBuilder.buildDeleteTrailingVectorElements(6788        MI.getOperand(0).getReg(), MIRBuilder.buildInstr(Opc, {MoreTy}, Elts));6789    MI.eraseFromParent();6790    return Legalized;6791  }6792  case TargetOpcode::G_SEXT:6793  case TargetOpcode::G_ZEXT:6794  case TargetOpcode::G_ANYEXT:6795  case TargetOpcode::G_TRUNC:6796  case TargetOpcode::G_FPTRUNC:6797  case TargetOpcode::G_FPEXT:6798  case TargetOpcode::G_FPTOSI:6799  case TargetOpcode::G_FPTOUI:6800  case TargetOpcode::G_FPTOSI_SAT:6801  case TargetOpcode::G_FPTOUI_SAT:6802  case TargetOpcode::G_SITOFP:6803  case TargetOpcode::G_UITOFP: {6804    Observer.changingInstr(MI);6805    LLT SrcExtTy;6806    LLT DstExtTy;6807    if (TypeIdx == 0) {6808      DstExtTy = MoreTy;6809      SrcExtTy = LLT::fixed_vector(6810          MoreTy.getNumElements(),6811          MRI.getType(MI.getOperand(1).getReg()).getElementType());6812    } else {6813      DstExtTy = LLT::fixed_vector(6814          MoreTy.getNumElements(),6815          MRI.getType(MI.getOperand(0).getReg()).getElementType());6816      SrcExtTy = MoreTy;6817    }6818    moreElementsVectorSrc(MI, SrcExtTy, 1);6819    moreElementsVectorDst(MI, DstExtTy, 0);6820    Observer.changedInstr(MI);6821    return Legalized;6822  }6823  case TargetOpcode::G_ICMP:6824  case TargetOpcode::G_FCMP: {6825    if (TypeIdx != 1)6826      return UnableToLegalize;6827 6828    Observer.changingInstr(MI);6829    moreElementsVectorSrc(MI, MoreTy, 2);6830    moreElementsVectorSrc(MI, MoreTy, 3);6831    LLT CondTy = LLT::fixed_vector(6832        MoreTy.getNumElements(),6833        MRI.getType(MI.getOperand(0).getReg()).getElementType());6834    moreElementsVectorDst(MI, CondTy, 0);6835    Observer.changedInstr(MI);6836    return Legalized;6837  }6838  case TargetOpcode::G_BITCAST: {6839    if (TypeIdx != 0)6840      return UnableToLegalize;6841 6842    LLT SrcTy = MRI.getType(MI.getOperand(1).getReg());6843    LLT DstTy = MRI.getType(MI.getOperand(0).getReg());6844 6845    unsigned coefficient = SrcTy.getNumElements() * MoreTy.getNumElements();6846    if (coefficient % DstTy.getNumElements() != 0)6847      return UnableToLegalize;6848 6849    coefficient = coefficient / DstTy.getNumElements();6850 6851    LLT NewTy = SrcTy.changeElementCount(6852        ElementCount::get(coefficient, MoreTy.isScalable()));6853    Observer.changingInstr(MI);6854    moreElementsVectorSrc(MI, NewTy, 1);6855    moreElementsVectorDst(MI, MoreTy, 0);6856    Observer.changedInstr(MI);6857    return Legalized;6858  }6859  case TargetOpcode::G_VECREDUCE_FADD:6860  case TargetOpcode::G_VECREDUCE_FMUL:6861  case TargetOpcode::G_VECREDUCE_ADD:6862  case TargetOpcode::G_VECREDUCE_MUL:6863  case TargetOpcode::G_VECREDUCE_AND:6864  case TargetOpcode::G_VECREDUCE_OR:6865  case TargetOpcode::G_VECREDUCE_XOR:6866  case TargetOpcode::G_VECREDUCE_SMAX:6867  case TargetOpcode::G_VECREDUCE_SMIN:6868  case TargetOpcode::G_VECREDUCE_UMAX:6869  case TargetOpcode::G_VECREDUCE_UMIN: {6870    LLT OrigTy = MRI.getType(MI.getOperand(1).getReg());6871    MachineOperand &MO = MI.getOperand(1);6872    auto NewVec = MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO);6873    auto NeutralElement = getNeutralElementForVecReduce(6874        MI.getOpcode(), MIRBuilder, MoreTy.getElementType());6875 6876    LLT IdxTy(TLI.getVectorIdxLLT(MIRBuilder.getDataLayout()));6877    for (size_t i = OrigTy.getNumElements(), e = MoreTy.getNumElements();6878         i != e; i++) {6879      auto Idx = MIRBuilder.buildConstant(IdxTy, i);6880      NewVec = MIRBuilder.buildInsertVectorElement(MoreTy, NewVec,6881                                                   NeutralElement, Idx);6882    }6883 6884    Observer.changingInstr(MI);6885    MO.setReg(NewVec.getReg(0));6886    Observer.changedInstr(MI);6887    return Legalized;6888  }6889 6890  default:6891    return UnableToLegalize;6892  }6893}6894 6895LegalizerHelper::LegalizeResult6896LegalizerHelper::equalizeVectorShuffleLengths(MachineInstr &MI) {6897  auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();6898  ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();6899  unsigned MaskNumElts = Mask.size();6900  unsigned SrcNumElts = SrcTy.getNumElements();6901  LLT DestEltTy = DstTy.getElementType();6902 6903  if (MaskNumElts == SrcNumElts)6904    return Legalized;6905 6906  if (MaskNumElts < SrcNumElts) {6907    // Extend mask to match new destination vector size with6908    // undef values.6909    SmallVector<int, 16> NewMask(SrcNumElts, -1);6910    llvm::copy(Mask, NewMask.begin());6911 6912    moreElementsVectorDst(MI, SrcTy, 0);6913    MIRBuilder.setInstrAndDebugLoc(MI);6914    MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),6915                                  MI.getOperand(1).getReg(),6916                                  MI.getOperand(2).getReg(), NewMask);6917    MI.eraseFromParent();6918 6919    return Legalized;6920  }6921 6922  unsigned PaddedMaskNumElts = alignTo(MaskNumElts, SrcNumElts);6923  unsigned NumConcat = PaddedMaskNumElts / SrcNumElts;6924  LLT PaddedTy = LLT::fixed_vector(PaddedMaskNumElts, DestEltTy);6925 6926  // Create new source vectors by concatenating the initial6927  // source vectors with undefined vectors of the same size.6928  auto Undef = MIRBuilder.buildUndef(SrcTy);6929  SmallVector<Register, 8> MOps1(NumConcat, Undef.getReg(0));6930  SmallVector<Register, 8> MOps2(NumConcat, Undef.getReg(0));6931  MOps1[0] = MI.getOperand(1).getReg();6932  MOps2[0] = MI.getOperand(2).getReg();6933 6934  auto Src1 = MIRBuilder.buildConcatVectors(PaddedTy, MOps1);6935  auto Src2 = MIRBuilder.buildConcatVectors(PaddedTy, MOps2);6936 6937  // Readjust mask for new input vector length.6938  SmallVector<int, 8> MappedOps(PaddedMaskNumElts, -1);6939  for (unsigned I = 0; I != MaskNumElts; ++I) {6940    int Idx = Mask[I];6941    if (Idx >= static_cast<int>(SrcNumElts))6942      Idx += PaddedMaskNumElts - SrcNumElts;6943    MappedOps[I] = Idx;6944  }6945 6946  // If we got more elements than required, extract subvector.6947  if (MaskNumElts != PaddedMaskNumElts) {6948    auto Shuffle =6949        MIRBuilder.buildShuffleVector(PaddedTy, Src1, Src2, MappedOps);6950 6951    SmallVector<Register, 16> Elts(MaskNumElts);6952    for (unsigned I = 0; I < MaskNumElts; ++I) {6953      Elts[I] =6954          MIRBuilder.buildExtractVectorElementConstant(DestEltTy, Shuffle, I)6955              .getReg(0);6956    }6957    MIRBuilder.buildBuildVector(DstReg, Elts);6958  } else {6959    MIRBuilder.buildShuffleVector(DstReg, Src1, Src2, MappedOps);6960  }6961 6962  MI.eraseFromParent();6963  return LegalizerHelper::LegalizeResult::Legalized;6964}6965 6966LegalizerHelper::LegalizeResult6967LegalizerHelper::moreElementsVectorShuffle(MachineInstr &MI,6968                                           unsigned int TypeIdx, LLT MoreTy) {6969  auto [DstTy, Src1Ty, Src2Ty] = MI.getFirst3LLTs();6970  ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();6971  unsigned NumElts = DstTy.getNumElements();6972  unsigned WidenNumElts = MoreTy.getNumElements();6973 6974  if (DstTy.isVector() && Src1Ty.isVector() &&6975      DstTy.getNumElements() != Src1Ty.getNumElements()) {6976    return equalizeVectorShuffleLengths(MI);6977  }6978 6979  if (TypeIdx != 0)6980    return UnableToLegalize;6981 6982  // Expect a canonicalized shuffle.6983  if (DstTy != Src1Ty || DstTy != Src2Ty)6984    return UnableToLegalize;6985 6986  moreElementsVectorSrc(MI, MoreTy, 1);6987  moreElementsVectorSrc(MI, MoreTy, 2);6988 6989  // Adjust mask based on new input vector length.6990  SmallVector<int, 16> NewMask(WidenNumElts, -1);6991  for (unsigned I = 0; I != NumElts; ++I) {6992    int Idx = Mask[I];6993    if (Idx < static_cast<int>(NumElts))6994      NewMask[I] = Idx;6995    else6996      NewMask[I] = Idx - NumElts + WidenNumElts;6997  }6998  moreElementsVectorDst(MI, MoreTy, 0);6999  MIRBuilder.setInstrAndDebugLoc(MI);7000  MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),7001                                MI.getOperand(1).getReg(),7002                                MI.getOperand(2).getReg(), NewMask);7003  MI.eraseFromParent();7004  return Legalized;7005}7006 7007void LegalizerHelper::multiplyRegisters(SmallVectorImpl<Register> &DstRegs,7008                                        ArrayRef<Register> Src1Regs,7009                                        ArrayRef<Register> Src2Regs,7010                                        LLT NarrowTy) {7011  MachineIRBuilder &B = MIRBuilder;7012  unsigned SrcParts = Src1Regs.size();7013  unsigned DstParts = DstRegs.size();7014 7015  unsigned DstIdx = 0; // Low bits of the result.7016  Register FactorSum =7017      B.buildMul(NarrowTy, Src1Regs[DstIdx], Src2Regs[DstIdx]).getReg(0);7018  DstRegs[DstIdx] = FactorSum;7019 7020  Register CarrySumPrevDstIdx;7021  SmallVector<Register, 4> Factors;7022 7023  for (DstIdx = 1; DstIdx < DstParts; DstIdx++) {7024    // Collect low parts of muls for DstIdx.7025    for (unsigned i = DstIdx + 1 < SrcParts ? 0 : DstIdx - SrcParts + 1;7026         i <= std::min(DstIdx, SrcParts - 1); ++i) {7027      MachineInstrBuilder Mul =7028          B.buildMul(NarrowTy, Src1Regs[DstIdx - i], Src2Regs[i]);7029      Factors.push_back(Mul.getReg(0));7030    }7031    // Collect high parts of muls from previous DstIdx.7032    for (unsigned i = DstIdx < SrcParts ? 0 : DstIdx - SrcParts;7033         i <= std::min(DstIdx - 1, SrcParts - 1); ++i) {7034      MachineInstrBuilder Umulh =7035          B.buildUMulH(NarrowTy, Src1Regs[DstIdx - 1 - i], Src2Regs[i]);7036      Factors.push_back(Umulh.getReg(0));7037    }7038    // Add CarrySum from additions calculated for previous DstIdx.7039    if (DstIdx != 1) {7040      Factors.push_back(CarrySumPrevDstIdx);7041    }7042 7043    Register CarrySum;7044    // Add all factors and accumulate all carries into CarrySum.7045    if (DstIdx != DstParts - 1) {7046      MachineInstrBuilder Uaddo =7047          B.buildUAddo(NarrowTy, LLT::scalar(1), Factors[0], Factors[1]);7048      FactorSum = Uaddo.getReg(0);7049      CarrySum = B.buildZExt(NarrowTy, Uaddo.getReg(1)).getReg(0);7050      for (unsigned i = 2; i < Factors.size(); ++i) {7051        MachineInstrBuilder Uaddo =7052            B.buildUAddo(NarrowTy, LLT::scalar(1), FactorSum, Factors[i]);7053        FactorSum = Uaddo.getReg(0);7054        MachineInstrBuilder Carry = B.buildZExt(NarrowTy, Uaddo.getReg(1));7055        CarrySum = B.buildAdd(NarrowTy, CarrySum, Carry).getReg(0);7056      }7057    } else {7058      // Since value for the next index is not calculated, neither is CarrySum.7059      FactorSum = B.buildAdd(NarrowTy, Factors[0], Factors[1]).getReg(0);7060      for (unsigned i = 2; i < Factors.size(); ++i)7061        FactorSum = B.buildAdd(NarrowTy, FactorSum, Factors[i]).getReg(0);7062    }7063 7064    CarrySumPrevDstIdx = CarrySum;7065    DstRegs[DstIdx] = FactorSum;7066    Factors.clear();7067  }7068}7069 7070LegalizerHelper::LegalizeResult7071LegalizerHelper::narrowScalarAddSub(MachineInstr &MI, unsigned TypeIdx,7072                                    LLT NarrowTy) {7073  if (TypeIdx != 0)7074    return UnableToLegalize;7075 7076  Register DstReg = MI.getOperand(0).getReg();7077  LLT DstType = MRI.getType(DstReg);7078  // FIXME: add support for vector types7079  if (DstType.isVector())7080    return UnableToLegalize;7081 7082  unsigned Opcode = MI.getOpcode();7083  unsigned OpO, OpE, OpF;7084  switch (Opcode) {7085  case TargetOpcode::G_SADDO:7086  case TargetOpcode::G_SADDE:7087  case TargetOpcode::G_UADDO:7088  case TargetOpcode::G_UADDE:7089  case TargetOpcode::G_ADD:7090    OpO = TargetOpcode::G_UADDO;7091    OpE = TargetOpcode::G_UADDE;7092    OpF = TargetOpcode::G_UADDE;7093    if (Opcode == TargetOpcode::G_SADDO || Opcode == TargetOpcode::G_SADDE)7094      OpF = TargetOpcode::G_SADDE;7095    break;7096  case TargetOpcode::G_SSUBO:7097  case TargetOpcode::G_SSUBE:7098  case TargetOpcode::G_USUBO:7099  case TargetOpcode::G_USUBE:7100  case TargetOpcode::G_SUB:7101    OpO = TargetOpcode::G_USUBO;7102    OpE = TargetOpcode::G_USUBE;7103    OpF = TargetOpcode::G_USUBE;7104    if (Opcode == TargetOpcode::G_SSUBO || Opcode == TargetOpcode::G_SSUBE)7105      OpF = TargetOpcode::G_SSUBE;7106    break;7107  default:7108    llvm_unreachable("Unexpected add/sub opcode!");7109  }7110 7111  // 1 for a plain add/sub, 2 if this is an operation with a carry-out.7112  unsigned NumDefs = MI.getNumExplicitDefs();7113  Register Src1 = MI.getOperand(NumDefs).getReg();7114  Register Src2 = MI.getOperand(NumDefs + 1).getReg();7115  Register CarryDst, CarryIn;7116  if (NumDefs == 2)7117    CarryDst = MI.getOperand(1).getReg();7118  if (MI.getNumOperands() == NumDefs + 3)7119    CarryIn = MI.getOperand(NumDefs + 2).getReg();7120 7121  LLT RegTy = MRI.getType(MI.getOperand(0).getReg());7122  LLT LeftoverTy, DummyTy;7123  SmallVector<Register, 2> Src1Regs, Src2Regs, Src1Left, Src2Left, DstRegs;7124  extractParts(Src1, RegTy, NarrowTy, LeftoverTy, Src1Regs, Src1Left,7125               MIRBuilder, MRI);7126  extractParts(Src2, RegTy, NarrowTy, DummyTy, Src2Regs, Src2Left, MIRBuilder,7127               MRI);7128 7129  int NarrowParts = Src1Regs.size();7130  Src1Regs.append(Src1Left);7131  Src2Regs.append(Src2Left);7132  DstRegs.reserve(Src1Regs.size());7133 7134  for (int i = 0, e = Src1Regs.size(); i != e; ++i) {7135    Register DstReg =7136        MRI.createGenericVirtualRegister(MRI.getType(Src1Regs[i]));7137    Register CarryOut;7138    // Forward the final carry-out to the destination register7139    if (i == e - 1 && CarryDst)7140      CarryOut = CarryDst;7141    else7142      CarryOut = MRI.createGenericVirtualRegister(LLT::scalar(1));7143 7144    if (!CarryIn) {7145      MIRBuilder.buildInstr(OpO, {DstReg, CarryOut},7146                            {Src1Regs[i], Src2Regs[i]});7147    } else if (i == e - 1) {7148      MIRBuilder.buildInstr(OpF, {DstReg, CarryOut},7149                            {Src1Regs[i], Src2Regs[i], CarryIn});7150    } else {7151      MIRBuilder.buildInstr(OpE, {DstReg, CarryOut},7152                            {Src1Regs[i], Src2Regs[i], CarryIn});7153    }7154 7155    DstRegs.push_back(DstReg);7156    CarryIn = CarryOut;7157  }7158  insertParts(MI.getOperand(0).getReg(), RegTy, NarrowTy,7159              ArrayRef(DstRegs).take_front(NarrowParts), LeftoverTy,7160              ArrayRef(DstRegs).drop_front(NarrowParts));7161 7162  MI.eraseFromParent();7163  return Legalized;7164}7165 7166LegalizerHelper::LegalizeResult7167LegalizerHelper::narrowScalarMul(MachineInstr &MI, LLT NarrowTy) {7168  auto [DstReg, Src1, Src2] = MI.getFirst3Regs();7169 7170  LLT Ty = MRI.getType(DstReg);7171  if (Ty.isVector())7172    return UnableToLegalize;7173 7174  unsigned Size = Ty.getSizeInBits();7175  unsigned NarrowSize = NarrowTy.getSizeInBits();7176  if (Size % NarrowSize != 0)7177    return UnableToLegalize;7178 7179  unsigned NumParts = Size / NarrowSize;7180  bool IsMulHigh = MI.getOpcode() == TargetOpcode::G_UMULH;7181  unsigned DstTmpParts = NumParts * (IsMulHigh ? 2 : 1);7182 7183  SmallVector<Register, 2> Src1Parts, Src2Parts;7184  SmallVector<Register, 2> DstTmpRegs(DstTmpParts);7185  extractParts(Src1, NarrowTy, NumParts, Src1Parts, MIRBuilder, MRI);7186  extractParts(Src2, NarrowTy, NumParts, Src2Parts, MIRBuilder, MRI);7187  multiplyRegisters(DstTmpRegs, Src1Parts, Src2Parts, NarrowTy);7188 7189  // Take only high half of registers if this is high mul.7190  ArrayRef<Register> DstRegs(&DstTmpRegs[DstTmpParts - NumParts], NumParts);7191  MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);7192  MI.eraseFromParent();7193  return Legalized;7194}7195 7196LegalizerHelper::LegalizeResult7197LegalizerHelper::narrowScalarFPTOI(MachineInstr &MI, unsigned TypeIdx,7198                                   LLT NarrowTy) {7199  if (TypeIdx != 0)7200    return UnableToLegalize;7201 7202  bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI;7203 7204  Register Src = MI.getOperand(1).getReg();7205  LLT SrcTy = MRI.getType(Src);7206 7207  // If all finite floats fit into the narrowed integer type, we can just swap7208  // out the result type. This is practically only useful for conversions from7209  // half to at least 16-bits, so just handle the one case.7210  if (SrcTy.getScalarType() != LLT::scalar(16) ||7211      NarrowTy.getScalarSizeInBits() < (IsSigned ? 17u : 16u))7212    return UnableToLegalize;7213 7214  Observer.changingInstr(MI);7215  narrowScalarDst(MI, NarrowTy, 0,7216                  IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT);7217  Observer.changedInstr(MI);7218  return Legalized;7219}7220 7221LegalizerHelper::LegalizeResult7222LegalizerHelper::narrowScalarExtract(MachineInstr &MI, unsigned TypeIdx,7223                                     LLT NarrowTy) {7224  if (TypeIdx != 1)7225    return UnableToLegalize;7226 7227  uint64_t NarrowSize = NarrowTy.getSizeInBits();7228 7229  int64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();7230  // FIXME: add support for when SizeOp1 isn't an exact multiple of7231  // NarrowSize.7232  if (SizeOp1 % NarrowSize != 0)7233    return UnableToLegalize;7234  int NumParts = SizeOp1 / NarrowSize;7235 7236  SmallVector<Register, 2> SrcRegs, DstRegs;7237  extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,7238               MIRBuilder, MRI);7239 7240  Register OpReg = MI.getOperand(0).getReg();7241  uint64_t OpStart = MI.getOperand(2).getImm();7242  uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();7243  for (int i = 0; i < NumParts; ++i) {7244    unsigned SrcStart = i * NarrowSize;7245 7246    if (SrcStart + NarrowSize <= OpStart || SrcStart >= OpStart + OpSize) {7247      // No part of the extract uses this subregister, ignore it.7248      continue;7249    } else if (SrcStart == OpStart && NarrowTy == MRI.getType(OpReg)) {7250      // The entire subregister is extracted, forward the value.7251      DstRegs.push_back(SrcRegs[i]);7252      continue;7253    }7254 7255    // OpSegStart is where this destination segment would start in OpReg if it7256    // extended infinitely in both directions.7257    int64_t ExtractOffset;7258    uint64_t SegSize;7259    if (OpStart < SrcStart) {7260      ExtractOffset = 0;7261      SegSize = std::min(NarrowSize, OpStart + OpSize - SrcStart);7262    } else {7263      ExtractOffset = OpStart - SrcStart;7264      SegSize = std::min(SrcStart + NarrowSize - OpStart, OpSize);7265    }7266 7267    Register SegReg = SrcRegs[i];7268    if (ExtractOffset != 0 || SegSize != NarrowSize) {7269      // A genuine extract is needed.7270      SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));7271      MIRBuilder.buildExtract(SegReg, SrcRegs[i], ExtractOffset);7272    }7273 7274    DstRegs.push_back(SegReg);7275  }7276 7277  Register DstReg = MI.getOperand(0).getReg();7278  if (MRI.getType(DstReg).isVector())7279    MIRBuilder.buildBuildVector(DstReg, DstRegs);7280  else if (DstRegs.size() > 1)7281    MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);7282  else7283    MIRBuilder.buildCopy(DstReg, DstRegs[0]);7284  MI.eraseFromParent();7285  return Legalized;7286}7287 7288LegalizerHelper::LegalizeResult7289LegalizerHelper::narrowScalarInsert(MachineInstr &MI, unsigned TypeIdx,7290                                    LLT NarrowTy) {7291  // FIXME: Don't know how to handle secondary types yet.7292  if (TypeIdx != 0)7293    return UnableToLegalize;7294 7295  SmallVector<Register, 2> SrcRegs, LeftoverRegs, DstRegs;7296  LLT RegTy = MRI.getType(MI.getOperand(0).getReg());7297  LLT LeftoverTy;7298  extractParts(MI.getOperand(1).getReg(), RegTy, NarrowTy, LeftoverTy, SrcRegs,7299               LeftoverRegs, MIRBuilder, MRI);7300 7301  SrcRegs.append(LeftoverRegs);7302 7303  uint64_t NarrowSize = NarrowTy.getSizeInBits();7304  Register OpReg = MI.getOperand(2).getReg();7305  uint64_t OpStart = MI.getOperand(3).getImm();7306  uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();7307  for (int I = 0, E = SrcRegs.size(); I != E; ++I) {7308    unsigned DstStart = I * NarrowSize;7309 7310    if (DstStart == OpStart && NarrowTy == MRI.getType(OpReg)) {7311      // The entire subregister is defined by this insert, forward the new7312      // value.7313      DstRegs.push_back(OpReg);7314      continue;7315    }7316 7317    Register SrcReg = SrcRegs[I];7318    if (MRI.getType(SrcRegs[I]) == LeftoverTy) {7319      // The leftover reg is smaller than NarrowTy, so we need to extend it.7320      SrcReg = MRI.createGenericVirtualRegister(NarrowTy);7321      MIRBuilder.buildAnyExt(SrcReg, SrcRegs[I]);7322    }7323 7324    if (DstStart + NarrowSize <= OpStart || DstStart >= OpStart + OpSize) {7325      // No part of the insert affects this subregister, forward the original.7326      DstRegs.push_back(SrcReg);7327      continue;7328    }7329 7330    // OpSegStart is where this destination segment would start in OpReg if it7331    // extended infinitely in both directions.7332    int64_t ExtractOffset, InsertOffset;7333    uint64_t SegSize;7334    if (OpStart < DstStart) {7335      InsertOffset = 0;7336      ExtractOffset = DstStart - OpStart;7337      SegSize = std::min(NarrowSize, OpStart + OpSize - DstStart);7338    } else {7339      InsertOffset = OpStart - DstStart;7340      ExtractOffset = 0;7341      SegSize =7342        std::min(NarrowSize - InsertOffset, OpStart + OpSize - DstStart);7343    }7344 7345    Register SegReg = OpReg;7346    if (ExtractOffset != 0 || SegSize != OpSize) {7347      // A genuine extract is needed.7348      SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));7349      MIRBuilder.buildExtract(SegReg, OpReg, ExtractOffset);7350    }7351 7352    Register DstReg = MRI.createGenericVirtualRegister(NarrowTy);7353    MIRBuilder.buildInsert(DstReg, SrcReg, SegReg, InsertOffset);7354    DstRegs.push_back(DstReg);7355  }7356 7357  uint64_t WideSize = DstRegs.size() * NarrowSize;7358  Register DstReg = MI.getOperand(0).getReg();7359  if (WideSize > RegTy.getSizeInBits()) {7360    Register MergeReg = MRI.createGenericVirtualRegister(LLT::scalar(WideSize));7361    MIRBuilder.buildMergeLikeInstr(MergeReg, DstRegs);7362    MIRBuilder.buildTrunc(DstReg, MergeReg);7363  } else7364    MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);7365 7366  MI.eraseFromParent();7367  return Legalized;7368}7369 7370LegalizerHelper::LegalizeResult7371LegalizerHelper::narrowScalarBasic(MachineInstr &MI, unsigned TypeIdx,7372                                   LLT NarrowTy) {7373  Register DstReg = MI.getOperand(0).getReg();7374  LLT DstTy = MRI.getType(DstReg);7375 7376  assert(MI.getNumOperands() == 3 && TypeIdx == 0);7377 7378  SmallVector<Register, 4> DstRegs, DstLeftoverRegs;7379  SmallVector<Register, 4> Src0Regs, Src0LeftoverRegs;7380  SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;7381  LLT LeftoverTy;7382  if (!extractParts(MI.getOperand(1).getReg(), DstTy, NarrowTy, LeftoverTy,7383                    Src0Regs, Src0LeftoverRegs, MIRBuilder, MRI))7384    return UnableToLegalize;7385 7386  LLT Unused;7387  if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, Unused,7388                    Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))7389    llvm_unreachable("inconsistent extractParts result");7390 7391  for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {7392    auto Inst = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},7393                                        {Src0Regs[I], Src1Regs[I]});7394    DstRegs.push_back(Inst.getReg(0));7395  }7396 7397  for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {7398    auto Inst = MIRBuilder.buildInstr(7399      MI.getOpcode(),7400      {LeftoverTy}, {Src0LeftoverRegs[I], Src1LeftoverRegs[I]});7401    DstLeftoverRegs.push_back(Inst.getReg(0));7402  }7403 7404  insertParts(DstReg, DstTy, NarrowTy, DstRegs,7405              LeftoverTy, DstLeftoverRegs);7406 7407  MI.eraseFromParent();7408  return Legalized;7409}7410 7411LegalizerHelper::LegalizeResult7412LegalizerHelper::narrowScalarExt(MachineInstr &MI, unsigned TypeIdx,7413                                 LLT NarrowTy) {7414  if (TypeIdx != 0)7415    return UnableToLegalize;7416 7417  auto [DstReg, SrcReg] = MI.getFirst2Regs();7418 7419  LLT DstTy = MRI.getType(DstReg);7420  if (DstTy.isVector())7421    return UnableToLegalize;7422 7423  SmallVector<Register, 8> Parts;7424  LLT GCDTy = extractGCDType(Parts, DstTy, NarrowTy, SrcReg);7425  LLT LCMTy = buildLCMMergePieces(DstTy, NarrowTy, GCDTy, Parts, MI.getOpcode());7426  buildWidenedRemergeToDst(DstReg, LCMTy, Parts);7427 7428  MI.eraseFromParent();7429  return Legalized;7430}7431 7432LegalizerHelper::LegalizeResult7433LegalizerHelper::narrowScalarSelect(MachineInstr &MI, unsigned TypeIdx,7434                                    LLT NarrowTy) {7435  if (TypeIdx != 0)7436    return UnableToLegalize;7437 7438  Register CondReg = MI.getOperand(1).getReg();7439  LLT CondTy = MRI.getType(CondReg);7440  if (CondTy.isVector()) // TODO: Handle vselect7441    return UnableToLegalize;7442 7443  Register DstReg = MI.getOperand(0).getReg();7444  LLT DstTy = MRI.getType(DstReg);7445 7446  SmallVector<Register, 4> DstRegs, DstLeftoverRegs;7447  SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;7448  SmallVector<Register, 4> Src2Regs, Src2LeftoverRegs;7449  LLT LeftoverTy;7450  if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, LeftoverTy,7451                    Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))7452    return UnableToLegalize;7453 7454  LLT Unused;7455  if (!extractParts(MI.getOperand(3).getReg(), DstTy, NarrowTy, Unused,7456                    Src2Regs, Src2LeftoverRegs, MIRBuilder, MRI))7457    llvm_unreachable("inconsistent extractParts result");7458 7459  for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {7460    auto Select = MIRBuilder.buildSelect(NarrowTy,7461                                         CondReg, Src1Regs[I], Src2Regs[I]);7462    DstRegs.push_back(Select.getReg(0));7463  }7464 7465  for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {7466    auto Select = MIRBuilder.buildSelect(7467      LeftoverTy, CondReg, Src1LeftoverRegs[I], Src2LeftoverRegs[I]);7468    DstLeftoverRegs.push_back(Select.getReg(0));7469  }7470 7471  insertParts(DstReg, DstTy, NarrowTy, DstRegs,7472              LeftoverTy, DstLeftoverRegs);7473 7474  MI.eraseFromParent();7475  return Legalized;7476}7477 7478LegalizerHelper::LegalizeResult7479LegalizerHelper::narrowScalarCTLZ(MachineInstr &MI, unsigned TypeIdx,7480                                  LLT NarrowTy) {7481  if (TypeIdx != 1)7482    return UnableToLegalize;7483 7484  auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();7485  unsigned NarrowSize = NarrowTy.getSizeInBits();7486 7487  if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {7488    const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTLZ_ZERO_UNDEF;7489 7490    MachineIRBuilder &B = MIRBuilder;7491    auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);7492    // ctlz(Hi:Lo) -> Hi == 0 ? (NarrowSize + ctlz(Lo)) : ctlz(Hi)7493    auto C_0 = B.buildConstant(NarrowTy, 0);7494    auto HiIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1),7495                                UnmergeSrc.getReg(1), C_0);7496    auto LoCTLZ = IsUndef ?7497      B.buildCTLZ_ZERO_UNDEF(DstTy, UnmergeSrc.getReg(0)) :7498      B.buildCTLZ(DstTy, UnmergeSrc.getReg(0));7499    auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);7500    auto HiIsZeroCTLZ = B.buildAdd(DstTy, LoCTLZ, C_NarrowSize);7501    auto HiCTLZ = B.buildCTLZ_ZERO_UNDEF(DstTy, UnmergeSrc.getReg(1));7502    B.buildSelect(DstReg, HiIsZero, HiIsZeroCTLZ, HiCTLZ);7503 7504    MI.eraseFromParent();7505    return Legalized;7506  }7507 7508  return UnableToLegalize;7509}7510 7511LegalizerHelper::LegalizeResult7512LegalizerHelper::narrowScalarCTTZ(MachineInstr &MI, unsigned TypeIdx,7513                                  LLT NarrowTy) {7514  if (TypeIdx != 1)7515    return UnableToLegalize;7516 7517  auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();7518  unsigned NarrowSize = NarrowTy.getSizeInBits();7519 7520  if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {7521    const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTTZ_ZERO_UNDEF;7522 7523    MachineIRBuilder &B = MIRBuilder;7524    auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);7525    // cttz(Hi:Lo) -> Lo == 0 ? (cttz(Hi) + NarrowSize) : cttz(Lo)7526    auto C_0 = B.buildConstant(NarrowTy, 0);7527    auto LoIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1),7528                                UnmergeSrc.getReg(0), C_0);7529    auto HiCTTZ = IsUndef ?7530      B.buildCTTZ_ZERO_UNDEF(DstTy, UnmergeSrc.getReg(1)) :7531      B.buildCTTZ(DstTy, UnmergeSrc.getReg(1));7532    auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);7533    auto LoIsZeroCTTZ = B.buildAdd(DstTy, HiCTTZ, C_NarrowSize);7534    auto LoCTTZ = B.buildCTTZ_ZERO_UNDEF(DstTy, UnmergeSrc.getReg(0));7535    B.buildSelect(DstReg, LoIsZero, LoIsZeroCTTZ, LoCTTZ);7536 7537    MI.eraseFromParent();7538    return Legalized;7539  }7540 7541  return UnableToLegalize;7542}7543 7544LegalizerHelper::LegalizeResult7545LegalizerHelper::narrowScalarCTPOP(MachineInstr &MI, unsigned TypeIdx,7546                                   LLT NarrowTy) {7547  if (TypeIdx != 1)7548    return UnableToLegalize;7549 7550  auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();7551  unsigned NarrowSize = NarrowTy.getSizeInBits();7552 7553  if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {7554    auto UnmergeSrc = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));7555 7556    auto LoCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(0));7557    auto HiCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(1));7558    MIRBuilder.buildAdd(DstReg, HiCTPOP, LoCTPOP);7559 7560    MI.eraseFromParent();7561    return Legalized;7562  }7563 7564  return UnableToLegalize;7565}7566 7567LegalizerHelper::LegalizeResult7568LegalizerHelper::narrowScalarFLDEXP(MachineInstr &MI, unsigned TypeIdx,7569                                    LLT NarrowTy) {7570  if (TypeIdx != 1)7571    return UnableToLegalize;7572 7573  MachineIRBuilder &B = MIRBuilder;7574  Register ExpReg = MI.getOperand(2).getReg();7575  LLT ExpTy = MRI.getType(ExpReg);7576 7577  unsigned ClampSize = NarrowTy.getScalarSizeInBits();7578 7579  // Clamp the exponent to the range of the target type.7580  auto MinExp = B.buildConstant(ExpTy, minIntN(ClampSize));7581  auto ClampMin = B.buildSMax(ExpTy, ExpReg, MinExp);7582  auto MaxExp = B.buildConstant(ExpTy, maxIntN(ClampSize));7583  auto Clamp = B.buildSMin(ExpTy, ClampMin, MaxExp);7584 7585  auto Trunc = B.buildTrunc(NarrowTy, Clamp);7586  Observer.changingInstr(MI);7587  MI.getOperand(2).setReg(Trunc.getReg(0));7588  Observer.changedInstr(MI);7589  return Legalized;7590}7591 7592LegalizerHelper::LegalizeResult7593LegalizerHelper::lowerBitCount(MachineInstr &MI) {7594  unsigned Opc = MI.getOpcode();7595  const auto &TII = MIRBuilder.getTII();7596  auto isSupported = [this](const LegalityQuery &Q) {7597    auto QAction = LI.getAction(Q).Action;7598    return QAction == Legal || QAction == Libcall || QAction == Custom;7599  };7600  switch (Opc) {7601  default:7602    return UnableToLegalize;7603  case TargetOpcode::G_CTLZ_ZERO_UNDEF: {7604    // This trivially expands to CTLZ.7605    Observer.changingInstr(MI);7606    MI.setDesc(TII.get(TargetOpcode::G_CTLZ));7607    Observer.changedInstr(MI);7608    return Legalized;7609  }7610  case TargetOpcode::G_CTLZ: {7611    auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();7612    unsigned Len = SrcTy.getScalarSizeInBits();7613 7614    if (isSupported({TargetOpcode::G_CTLZ_ZERO_UNDEF, {DstTy, SrcTy}})) {7615      // If CTLZ_ZERO_UNDEF is supported, emit that and a select for zero.7616      auto CtlzZU = MIRBuilder.buildCTLZ_ZERO_UNDEF(DstTy, SrcReg);7617      auto ZeroSrc = MIRBuilder.buildConstant(SrcTy, 0);7618      auto ICmp = MIRBuilder.buildICmp(7619          CmpInst::ICMP_EQ, SrcTy.changeElementSize(1), SrcReg, ZeroSrc);7620      auto LenConst = MIRBuilder.buildConstant(DstTy, Len);7621      MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CtlzZU);7622      MI.eraseFromParent();7623      return Legalized;7624    }7625    // for now, we do this:7626    // NewLen = NextPowerOf2(Len);7627    // x = x | (x >> 1);7628    // x = x | (x >> 2);7629    // ...7630    // x = x | (x >>16);7631    // x = x | (x >>32); // for 64-bit input7632    // Upto NewLen/27633    // return Len - popcount(x);7634    //7635    // Ref: "Hacker's Delight" by Henry Warren7636    Register Op = SrcReg;7637    unsigned NewLen = PowerOf2Ceil(Len);7638    for (unsigned i = 0; (1U << i) <= (NewLen / 2); ++i) {7639      auto MIBShiftAmt = MIRBuilder.buildConstant(SrcTy, 1ULL << i);7640      auto MIBOp = MIRBuilder.buildOr(7641          SrcTy, Op, MIRBuilder.buildLShr(SrcTy, Op, MIBShiftAmt));7642      Op = MIBOp.getReg(0);7643    }7644    auto MIBPop = MIRBuilder.buildCTPOP(DstTy, Op);7645    MIRBuilder.buildSub(MI.getOperand(0), MIRBuilder.buildConstant(DstTy, Len),7646                        MIBPop);7647    MI.eraseFromParent();7648    return Legalized;7649  }7650  case TargetOpcode::G_CTTZ_ZERO_UNDEF: {7651    // This trivially expands to CTTZ.7652    Observer.changingInstr(MI);7653    MI.setDesc(TII.get(TargetOpcode::G_CTTZ));7654    Observer.changedInstr(MI);7655    return Legalized;7656  }7657  case TargetOpcode::G_CTTZ: {7658    auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();7659 7660    unsigned Len = SrcTy.getScalarSizeInBits();7661    if (isSupported({TargetOpcode::G_CTTZ_ZERO_UNDEF, {DstTy, SrcTy}})) {7662      // If CTTZ_ZERO_UNDEF is legal or custom, emit that and a select with7663      // zero.7664      auto CttzZU = MIRBuilder.buildCTTZ_ZERO_UNDEF(DstTy, SrcReg);7665      auto Zero = MIRBuilder.buildConstant(SrcTy, 0);7666      auto ICmp = MIRBuilder.buildICmp(7667          CmpInst::ICMP_EQ, DstTy.changeElementSize(1), SrcReg, Zero);7668      auto LenConst = MIRBuilder.buildConstant(DstTy, Len);7669      MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CttzZU);7670      MI.eraseFromParent();7671      return Legalized;7672    }7673    // for now, we use: { return popcount(~x & (x - 1)); }7674    // unless the target has ctlz but not ctpop, in which case we use:7675    // { return 32 - nlz(~x & (x-1)); }7676    // Ref: "Hacker's Delight" by Henry Warren7677    auto MIBCstNeg1 = MIRBuilder.buildConstant(SrcTy, -1);7678    auto MIBNot = MIRBuilder.buildXor(SrcTy, SrcReg, MIBCstNeg1);7679    auto MIBTmp = MIRBuilder.buildAnd(7680        SrcTy, MIBNot, MIRBuilder.buildAdd(SrcTy, SrcReg, MIBCstNeg1));7681    if (!isSupported({TargetOpcode::G_CTPOP, {SrcTy, SrcTy}}) &&7682        isSupported({TargetOpcode::G_CTLZ, {SrcTy, SrcTy}})) {7683      auto MIBCstLen = MIRBuilder.buildConstant(SrcTy, Len);7684      MIRBuilder.buildSub(MI.getOperand(0), MIBCstLen,7685                          MIRBuilder.buildCTLZ(SrcTy, MIBTmp));7686      MI.eraseFromParent();7687      return Legalized;7688    }7689    Observer.changingInstr(MI);7690    MI.setDesc(TII.get(TargetOpcode::G_CTPOP));7691    MI.getOperand(1).setReg(MIBTmp.getReg(0));7692    Observer.changedInstr(MI);7693    return Legalized;7694  }7695  case TargetOpcode::G_CTPOP: {7696    Register SrcReg = MI.getOperand(1).getReg();7697    LLT Ty = MRI.getType(SrcReg);7698    unsigned Size = Ty.getScalarSizeInBits();7699    MachineIRBuilder &B = MIRBuilder;7700 7701    // Bail out on irregular type lengths.7702    if (Size > 128 || Size % 8 != 0)7703      return UnableToLegalize;7704 7705    // Count set bits in blocks of 2 bits. Default approach would be7706    // B2Count = { val & 0x55555555 } + { (val >> 1) & 0x55555555 }7707    // We use following formula instead:7708    // B2Count = val - { (val >> 1) & 0x55555555 }7709    // since it gives same result in blocks of 2 with one instruction less.7710    auto C_1 = B.buildConstant(Ty, 1);7711    auto B2Set1LoTo1Hi = B.buildLShr(Ty, SrcReg, C_1);7712    APInt B2Mask1HiTo0 = APInt::getSplat(Size, APInt(8, 0x55));7713    auto C_B2Mask1HiTo0 = B.buildConstant(Ty, B2Mask1HiTo0);7714    auto B2Count1Hi = B.buildAnd(Ty, B2Set1LoTo1Hi, C_B2Mask1HiTo0);7715    auto B2Count = B.buildSub(Ty, SrcReg, B2Count1Hi);7716 7717    // In order to get count in blocks of 4 add values from adjacent block of 2.7718    // B4Count = { B2Count & 0x33333333 } + { (B2Count >> 2) & 0x33333333 }7719    auto C_2 = B.buildConstant(Ty, 2);7720    auto B4Set2LoTo2Hi = B.buildLShr(Ty, B2Count, C_2);7721    APInt B4Mask2HiTo0 = APInt::getSplat(Size, APInt(8, 0x33));7722    auto C_B4Mask2HiTo0 = B.buildConstant(Ty, B4Mask2HiTo0);7723    auto B4HiB2Count = B.buildAnd(Ty, B4Set2LoTo2Hi, C_B4Mask2HiTo0);7724    auto B4LoB2Count = B.buildAnd(Ty, B2Count, C_B4Mask2HiTo0);7725    auto B4Count = B.buildAdd(Ty, B4HiB2Count, B4LoB2Count);7726 7727    // For count in blocks of 8 bits we don't have to mask high 4 bits before7728    // addition since count value sits in range {0,...,8} and 4 bits are enough7729    // to hold such binary values. After addition high 4 bits still hold count7730    // of set bits in high 4 bit block, set them to zero and get 8 bit result.7731    // B8Count = { B4Count + (B4Count >> 4) } & 0x0F0F0F0F7732    auto C_4 = B.buildConstant(Ty, 4);7733    auto B8HiB4Count = B.buildLShr(Ty, B4Count, C_4);7734    auto B8CountDirty4Hi = B.buildAdd(Ty, B8HiB4Count, B4Count);7735    APInt B8Mask4HiTo0 = APInt::getSplat(Size, APInt(8, 0x0F));7736    auto C_B8Mask4HiTo0 = B.buildConstant(Ty, B8Mask4HiTo0);7737    auto B8Count = B.buildAnd(Ty, B8CountDirty4Hi, C_B8Mask4HiTo0);7738 7739    assert(Size<=128 && "Scalar size is too large for CTPOP lower algorithm");7740    // 8 bits can hold CTPOP result of 128 bit int or smaller. Mul with this7741    // bitmask will set 8 msb in ResTmp to sum of all B8Counts in 8 bit blocks.7742    auto MulMask = B.buildConstant(Ty, APInt::getSplat(Size, APInt(8, 0x01)));7743 7744    // Shift count result from 8 high bits to low bits.7745    auto C_SizeM8 = B.buildConstant(Ty, Size - 8);7746 7747    auto IsMulSupported = [this](const LLT Ty) {7748      auto Action = LI.getAction({TargetOpcode::G_MUL, {Ty}}).Action;7749      return Action == Legal || Action == WidenScalar || Action == Custom;7750    };7751    if (IsMulSupported(Ty)) {7752      auto ResTmp = B.buildMul(Ty, B8Count, MulMask);7753      B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);7754    } else {7755      auto ResTmp = B8Count;7756      for (unsigned Shift = 8; Shift < Size; Shift *= 2) {7757        auto ShiftC = B.buildConstant(Ty, Shift);7758        auto Shl = B.buildShl(Ty, ResTmp, ShiftC);7759        ResTmp = B.buildAdd(Ty, ResTmp, Shl);7760      }7761      B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);7762    }7763    MI.eraseFromParent();7764    return Legalized;7765  }7766  }7767}7768 7769// Check that (every element of) Reg is undef or not an exact multiple of BW.7770static bool isNonZeroModBitWidthOrUndef(const MachineRegisterInfo &MRI,7771                                        Register Reg, unsigned BW) {7772  return matchUnaryPredicate(7773      MRI, Reg,7774      [=](const Constant *C) {7775        // Null constant here means an undef.7776        const ConstantInt *CI = dyn_cast_or_null<ConstantInt>(C);7777        return !CI || CI->getValue().urem(BW) != 0;7778      },7779      /*AllowUndefs*/ true);7780}7781 7782LegalizerHelper::LegalizeResult7783LegalizerHelper::lowerFunnelShiftWithInverse(MachineInstr &MI) {7784  auto [Dst, X, Y, Z] = MI.getFirst4Regs();7785  LLT Ty = MRI.getType(Dst);7786  LLT ShTy = MRI.getType(Z);7787 7788  unsigned BW = Ty.getScalarSizeInBits();7789 7790  if (!isPowerOf2_32(BW))7791    return UnableToLegalize;7792 7793  const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;7794  unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;7795 7796  if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {7797    // fshl X, Y, Z -> fshr X, Y, -Z7798    // fshr X, Y, Z -> fshl X, Y, -Z7799    auto Zero = MIRBuilder.buildConstant(ShTy, 0);7800    Z = MIRBuilder.buildSub(Ty, Zero, Z).getReg(0);7801  } else {7802    // fshl X, Y, Z -> fshr (srl X, 1), (fshr X, Y, 1), ~Z7803    // fshr X, Y, Z -> fshl (fshl X, Y, 1), (shl Y, 1), ~Z7804    auto One = MIRBuilder.buildConstant(ShTy, 1);7805    if (IsFSHL) {7806      Y = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);7807      X = MIRBuilder.buildLShr(Ty, X, One).getReg(0);7808    } else {7809      X = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);7810      Y = MIRBuilder.buildShl(Ty, Y, One).getReg(0);7811    }7812 7813    Z = MIRBuilder.buildNot(ShTy, Z).getReg(0);7814  }7815 7816  MIRBuilder.buildInstr(RevOpcode, {Dst}, {X, Y, Z});7817  MI.eraseFromParent();7818  return Legalized;7819}7820 7821LegalizerHelper::LegalizeResult7822LegalizerHelper::lowerFunnelShiftAsShifts(MachineInstr &MI) {7823  auto [Dst, X, Y, Z] = MI.getFirst4Regs();7824  LLT Ty = MRI.getType(Dst);7825  LLT ShTy = MRI.getType(Z);7826 7827  const unsigned BW = Ty.getScalarSizeInBits();7828  const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;7829 7830  Register ShX, ShY;7831  Register ShAmt, InvShAmt;7832 7833  // FIXME: Emit optimized urem by constant instead of letting it expand later.7834  if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {7835    // fshl: X << C | Y >> (BW - C)7836    // fshr: X << (BW - C) | Y >> C7837    // where C = Z % BW is not zero7838    auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);7839    ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);7840    InvShAmt = MIRBuilder.buildSub(ShTy, BitWidthC, ShAmt).getReg(0);7841    ShX = MIRBuilder.buildShl(Ty, X, IsFSHL ? ShAmt : InvShAmt).getReg(0);7842    ShY = MIRBuilder.buildLShr(Ty, Y, IsFSHL ? InvShAmt : ShAmt).getReg(0);7843  } else {7844    // fshl: X << (Z % BW) | Y >> 1 >> (BW - 1 - (Z % BW))7845    // fshr: X << 1 << (BW - 1 - (Z % BW)) | Y >> (Z % BW)7846    auto Mask = MIRBuilder.buildConstant(ShTy, BW - 1);7847    if (isPowerOf2_32(BW)) {7848      // Z % BW -> Z & (BW - 1)7849      ShAmt = MIRBuilder.buildAnd(ShTy, Z, Mask).getReg(0);7850      // (BW - 1) - (Z % BW) -> ~Z & (BW - 1)7851      auto NotZ = MIRBuilder.buildNot(ShTy, Z);7852      InvShAmt = MIRBuilder.buildAnd(ShTy, NotZ, Mask).getReg(0);7853    } else {7854      auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);7855      ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);7856      InvShAmt = MIRBuilder.buildSub(ShTy, Mask, ShAmt).getReg(0);7857    }7858 7859    auto One = MIRBuilder.buildConstant(ShTy, 1);7860    if (IsFSHL) {7861      ShX = MIRBuilder.buildShl(Ty, X, ShAmt).getReg(0);7862      auto ShY1 = MIRBuilder.buildLShr(Ty, Y, One);7863      ShY = MIRBuilder.buildLShr(Ty, ShY1, InvShAmt).getReg(0);7864    } else {7865      auto ShX1 = MIRBuilder.buildShl(Ty, X, One);7866      ShX = MIRBuilder.buildShl(Ty, ShX1, InvShAmt).getReg(0);7867      ShY = MIRBuilder.buildLShr(Ty, Y, ShAmt).getReg(0);7868    }7869  }7870 7871  MIRBuilder.buildOr(Dst, ShX, ShY, MachineInstr::Disjoint);7872  MI.eraseFromParent();7873  return Legalized;7874}7875 7876LegalizerHelper::LegalizeResult7877LegalizerHelper::lowerFunnelShift(MachineInstr &MI) {7878  // These operations approximately do the following (while avoiding undefined7879  // shifts by BW):7880  // G_FSHL: (X << (Z % BW)) | (Y >> (BW - (Z % BW)))7881  // G_FSHR: (X << (BW - (Z % BW))) | (Y >> (Z % BW))7882  Register Dst = MI.getOperand(0).getReg();7883  LLT Ty = MRI.getType(Dst);7884  LLT ShTy = MRI.getType(MI.getOperand(3).getReg());7885 7886  bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;7887  unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;7888 7889  // TODO: Use smarter heuristic that accounts for vector legalization.7890  if (LI.getAction({RevOpcode, {Ty, ShTy}}).Action == Lower)7891    return lowerFunnelShiftAsShifts(MI);7892 7893  // This only works for powers of 2, fallback to shifts if it fails.7894  LegalizerHelper::LegalizeResult Result = lowerFunnelShiftWithInverse(MI);7895  if (Result == UnableToLegalize)7896    return lowerFunnelShiftAsShifts(MI);7897  return Result;7898}7899 7900LegalizerHelper::LegalizeResult LegalizerHelper::lowerEXT(MachineInstr &MI) {7901  auto [Dst, Src] = MI.getFirst2Regs();7902  LLT DstTy = MRI.getType(Dst);7903  LLT SrcTy = MRI.getType(Src);7904 7905  uint32_t DstTySize = DstTy.getSizeInBits();7906  uint32_t DstTyScalarSize = DstTy.getScalarSizeInBits();7907  uint32_t SrcTyScalarSize = SrcTy.getScalarSizeInBits();7908 7909  if (!isPowerOf2_32(DstTySize) || !isPowerOf2_32(DstTyScalarSize) ||7910      !isPowerOf2_32(SrcTyScalarSize))7911    return UnableToLegalize;7912 7913  // The step between extend is too large, split it by creating an intermediate7914  // extend instruction7915  if (SrcTyScalarSize * 2 < DstTyScalarSize) {7916    LLT MidTy = SrcTy.changeElementSize(SrcTyScalarSize * 2);7917    // If the destination type is illegal, split it into multiple statements7918    // zext x -> zext(merge(zext(unmerge), zext(unmerge)))7919    auto NewExt = MIRBuilder.buildInstr(MI.getOpcode(), {MidTy}, {Src});7920    // Unmerge the vector7921    LLT EltTy = MidTy.changeElementCount(7922        MidTy.getElementCount().divideCoefficientBy(2));7923    auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, NewExt);7924 7925    // ZExt the vectors7926    LLT ZExtResTy = DstTy.changeElementCount(7927        DstTy.getElementCount().divideCoefficientBy(2));7928    auto ZExtRes1 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},7929                                          {UnmergeSrc.getReg(0)});7930    auto ZExtRes2 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},7931                                          {UnmergeSrc.getReg(1)});7932 7933    // Merge the ending vectors7934    MIRBuilder.buildMergeLikeInstr(Dst, {ZExtRes1, ZExtRes2});7935 7936    MI.eraseFromParent();7937    return Legalized;7938  }7939  return UnableToLegalize;7940}7941 7942LegalizerHelper::LegalizeResult LegalizerHelper::lowerTRUNC(MachineInstr &MI) {7943  // MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;7944  MachineRegisterInfo &MRI = *MIRBuilder.getMRI();7945  // Similar to how operand splitting is done in SelectiondDAG, we can handle7946  // %res(v8s8) = G_TRUNC %in(v8s32) by generating:7947  //   %inlo(<4x s32>), %inhi(<4 x s32>) = G_UNMERGE %in(<8 x s32>)7948  //   %lo16(<4 x s16>) = G_TRUNC %inlo7949  //   %hi16(<4 x s16>) = G_TRUNC %inhi7950  //   %in16(<8 x s16>) = G_CONCAT_VECTORS %lo16, %hi167951  //   %res(<8 x s8>) = G_TRUNC %in167952 7953  assert(MI.getOpcode() == TargetOpcode::G_TRUNC);7954 7955  Register DstReg = MI.getOperand(0).getReg();7956  Register SrcReg = MI.getOperand(1).getReg();7957  LLT DstTy = MRI.getType(DstReg);7958  LLT SrcTy = MRI.getType(SrcReg);7959 7960  if (DstTy.isVector() && isPowerOf2_32(DstTy.getNumElements()) &&7961      isPowerOf2_32(DstTy.getScalarSizeInBits()) &&7962      isPowerOf2_32(SrcTy.getNumElements()) &&7963      isPowerOf2_32(SrcTy.getScalarSizeInBits())) {7964    // Split input type.7965    LLT SplitSrcTy = SrcTy.changeElementCount(7966        SrcTy.getElementCount().divideCoefficientBy(2));7967 7968    // First, split the source into two smaller vectors.7969    SmallVector<Register, 2> SplitSrcs;7970    extractParts(SrcReg, SplitSrcTy, 2, SplitSrcs, MIRBuilder, MRI);7971 7972    // Truncate the splits into intermediate narrower elements.7973    LLT InterTy;7974    if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())7975      InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits() * 2);7976    else7977      InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits());7978    for (Register &Src : SplitSrcs)7979      Src = MIRBuilder.buildTrunc(InterTy, Src).getReg(0);7980 7981    // Combine the new truncates into one vector7982    auto Merge = MIRBuilder.buildMergeLikeInstr(7983        DstTy.changeElementSize(InterTy.getScalarSizeInBits()), SplitSrcs);7984 7985    // Truncate the new vector to the final result type7986    if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())7987      MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), Merge.getReg(0));7988    else7989      MIRBuilder.buildCopy(MI.getOperand(0).getReg(), Merge.getReg(0));7990 7991    MI.eraseFromParent();7992 7993    return Legalized;7994  }7995  return UnableToLegalize;7996}7997 7998LegalizerHelper::LegalizeResult7999LegalizerHelper::lowerRotateWithReverseRotate(MachineInstr &MI) {8000  auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();8001  auto Zero = MIRBuilder.buildConstant(AmtTy, 0);8002  bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;8003  unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;8004  auto Neg = MIRBuilder.buildSub(AmtTy, Zero, Amt);8005  MIRBuilder.buildInstr(RevRot, {Dst}, {Src, Neg});8006  MI.eraseFromParent();8007  return Legalized;8008}8009 8010LegalizerHelper::LegalizeResult LegalizerHelper::lowerRotate(MachineInstr &MI) {8011  auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();8012 8013  unsigned EltSizeInBits = DstTy.getScalarSizeInBits();8014  bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;8015 8016  MIRBuilder.setInstrAndDebugLoc(MI);8017 8018  // If a rotate in the other direction is supported, use it.8019  unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;8020  if (LI.isLegalOrCustom({RevRot, {DstTy, SrcTy}}) &&8021      isPowerOf2_32(EltSizeInBits))8022    return lowerRotateWithReverseRotate(MI);8023 8024  // If a funnel shift is supported, use it.8025  unsigned FShOpc = IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;8026  unsigned RevFsh = !IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;8027  bool IsFShLegal = false;8028  if ((IsFShLegal = LI.isLegalOrCustom({FShOpc, {DstTy, AmtTy}})) ||8029      LI.isLegalOrCustom({RevFsh, {DstTy, AmtTy}})) {8030    auto buildFunnelShift = [&](unsigned Opc, Register R1, Register R2,8031                                Register R3) {8032      MIRBuilder.buildInstr(Opc, {R1}, {R2, R2, R3});8033      MI.eraseFromParent();8034      return Legalized;8035    };8036    // If a funnel shift in the other direction is supported, use it.8037    if (IsFShLegal) {8038      return buildFunnelShift(FShOpc, Dst, Src, Amt);8039    } else if (isPowerOf2_32(EltSizeInBits)) {8040      Amt = MIRBuilder.buildNeg(DstTy, Amt).getReg(0);8041      return buildFunnelShift(RevFsh, Dst, Src, Amt);8042    }8043  }8044 8045  auto Zero = MIRBuilder.buildConstant(AmtTy, 0);8046  unsigned ShOpc = IsLeft ? TargetOpcode::G_SHL : TargetOpcode::G_LSHR;8047  unsigned RevShiftOpc = IsLeft ? TargetOpcode::G_LSHR : TargetOpcode::G_SHL;8048  auto BitWidthMinusOneC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits - 1);8049  Register ShVal;8050  Register RevShiftVal;8051  if (isPowerOf2_32(EltSizeInBits)) {8052    // (rotl x, c) -> x << (c & (w - 1)) | x >> (-c & (w - 1))8053    // (rotr x, c) -> x >> (c & (w - 1)) | x << (-c & (w - 1))8054    auto NegAmt = MIRBuilder.buildSub(AmtTy, Zero, Amt);8055    auto ShAmt = MIRBuilder.buildAnd(AmtTy, Amt, BitWidthMinusOneC);8056    ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);8057    auto RevAmt = MIRBuilder.buildAnd(AmtTy, NegAmt, BitWidthMinusOneC);8058    RevShiftVal =8059        MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, RevAmt}).getReg(0);8060  } else {8061    // (rotl x, c) -> x << (c % w) | x >> 1 >> (w - 1 - (c % w))8062    // (rotr x, c) -> x >> (c % w) | x << 1 << (w - 1 - (c % w))8063    auto BitWidthC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits);8064    auto ShAmt = MIRBuilder.buildURem(AmtTy, Amt, BitWidthC);8065    ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);8066    auto RevAmt = MIRBuilder.buildSub(AmtTy, BitWidthMinusOneC, ShAmt);8067    auto One = MIRBuilder.buildConstant(AmtTy, 1);8068    auto Inner = MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, One});8069    RevShiftVal =8070        MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Inner, RevAmt}).getReg(0);8071  }8072  MIRBuilder.buildOr(Dst, ShVal, RevShiftVal);8073  MI.eraseFromParent();8074  return Legalized;8075}8076 8077// Expand s32 = G_UITOFP s64 using bit operations to an IEEE float8078// representation.8079LegalizerHelper::LegalizeResult8080LegalizerHelper::lowerU64ToF32BitOps(MachineInstr &MI) {8081  auto [Dst, Src] = MI.getFirst2Regs();8082  const LLT S64 = LLT::scalar(64);8083  const LLT S32 = LLT::scalar(32);8084  const LLT S1 = LLT::scalar(1);8085 8086  assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S32);8087 8088  // unsigned cul2f(ulong u) {8089  //   uint lz = clz(u);8090  //   uint e = (u != 0) ? 127U + 63U - lz : 0;8091  //   u = (u << lz) & 0x7fffffffffffffffUL;8092  //   ulong t = u & 0xffffffffffUL;8093  //   uint v = (e << 23) | (uint)(u >> 40);8094  //   uint r = t > 0x8000000000UL ? 1U : (t == 0x8000000000UL ? v & 1U : 0U);8095  //   return as_float(v + r);8096  // }8097 8098  auto Zero32 = MIRBuilder.buildConstant(S32, 0);8099  auto Zero64 = MIRBuilder.buildConstant(S64, 0);8100 8101  auto LZ = MIRBuilder.buildCTLZ_ZERO_UNDEF(S32, Src);8102 8103  auto K = MIRBuilder.buildConstant(S32, 127U + 63U);8104  auto Sub = MIRBuilder.buildSub(S32, K, LZ);8105 8106  auto NotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, Src, Zero64);8107  auto E = MIRBuilder.buildSelect(S32, NotZero, Sub, Zero32);8108 8109  auto Mask0 = MIRBuilder.buildConstant(S64, (-1ULL) >> 1);8110  auto ShlLZ = MIRBuilder.buildShl(S64, Src, LZ);8111 8112  auto U = MIRBuilder.buildAnd(S64, ShlLZ, Mask0);8113 8114  auto Mask1 = MIRBuilder.buildConstant(S64, 0xffffffffffULL);8115  auto T = MIRBuilder.buildAnd(S64, U, Mask1);8116 8117  auto UShl = MIRBuilder.buildLShr(S64, U, MIRBuilder.buildConstant(S64, 40));8118  auto ShlE = MIRBuilder.buildShl(S32, E, MIRBuilder.buildConstant(S32, 23));8119  auto V = MIRBuilder.buildOr(S32, ShlE, MIRBuilder.buildTrunc(S32, UShl));8120 8121  auto C = MIRBuilder.buildConstant(S64, 0x8000000000ULL);8122  auto RCmp = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, S1, T, C);8123  auto TCmp = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, T, C);8124  auto One = MIRBuilder.buildConstant(S32, 1);8125 8126  auto VTrunc1 = MIRBuilder.buildAnd(S32, V, One);8127  auto Select0 = MIRBuilder.buildSelect(S32, TCmp, VTrunc1, Zero32);8128  auto R = MIRBuilder.buildSelect(S32, RCmp, One, Select0);8129  MIRBuilder.buildAdd(Dst, V, R);8130 8131  MI.eraseFromParent();8132  return Legalized;8133}8134 8135// Expand s32 = G_UITOFP s64 to an IEEE float representation using bit8136// operations and G_SITOFP8137LegalizerHelper::LegalizeResult8138LegalizerHelper::lowerU64ToF32WithSITOFP(MachineInstr &MI) {8139  auto [Dst, Src] = MI.getFirst2Regs();8140  const LLT S64 = LLT::scalar(64);8141  const LLT S32 = LLT::scalar(32);8142  const LLT S1 = LLT::scalar(1);8143 8144  assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S32);8145 8146  // For i64 < INT_MAX we simply reuse SITOFP.8147  // Otherwise, divide i64 by 2, round result by ORing with the lowest bit8148  // saved before division, convert to float by SITOFP, multiply the result8149  // by 2.8150  auto One = MIRBuilder.buildConstant(S64, 1);8151  auto Zero = MIRBuilder.buildConstant(S64, 0);8152  // Result if Src < INT_MAX8153  auto SmallResult = MIRBuilder.buildSITOFP(S32, Src);8154  // Result if Src >= INT_MAX8155  auto Halved = MIRBuilder.buildLShr(S64, Src, One);8156  auto LowerBit = MIRBuilder.buildAnd(S64, Src, One);8157  auto RoundedHalved = MIRBuilder.buildOr(S64, Halved, LowerBit);8158  auto HalvedFP = MIRBuilder.buildSITOFP(S32, RoundedHalved);8159  auto LargeResult = MIRBuilder.buildFAdd(S32, HalvedFP, HalvedFP);8160  // Check if the original value is larger than INT_MAX by comparing with8161  // zero to pick one of the two conversions.8162  auto IsLarge =8163      MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_SLT, S1, Src, Zero);8164  MIRBuilder.buildSelect(Dst, IsLarge, LargeResult, SmallResult);8165 8166  MI.eraseFromParent();8167  return Legalized;8168}8169 8170// Expand s64 = G_UITOFP s64 using bit and float arithmetic operations to an8171// IEEE double representation.8172LegalizerHelper::LegalizeResult8173LegalizerHelper::lowerU64ToF64BitFloatOps(MachineInstr &MI) {8174  auto [Dst, Src] = MI.getFirst2Regs();8175  const LLT S64 = LLT::scalar(64);8176  const LLT S32 = LLT::scalar(32);8177 8178  assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S64);8179 8180  // We create double value from 32 bit parts with 32 exponent difference.8181  // Note that + and - are float operations that adjust the implicit leading8182  // one, the bases 2^52 and 2^84 are for illustrative purposes.8183  //8184  // X = 2^52 * 1.0...LowBits8185  // Y = 2^84 * 1.0...HighBits8186  // Scratch = 2^84 * 1.0...HighBits - 2^84 * 1.0 - 2^52 * 1.08187  //         = - 2^52 * 1.0...HighBits8188  // Result = - 2^52 * 1.0...HighBits + 2^52 * 1.0...LowBits8189  auto TwoP52 = MIRBuilder.buildConstant(S64, UINT64_C(0x4330000000000000));8190  auto TwoP84 = MIRBuilder.buildConstant(S64, UINT64_C(0x4530000000000000));8191  auto TwoP52P84 = llvm::bit_cast<double>(UINT64_C(0x4530000000100000));8192  auto TwoP52P84FP = MIRBuilder.buildFConstant(S64, TwoP52P84);8193  auto HalfWidth = MIRBuilder.buildConstant(S64, 32);8194 8195  auto LowBits = MIRBuilder.buildTrunc(S32, Src);8196  LowBits = MIRBuilder.buildZExt(S64, LowBits);8197  auto LowBitsFP = MIRBuilder.buildOr(S64, TwoP52, LowBits);8198  auto HighBits = MIRBuilder.buildLShr(S64, Src, HalfWidth);8199  auto HighBitsFP = MIRBuilder.buildOr(S64, TwoP84, HighBits);8200  auto Scratch = MIRBuilder.buildFSub(S64, HighBitsFP, TwoP52P84FP);8201  MIRBuilder.buildFAdd(Dst, Scratch, LowBitsFP);8202 8203  MI.eraseFromParent();8204  return Legalized;8205}8206 8207/// i64->fp16 itofp can be lowered to i64->f64,f64->f32,f32->f16. We cannot8208/// convert fpround f64->f16 without double-rounding, so we manually perform the8209/// lowering here where we know it is valid.8210static LegalizerHelper::LegalizeResult8211loweri64tof16ITOFP(MachineInstr &MI, Register Dst, LLT DstTy, Register Src,8212                   LLT SrcTy, MachineIRBuilder &MIRBuilder) {8213  auto M1 = MI.getOpcode() == TargetOpcode::G_UITOFP8214                ? MIRBuilder.buildUITOFP(SrcTy, Src)8215                : MIRBuilder.buildSITOFP(SrcTy, Src);8216  LLT S32Ty = SrcTy.changeElementSize(32);8217  auto M2 = MIRBuilder.buildFPTrunc(S32Ty, M1);8218  MIRBuilder.buildFPTrunc(Dst, M2);8219  MI.eraseFromParent();8220  return LegalizerHelper::Legalized;8221}8222 8223LegalizerHelper::LegalizeResult LegalizerHelper::lowerUITOFP(MachineInstr &MI) {8224  auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();8225 8226  if (SrcTy == LLT::scalar(1)) {8227    auto True = MIRBuilder.buildFConstant(DstTy, 1.0);8228    auto False = MIRBuilder.buildFConstant(DstTy, 0.0);8229    MIRBuilder.buildSelect(Dst, Src, True, False);8230    MI.eraseFromParent();8231    return Legalized;8232  }8233 8234  if (DstTy.getScalarSizeInBits() == 16 && SrcTy.getScalarSizeInBits() == 64)8235    return loweri64tof16ITOFP(MI, Dst, DstTy, Src, SrcTy, MIRBuilder);8236 8237  if (SrcTy != LLT::scalar(64))8238    return UnableToLegalize;8239 8240  if (DstTy == LLT::scalar(32))8241    // TODO: SelectionDAG has several alternative expansions to port which may8242    // be more reasonable depending on the available instructions. We also need8243    // a more advanced mechanism to choose an optimal version depending on8244    // target features such as sitofp or CTLZ availability.8245    return lowerU64ToF32WithSITOFP(MI);8246 8247  if (DstTy == LLT::scalar(64))8248    return lowerU64ToF64BitFloatOps(MI);8249 8250  return UnableToLegalize;8251}8252 8253LegalizerHelper::LegalizeResult LegalizerHelper::lowerSITOFP(MachineInstr &MI) {8254  auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();8255 8256  const LLT S64 = LLT::scalar(64);8257  const LLT S32 = LLT::scalar(32);8258  const LLT S1 = LLT::scalar(1);8259 8260  if (SrcTy == S1) {8261    auto True = MIRBuilder.buildFConstant(DstTy, -1.0);8262    auto False = MIRBuilder.buildFConstant(DstTy, 0.0);8263    MIRBuilder.buildSelect(Dst, Src, True, False);8264    MI.eraseFromParent();8265    return Legalized;8266  }8267 8268  if (DstTy.getScalarSizeInBits() == 16 && SrcTy.getScalarSizeInBits() == 64)8269    return loweri64tof16ITOFP(MI, Dst, DstTy, Src, SrcTy, MIRBuilder);8270 8271  if (SrcTy != S64)8272    return UnableToLegalize;8273 8274  if (DstTy == S32) {8275    // signed cl2f(long l) {8276    //   long s = l >> 63;8277    //   float r = cul2f((l + s) ^ s);8278    //   return s ? -r : r;8279    // }8280    Register L = Src;8281    auto SignBit = MIRBuilder.buildConstant(S64, 63);8282    auto S = MIRBuilder.buildAShr(S64, L, SignBit);8283 8284    auto LPlusS = MIRBuilder.buildAdd(S64, L, S);8285    auto Xor = MIRBuilder.buildXor(S64, LPlusS, S);8286    auto R = MIRBuilder.buildUITOFP(S32, Xor);8287 8288    auto RNeg = MIRBuilder.buildFNeg(S32, R);8289    auto SignNotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, S,8290                                            MIRBuilder.buildConstant(S64, 0));8291    MIRBuilder.buildSelect(Dst, SignNotZero, RNeg, R);8292    MI.eraseFromParent();8293    return Legalized;8294  }8295 8296  return UnableToLegalize;8297}8298 8299LegalizerHelper::LegalizeResult LegalizerHelper::lowerFPTOUI(MachineInstr &MI) {8300  auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();8301  const LLT S64 = LLT::scalar(64);8302  const LLT S32 = LLT::scalar(32);8303 8304  if (SrcTy != S64 && SrcTy != S32)8305    return UnableToLegalize;8306  if (DstTy != S32 && DstTy != S64)8307    return UnableToLegalize;8308 8309  // FPTOSI gives same result as FPTOUI for positive signed integers.8310  // FPTOUI needs to deal with fp values that convert to unsigned integers8311  // greater or equal to 2^31 for float or 2^63 for double. For brevity 2^Exp.8312 8313  APInt TwoPExpInt = APInt::getSignMask(DstTy.getSizeInBits());8314  APFloat TwoPExpFP(SrcTy.getSizeInBits() == 32 ? APFloat::IEEEsingle()8315                                                : APFloat::IEEEdouble(),8316                    APInt::getZero(SrcTy.getSizeInBits()));8317  TwoPExpFP.convertFromAPInt(TwoPExpInt, false, APFloat::rmNearestTiesToEven);8318 8319  MachineInstrBuilder FPTOSI = MIRBuilder.buildFPTOSI(DstTy, Src);8320 8321  MachineInstrBuilder Threshold = MIRBuilder.buildFConstant(SrcTy, TwoPExpFP);8322  // For fp Value greater or equal to Threshold(2^Exp), we use FPTOSI on8323  // (Value - 2^Exp) and add 2^Exp by setting highest bit in result to 1.8324  MachineInstrBuilder FSub = MIRBuilder.buildFSub(SrcTy, Src, Threshold);8325  MachineInstrBuilder ResLowBits = MIRBuilder.buildFPTOSI(DstTy, FSub);8326  MachineInstrBuilder ResHighBit = MIRBuilder.buildConstant(DstTy, TwoPExpInt);8327  MachineInstrBuilder Res = MIRBuilder.buildXor(DstTy, ResLowBits, ResHighBit);8328 8329  const LLT S1 = LLT::scalar(1);8330 8331  MachineInstrBuilder FCMP =8332      MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, S1, Src, Threshold);8333  MIRBuilder.buildSelect(Dst, FCMP, FPTOSI, Res);8334 8335  MI.eraseFromParent();8336  return Legalized;8337}8338 8339LegalizerHelper::LegalizeResult LegalizerHelper::lowerFPTOSI(MachineInstr &MI) {8340  auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();8341  const LLT S64 = LLT::scalar(64);8342  const LLT S32 = LLT::scalar(32);8343 8344  // FIXME: Only f32 to i64 conversions are supported.8345  if (SrcTy.getScalarType() != S32 || DstTy.getScalarType() != S64)8346    return UnableToLegalize;8347 8348  // Expand f32 -> i64 conversion8349  // This algorithm comes from compiler-rt's implementation of fixsfdi:8350  // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/fixsfdi.c8351 8352  unsigned SrcEltBits = SrcTy.getScalarSizeInBits();8353 8354  auto ExponentMask = MIRBuilder.buildConstant(SrcTy, 0x7F800000);8355  auto ExponentLoBit = MIRBuilder.buildConstant(SrcTy, 23);8356 8357  auto AndExpMask = MIRBuilder.buildAnd(SrcTy, Src, ExponentMask);8358  auto ExponentBits = MIRBuilder.buildLShr(SrcTy, AndExpMask, ExponentLoBit);8359 8360  auto SignMask = MIRBuilder.buildConstant(SrcTy,8361                                           APInt::getSignMask(SrcEltBits));8362  auto AndSignMask = MIRBuilder.buildAnd(SrcTy, Src, SignMask);8363  auto SignLowBit = MIRBuilder.buildConstant(SrcTy, SrcEltBits - 1);8364  auto Sign = MIRBuilder.buildAShr(SrcTy, AndSignMask, SignLowBit);8365  Sign = MIRBuilder.buildSExt(DstTy, Sign);8366 8367  auto MantissaMask = MIRBuilder.buildConstant(SrcTy, 0x007FFFFF);8368  auto AndMantissaMask = MIRBuilder.buildAnd(SrcTy, Src, MantissaMask);8369  auto K = MIRBuilder.buildConstant(SrcTy, 0x00800000);8370 8371  auto R = MIRBuilder.buildOr(SrcTy, AndMantissaMask, K);8372  R = MIRBuilder.buildZExt(DstTy, R);8373 8374  auto Bias = MIRBuilder.buildConstant(SrcTy, 127);8375  auto Exponent = MIRBuilder.buildSub(SrcTy, ExponentBits, Bias);8376  auto SubExponent = MIRBuilder.buildSub(SrcTy, Exponent, ExponentLoBit);8377  auto ExponentSub = MIRBuilder.buildSub(SrcTy, ExponentLoBit, Exponent);8378 8379  auto Shl = MIRBuilder.buildShl(DstTy, R, SubExponent);8380  auto Srl = MIRBuilder.buildLShr(DstTy, R, ExponentSub);8381 8382  const LLT S1 = LLT::scalar(1);8383  auto CmpGt = MIRBuilder.buildICmp(CmpInst::ICMP_SGT,8384                                    S1, Exponent, ExponentLoBit);8385 8386  R = MIRBuilder.buildSelect(DstTy, CmpGt, Shl, Srl);8387 8388  auto XorSign = MIRBuilder.buildXor(DstTy, R, Sign);8389  auto Ret = MIRBuilder.buildSub(DstTy, XorSign, Sign);8390 8391  auto ZeroSrcTy = MIRBuilder.buildConstant(SrcTy, 0);8392 8393  auto ExponentLt0 = MIRBuilder.buildICmp(CmpInst::ICMP_SLT,8394                                          S1, Exponent, ZeroSrcTy);8395 8396  auto ZeroDstTy = MIRBuilder.buildConstant(DstTy, 0);8397  MIRBuilder.buildSelect(Dst, ExponentLt0, ZeroDstTy, Ret);8398 8399  MI.eraseFromParent();8400  return Legalized;8401}8402 8403LegalizerHelper::LegalizeResult8404LegalizerHelper::lowerFPTOINT_SAT(MachineInstr &MI) {8405  auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();8406 8407  bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI_SAT;8408  unsigned SatWidth = DstTy.getScalarSizeInBits();8409 8410  // Determine minimum and maximum integer values and their corresponding8411  // floating-point values.8412  APInt MinInt, MaxInt;8413  if (IsSigned) {8414    MinInt = APInt::getSignedMinValue(SatWidth);8415    MaxInt = APInt::getSignedMaxValue(SatWidth);8416  } else {8417    MinInt = APInt::getMinValue(SatWidth);8418    MaxInt = APInt::getMaxValue(SatWidth);8419  }8420 8421  const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());8422  APFloat MinFloat(Semantics);8423  APFloat MaxFloat(Semantics);8424 8425  APFloat::opStatus MinStatus =8426      MinFloat.convertFromAPInt(MinInt, IsSigned, APFloat::rmTowardZero);8427  APFloat::opStatus MaxStatus =8428      MaxFloat.convertFromAPInt(MaxInt, IsSigned, APFloat::rmTowardZero);8429  bool AreExactFloatBounds = !(MinStatus & APFloat::opStatus::opInexact) &&8430                             !(MaxStatus & APFloat::opStatus::opInexact);8431 8432  // If the integer bounds are exactly representable as floats, emit a8433  // min+max+fptoi sequence. Otherwise we have to use a sequence of comparisons8434  // and selects.8435  if (AreExactFloatBounds) {8436    // Clamp Src by MinFloat from below. If Src is NaN the result is MinFloat.8437    auto MaxC = MIRBuilder.buildFConstant(SrcTy, MinFloat);8438    auto MaxP = MIRBuilder.buildFCmp(CmpInst::FCMP_OGT,8439                                     SrcTy.changeElementSize(1), Src, MaxC);8440    auto Max = MIRBuilder.buildSelect(SrcTy, MaxP, Src, MaxC);8441    // Clamp by MaxFloat from above. NaN cannot occur.8442    auto MinC = MIRBuilder.buildFConstant(SrcTy, MaxFloat);8443    auto MinP =8444        MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, SrcTy.changeElementSize(1), Max,8445                             MinC, MachineInstr::FmNoNans);8446    auto Min =8447        MIRBuilder.buildSelect(SrcTy, MinP, Max, MinC, MachineInstr::FmNoNans);8448    // Convert clamped value to integer. In the unsigned case we're done,8449    // because we mapped NaN to MinFloat, which will cast to zero.8450    if (!IsSigned) {8451      MIRBuilder.buildFPTOUI(Dst, Min);8452      MI.eraseFromParent();8453      return Legalized;8454    }8455 8456    // Otherwise, select 0 if Src is NaN.8457    auto FpToInt = MIRBuilder.buildFPTOSI(DstTy, Min);8458    auto IsZero = MIRBuilder.buildFCmp(CmpInst::FCMP_UNO,8459                                       DstTy.changeElementSize(1), Src, Src);8460    MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0),8461                           FpToInt);8462    MI.eraseFromParent();8463    return Legalized;8464  }8465 8466  // Result of direct conversion. The assumption here is that the operation is8467  // non-trapping and it's fine to apply it to an out-of-range value if we8468  // select it away later.8469  auto FpToInt = IsSigned ? MIRBuilder.buildFPTOSI(DstTy, Src)8470                          : MIRBuilder.buildFPTOUI(DstTy, Src);8471 8472  // If Src ULT MinFloat, select MinInt. In particular, this also selects8473  // MinInt if Src is NaN.8474  auto ULT =8475      MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, SrcTy.changeElementSize(1), Src,8476                           MIRBuilder.buildFConstant(SrcTy, MinFloat));8477  auto Max = MIRBuilder.buildSelect(8478      DstTy, ULT, MIRBuilder.buildConstant(DstTy, MinInt), FpToInt);8479  // If Src OGT MaxFloat, select MaxInt.8480  auto OGT =8481      MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, SrcTy.changeElementSize(1), Src,8482                           MIRBuilder.buildFConstant(SrcTy, MaxFloat));8483 8484  // In the unsigned case we are done, because we mapped NaN to MinInt, which8485  // is already zero.8486  if (!IsSigned) {8487    MIRBuilder.buildSelect(Dst, OGT, MIRBuilder.buildConstant(DstTy, MaxInt),8488                           Max);8489    MI.eraseFromParent();8490    return Legalized;8491  }8492 8493  // Otherwise, select 0 if Src is NaN.8494  auto Min = MIRBuilder.buildSelect(8495      DstTy, OGT, MIRBuilder.buildConstant(DstTy, MaxInt), Max);8496  auto IsZero = MIRBuilder.buildFCmp(CmpInst::FCMP_UNO,8497                                     DstTy.changeElementSize(1), Src, Src);8498  MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0), Min);8499  MI.eraseFromParent();8500  return Legalized;8501}8502 8503// f64 -> f16 conversion using round-to-nearest-even rounding mode.8504LegalizerHelper::LegalizeResult8505LegalizerHelper::lowerFPTRUNC_F64_TO_F16(MachineInstr &MI) {8506  const LLT S1 = LLT::scalar(1);8507  const LLT S32 = LLT::scalar(32);8508 8509  auto [Dst, Src] = MI.getFirst2Regs();8510  assert(MRI.getType(Dst).getScalarType() == LLT::scalar(16) &&8511         MRI.getType(Src).getScalarType() == LLT::scalar(64));8512 8513  if (MRI.getType(Src).isVector()) // TODO: Handle vectors directly.8514    return UnableToLegalize;8515 8516  if (MI.getFlag(MachineInstr::FmAfn)) {8517    unsigned Flags = MI.getFlags();8518    auto Src32 = MIRBuilder.buildFPTrunc(S32, Src, Flags);8519    MIRBuilder.buildFPTrunc(Dst, Src32, Flags);8520    MI.eraseFromParent();8521    return Legalized;8522  }8523 8524  const unsigned ExpMask = 0x7ff;8525  const unsigned ExpBiasf64 = 1023;8526  const unsigned ExpBiasf16 = 15;8527 8528  auto Unmerge = MIRBuilder.buildUnmerge(S32, Src);8529  Register U = Unmerge.getReg(0);8530  Register UH = Unmerge.getReg(1);8531 8532  auto E = MIRBuilder.buildLShr(S32, UH, MIRBuilder.buildConstant(S32, 20));8533  E = MIRBuilder.buildAnd(S32, E, MIRBuilder.buildConstant(S32, ExpMask));8534 8535  // Subtract the fp64 exponent bias (1023) to get the real exponent and8536  // add the f16 bias (15) to get the biased exponent for the f16 format.8537  E = MIRBuilder.buildAdd(8538    S32, E, MIRBuilder.buildConstant(S32, -ExpBiasf64 + ExpBiasf16));8539 8540  auto M = MIRBuilder.buildLShr(S32, UH, MIRBuilder.buildConstant(S32, 8));8541  M = MIRBuilder.buildAnd(S32, M, MIRBuilder.buildConstant(S32, 0xffe));8542 8543  auto MaskedSig = MIRBuilder.buildAnd(S32, UH,8544                                       MIRBuilder.buildConstant(S32, 0x1ff));8545  MaskedSig = MIRBuilder.buildOr(S32, MaskedSig, U);8546 8547  auto Zero = MIRBuilder.buildConstant(S32, 0);8548  auto SigCmpNE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, MaskedSig, Zero);8549  auto Lo40Set = MIRBuilder.buildZExt(S32, SigCmpNE0);8550  M = MIRBuilder.buildOr(S32, M, Lo40Set);8551 8552  // (M != 0 ? 0x0200 : 0) | 0x7c00;8553  auto Bits0x200 = MIRBuilder.buildConstant(S32, 0x0200);8554  auto CmpM_NE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, M, Zero);8555  auto SelectCC = MIRBuilder.buildSelect(S32, CmpM_NE0, Bits0x200, Zero);8556 8557  auto Bits0x7c00 = MIRBuilder.buildConstant(S32, 0x7c00);8558  auto I = MIRBuilder.buildOr(S32, SelectCC, Bits0x7c00);8559 8560  // N = M | (E << 12);8561  auto EShl12 = MIRBuilder.buildShl(S32, E, MIRBuilder.buildConstant(S32, 12));8562  auto N = MIRBuilder.buildOr(S32, M, EShl12);8563 8564  // B = clamp(1-E, 0, 13);8565  auto One = MIRBuilder.buildConstant(S32, 1);8566  auto OneSubExp = MIRBuilder.buildSub(S32, One, E);8567  auto B = MIRBuilder.buildSMax(S32, OneSubExp, Zero);8568  B = MIRBuilder.buildSMin(S32, B, MIRBuilder.buildConstant(S32, 13));8569 8570  auto SigSetHigh = MIRBuilder.buildOr(S32, M,8571                                       MIRBuilder.buildConstant(S32, 0x1000));8572 8573  auto D = MIRBuilder.buildLShr(S32, SigSetHigh, B);8574  auto D0 = MIRBuilder.buildShl(S32, D, B);8575 8576  auto D0_NE_SigSetHigh = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1,8577                                             D0, SigSetHigh);8578  auto D1 = MIRBuilder.buildZExt(S32, D0_NE_SigSetHigh);8579  D = MIRBuilder.buildOr(S32, D, D1);8580 8581  auto CmpELtOne = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, S1, E, One);8582  auto V = MIRBuilder.buildSelect(S32, CmpELtOne, D, N);8583 8584  auto VLow3 = MIRBuilder.buildAnd(S32, V, MIRBuilder.buildConstant(S32, 7));8585  V = MIRBuilder.buildLShr(S32, V, MIRBuilder.buildConstant(S32, 2));8586 8587  auto VLow3Eq3 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, VLow3,8588                                       MIRBuilder.buildConstant(S32, 3));8589  auto V0 = MIRBuilder.buildZExt(S32, VLow3Eq3);8590 8591  auto VLow3Gt5 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1, VLow3,8592                                       MIRBuilder.buildConstant(S32, 5));8593  auto V1 = MIRBuilder.buildZExt(S32, VLow3Gt5);8594 8595  V1 = MIRBuilder.buildOr(S32, V0, V1);8596  V = MIRBuilder.buildAdd(S32, V, V1);8597 8598  auto CmpEGt30 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT,  S1,8599                                       E, MIRBuilder.buildConstant(S32, 30));8600  V = MIRBuilder.buildSelect(S32, CmpEGt30,8601                             MIRBuilder.buildConstant(S32, 0x7c00), V);8602 8603  auto CmpEGt1039 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1,8604                                         E, MIRBuilder.buildConstant(S32, 1039));8605  V = MIRBuilder.buildSelect(S32, CmpEGt1039, I, V);8606 8607  // Extract the sign bit.8608  auto Sign = MIRBuilder.buildLShr(S32, UH, MIRBuilder.buildConstant(S32, 16));8609  Sign = MIRBuilder.buildAnd(S32, Sign, MIRBuilder.buildConstant(S32, 0x8000));8610 8611  // Insert the sign bit8612  V = MIRBuilder.buildOr(S32, Sign, V);8613 8614  MIRBuilder.buildTrunc(Dst, V);8615  MI.eraseFromParent();8616  return Legalized;8617}8618 8619LegalizerHelper::LegalizeResult8620LegalizerHelper::lowerFPTRUNC(MachineInstr &MI) {8621  auto [DstTy, SrcTy] = MI.getFirst2LLTs();8622  const LLT S64 = LLT::scalar(64);8623  const LLT S16 = LLT::scalar(16);8624 8625  if (DstTy.getScalarType() == S16 && SrcTy.getScalarType() == S64)8626    return lowerFPTRUNC_F64_TO_F16(MI);8627 8628  return UnableToLegalize;8629}8630 8631LegalizerHelper::LegalizeResult LegalizerHelper::lowerFPOWI(MachineInstr &MI) {8632  auto [Dst, Src0, Src1] = MI.getFirst3Regs();8633  LLT Ty = MRI.getType(Dst);8634 8635  auto CvtSrc1 = MIRBuilder.buildSITOFP(Ty, Src1);8636  MIRBuilder.buildFPow(Dst, Src0, CvtSrc1, MI.getFlags());8637  MI.eraseFromParent();8638  return Legalized;8639}8640 8641static CmpInst::Predicate minMaxToCompare(unsigned Opc) {8642  switch (Opc) {8643  case TargetOpcode::G_SMIN:8644    return CmpInst::ICMP_SLT;8645  case TargetOpcode::G_SMAX:8646    return CmpInst::ICMP_SGT;8647  case TargetOpcode::G_UMIN:8648    return CmpInst::ICMP_ULT;8649  case TargetOpcode::G_UMAX:8650    return CmpInst::ICMP_UGT;8651  default:8652    llvm_unreachable("not in integer min/max");8653  }8654}8655 8656LegalizerHelper::LegalizeResult LegalizerHelper::lowerMinMax(MachineInstr &MI) {8657  auto [Dst, Src0, Src1] = MI.getFirst3Regs();8658 8659  const CmpInst::Predicate Pred = minMaxToCompare(MI.getOpcode());8660  LLT CmpType = MRI.getType(Dst).changeElementSize(1);8661 8662  auto Cmp = MIRBuilder.buildICmp(Pred, CmpType, Src0, Src1);8663  MIRBuilder.buildSelect(Dst, Cmp, Src0, Src1);8664 8665  MI.eraseFromParent();8666  return Legalized;8667}8668 8669LegalizerHelper::LegalizeResult8670LegalizerHelper::lowerThreewayCompare(MachineInstr &MI) {8671  GSUCmp *Cmp = cast<GSUCmp>(&MI);8672 8673  Register Dst = Cmp->getReg(0);8674  LLT DstTy = MRI.getType(Dst);8675  LLT SrcTy = MRI.getType(Cmp->getReg(1));8676  LLT CmpTy = DstTy.changeElementSize(1);8677 8678  CmpInst::Predicate LTPredicate = Cmp->isSigned()8679                                       ? CmpInst::Predicate::ICMP_SLT8680                                       : CmpInst::Predicate::ICMP_ULT;8681  CmpInst::Predicate GTPredicate = Cmp->isSigned()8682                                       ? CmpInst::Predicate::ICMP_SGT8683                                       : CmpInst::Predicate::ICMP_UGT;8684 8685  auto Zero = MIRBuilder.buildConstant(DstTy, 0);8686  auto IsGT = MIRBuilder.buildICmp(GTPredicate, CmpTy, Cmp->getLHSReg(),8687                                   Cmp->getRHSReg());8688  auto IsLT = MIRBuilder.buildICmp(LTPredicate, CmpTy, Cmp->getLHSReg(),8689                                   Cmp->getRHSReg());8690 8691  auto &Ctx = MIRBuilder.getMF().getFunction().getContext();8692  auto BC = TLI.getBooleanContents(DstTy.isVector(), /*isFP=*/false);8693  if (TLI.preferSelectsOverBooleanArithmetic(8694          getApproximateEVTForLLT(SrcTy, Ctx)) ||8695      BC == TargetLowering::UndefinedBooleanContent) {8696    auto One = MIRBuilder.buildConstant(DstTy, 1);8697    auto SelectZeroOrOne = MIRBuilder.buildSelect(DstTy, IsGT, One, Zero);8698 8699    auto MinusOne = MIRBuilder.buildConstant(DstTy, -1);8700    MIRBuilder.buildSelect(Dst, IsLT, MinusOne, SelectZeroOrOne);8701  } else {8702    if (BC == TargetLowering::ZeroOrNegativeOneBooleanContent)8703      std::swap(IsGT, IsLT);8704    // Extend boolean results to DstTy, which is at least i2, before subtracting8705    // them.8706    unsigned BoolExtOp =8707        MIRBuilder.getBoolExtOp(DstTy.isVector(), /*isFP=*/false);8708    IsGT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsGT});8709    IsLT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsLT});8710    MIRBuilder.buildSub(Dst, IsGT, IsLT);8711  }8712 8713  MI.eraseFromParent();8714  return Legalized;8715}8716 8717LegalizerHelper::LegalizeResult8718LegalizerHelper::lowerFCopySign(MachineInstr &MI) {8719  auto [Dst, DstTy, Src0, Src0Ty, Src1, Src1Ty] = MI.getFirst3RegLLTs();8720  const int Src0Size = Src0Ty.getScalarSizeInBits();8721  const int Src1Size = Src1Ty.getScalarSizeInBits();8722 8723  auto SignBitMask = MIRBuilder.buildConstant(8724    Src0Ty, APInt::getSignMask(Src0Size));8725 8726  auto NotSignBitMask = MIRBuilder.buildConstant(8727    Src0Ty, APInt::getLowBitsSet(Src0Size, Src0Size - 1));8728 8729  Register And0 = MIRBuilder.buildAnd(Src0Ty, Src0, NotSignBitMask).getReg(0);8730  Register And1;8731  if (Src0Ty == Src1Ty) {8732    And1 = MIRBuilder.buildAnd(Src1Ty, Src1, SignBitMask).getReg(0);8733  } else if (Src0Size > Src1Size) {8734    auto ShiftAmt = MIRBuilder.buildConstant(Src0Ty, Src0Size - Src1Size);8735    auto Zext = MIRBuilder.buildZExt(Src0Ty, Src1);8736    auto Shift = MIRBuilder.buildShl(Src0Ty, Zext, ShiftAmt);8737    And1 = MIRBuilder.buildAnd(Src0Ty, Shift, SignBitMask).getReg(0);8738  } else {8739    auto ShiftAmt = MIRBuilder.buildConstant(Src1Ty, Src1Size - Src0Size);8740    auto Shift = MIRBuilder.buildLShr(Src1Ty, Src1, ShiftAmt);8741    auto Trunc = MIRBuilder.buildTrunc(Src0Ty, Shift);8742    And1 = MIRBuilder.buildAnd(Src0Ty, Trunc, SignBitMask).getReg(0);8743  }8744 8745  // Be careful about setting nsz/nnan/ninf on every instruction, since the8746  // constants are a nan and -0.0, but the final result should preserve8747  // everything.8748  unsigned Flags = MI.getFlags();8749 8750  // We masked the sign bit and the not-sign bit, so these are disjoint.8751  Flags |= MachineInstr::Disjoint;8752 8753  MIRBuilder.buildOr(Dst, And0, And1, Flags);8754 8755  MI.eraseFromParent();8756  return Legalized;8757}8758 8759LegalizerHelper::LegalizeResult8760LegalizerHelper::lowerFMinNumMaxNum(MachineInstr &MI) {8761  // FIXME: fminnum/fmaxnum and fminimumnum/fmaximumnum should not have8762  // identical handling. fminimumnum/fmaximumnum also need a path that do not8763  // depend on fminnum/fmaxnum.8764 8765  unsigned NewOp;8766  switch (MI.getOpcode()) {8767  case TargetOpcode::G_FMINNUM:8768    NewOp = TargetOpcode::G_FMINNUM_IEEE;8769    break;8770  case TargetOpcode::G_FMINIMUMNUM:8771    NewOp = TargetOpcode::G_FMINNUM;8772    break;8773  case TargetOpcode::G_FMAXNUM:8774    NewOp = TargetOpcode::G_FMAXNUM_IEEE;8775    break;8776  case TargetOpcode::G_FMAXIMUMNUM:8777    NewOp = TargetOpcode::G_FMAXNUM;8778    break;8779  default:8780    llvm_unreachable("unexpected min/max opcode");8781  }8782 8783  auto [Dst, Src0, Src1] = MI.getFirst3Regs();8784  LLT Ty = MRI.getType(Dst);8785 8786  if (!MI.getFlag(MachineInstr::FmNoNans)) {8787    // Insert canonicalizes if it's possible we need to quiet to get correct8788    // sNaN behavior.8789 8790    // Note this must be done here, and not as an optimization combine in the8791    // absence of a dedicate quiet-snan instruction as we're using an8792    // omni-purpose G_FCANONICALIZE.8793    if (!isKnownNeverSNaN(Src0, MRI))8794      Src0 = MIRBuilder.buildFCanonicalize(Ty, Src0, MI.getFlags()).getReg(0);8795 8796    if (!isKnownNeverSNaN(Src1, MRI))8797      Src1 = MIRBuilder.buildFCanonicalize(Ty, Src1, MI.getFlags()).getReg(0);8798  }8799 8800  // If there are no nans, it's safe to simply replace this with the non-IEEE8801  // version.8802  MIRBuilder.buildInstr(NewOp, {Dst}, {Src0, Src1}, MI.getFlags());8803  MI.eraseFromParent();8804  return Legalized;8805}8806 8807LegalizerHelper::LegalizeResult8808LegalizerHelper::lowerFMinimumMaximum(MachineInstr &MI) {8809  unsigned Opc = MI.getOpcode();8810  auto [Dst, Src0, Src1] = MI.getFirst3Regs();8811  LLT Ty = MRI.getType(Dst);8812  LLT CmpTy = Ty.changeElementSize(1);8813 8814  bool IsMax = (Opc == TargetOpcode::G_FMAXIMUM);8815  unsigned OpcIeee =8816      IsMax ? TargetOpcode::G_FMAXNUM_IEEE : TargetOpcode::G_FMINNUM_IEEE;8817  unsigned OpcNonIeee =8818      IsMax ? TargetOpcode::G_FMAXNUM : TargetOpcode::G_FMINNUM;8819  bool MinMaxMustRespectOrderedZero = false;8820  Register Res;8821 8822  // IEEE variants don't need canonicalization8823  if (LI.isLegalOrCustom({OpcIeee, Ty})) {8824    Res = MIRBuilder.buildInstr(OpcIeee, {Ty}, {Src0, Src1}).getReg(0);8825    MinMaxMustRespectOrderedZero = true;8826  } else if (LI.isLegalOrCustom({OpcNonIeee, Ty})) {8827    Res = MIRBuilder.buildInstr(OpcNonIeee, {Ty}, {Src0, Src1}).getReg(0);8828  } else {8829    auto Compare = MIRBuilder.buildFCmp(8830        IsMax ? CmpInst::FCMP_OGT : CmpInst::FCMP_OLT, CmpTy, Src0, Src1);8831    Res = MIRBuilder.buildSelect(Ty, Compare, Src0, Src1).getReg(0);8832  }8833 8834  // Propagate any NaN of both operands8835  if (!MI.getFlag(MachineInstr::FmNoNans) &&8836      (!isKnownNeverNaN(Src0, MRI) || isKnownNeverNaN(Src1, MRI))) {8837    auto IsOrdered = MIRBuilder.buildFCmp(CmpInst::FCMP_ORD, CmpTy, Src0, Src1);8838 8839    LLT ElementTy = Ty.isScalar() ? Ty : Ty.getElementType();8840    APFloat NaNValue = APFloat::getNaN(getFltSemanticForLLT(ElementTy));8841    Register NaN = MIRBuilder.buildFConstant(ElementTy, NaNValue).getReg(0);8842    if (Ty.isVector())8843      NaN = MIRBuilder.buildSplatBuildVector(Ty, NaN).getReg(0);8844 8845    Res = MIRBuilder.buildSelect(Ty, IsOrdered, Res, NaN).getReg(0);8846  }8847 8848  // fminimum/fmaximum requires -0.0 less than +0.08849  if (!MinMaxMustRespectOrderedZero && !MI.getFlag(MachineInstr::FmNsz)) {8850    GISelValueTracking VT(MIRBuilder.getMF());8851    KnownFPClass Src0Info = VT.computeKnownFPClass(Src0, fcZero);8852    KnownFPClass Src1Info = VT.computeKnownFPClass(Src1, fcZero);8853 8854    if (!Src0Info.isKnownNeverZero() && !Src1Info.isKnownNeverZero()) {8855      const unsigned Flags = MI.getFlags();8856      Register Zero = MIRBuilder.buildFConstant(Ty, 0.0).getReg(0);8857      auto IsZero = MIRBuilder.buildFCmp(CmpInst::FCMP_OEQ, CmpTy, Res, Zero);8858 8859      unsigned TestClass = IsMax ? fcPosZero : fcNegZero;8860 8861      auto LHSTestZero = MIRBuilder.buildIsFPClass(CmpTy, Src0, TestClass);8862      auto LHSSelect =8863          MIRBuilder.buildSelect(Ty, LHSTestZero, Src0, Res, Flags);8864 8865      auto RHSTestZero = MIRBuilder.buildIsFPClass(CmpTy, Src1, TestClass);8866      auto RHSSelect =8867          MIRBuilder.buildSelect(Ty, RHSTestZero, Src1, LHSSelect, Flags);8868 8869      Res = MIRBuilder.buildSelect(Ty, IsZero, RHSSelect, Res, Flags).getReg(0);8870    }8871  }8872 8873  MIRBuilder.buildCopy(Dst, Res);8874  MI.eraseFromParent();8875  return Legalized;8876}8877 8878LegalizerHelper::LegalizeResult LegalizerHelper::lowerFMad(MachineInstr &MI) {8879  // Expand G_FMAD a, b, c -> G_FADD (G_FMUL a, b), c8880  Register DstReg = MI.getOperand(0).getReg();8881  LLT Ty = MRI.getType(DstReg);8882  unsigned Flags = MI.getFlags();8883 8884  auto Mul = MIRBuilder.buildFMul(Ty, MI.getOperand(1), MI.getOperand(2),8885                                  Flags);8886  MIRBuilder.buildFAdd(DstReg, Mul, MI.getOperand(3), Flags);8887  MI.eraseFromParent();8888  return Legalized;8889}8890 8891LegalizerHelper::LegalizeResult8892LegalizerHelper::lowerIntrinsicRound(MachineInstr &MI) {8893  auto [DstReg, X] = MI.getFirst2Regs();8894  const unsigned Flags = MI.getFlags();8895  const LLT Ty = MRI.getType(DstReg);8896  const LLT CondTy = Ty.changeElementSize(1);8897 8898  // round(x) =>8899  //  t = trunc(x);8900  //  d = fabs(x - t);8901  //  o = copysign(d >= 0.5 ? 1.0 : 0.0, x);8902  //  return t + o;8903 8904  auto T = MIRBuilder.buildIntrinsicTrunc(Ty, X, Flags);8905 8906  auto Diff = MIRBuilder.buildFSub(Ty, X, T, Flags);8907  auto AbsDiff = MIRBuilder.buildFAbs(Ty, Diff, Flags);8908 8909  auto Half = MIRBuilder.buildFConstant(Ty, 0.5);8910  auto Cmp =8911      MIRBuilder.buildFCmp(CmpInst::FCMP_OGE, CondTy, AbsDiff, Half, Flags);8912 8913  // Could emit G_UITOFP instead8914  auto One = MIRBuilder.buildFConstant(Ty, 1.0);8915  auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);8916  auto BoolFP = MIRBuilder.buildSelect(Ty, Cmp, One, Zero);8917  auto SignedOffset = MIRBuilder.buildFCopysign(Ty, BoolFP, X);8918 8919  MIRBuilder.buildFAdd(DstReg, T, SignedOffset, Flags);8920 8921  MI.eraseFromParent();8922  return Legalized;8923}8924 8925LegalizerHelper::LegalizeResult LegalizerHelper::lowerFFloor(MachineInstr &MI) {8926  auto [DstReg, SrcReg] = MI.getFirst2Regs();8927  unsigned Flags = MI.getFlags();8928  LLT Ty = MRI.getType(DstReg);8929  const LLT CondTy = Ty.changeElementSize(1);8930 8931  // result = trunc(src);8932  // if (src < 0.0 && src != result)8933  //   result += -1.0.8934 8935  auto Trunc = MIRBuilder.buildIntrinsicTrunc(Ty, SrcReg, Flags);8936  auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);8937 8938  auto Lt0 = MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, CondTy,8939                                  SrcReg, Zero, Flags);8940  auto NeTrunc = MIRBuilder.buildFCmp(CmpInst::FCMP_ONE, CondTy,8941                                      SrcReg, Trunc, Flags);8942  auto And = MIRBuilder.buildAnd(CondTy, Lt0, NeTrunc);8943  auto AddVal = MIRBuilder.buildSITOFP(Ty, And);8944 8945  MIRBuilder.buildFAdd(DstReg, Trunc, AddVal, Flags);8946  MI.eraseFromParent();8947  return Legalized;8948}8949 8950LegalizerHelper::LegalizeResult8951LegalizerHelper::lowerMergeValues(MachineInstr &MI) {8952  const unsigned NumOps = MI.getNumOperands();8953  auto [DstReg, DstTy, Src0Reg, Src0Ty] = MI.getFirst2RegLLTs();8954  unsigned PartSize = Src0Ty.getSizeInBits();8955 8956  LLT WideTy = LLT::scalar(DstTy.getSizeInBits());8957  Register ResultReg = MIRBuilder.buildZExt(WideTy, Src0Reg).getReg(0);8958 8959  for (unsigned I = 2; I != NumOps; ++I) {8960    const unsigned Offset = (I - 1) * PartSize;8961 8962    Register SrcReg = MI.getOperand(I).getReg();8963    auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);8964 8965    Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :8966      MRI.createGenericVirtualRegister(WideTy);8967 8968    auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);8969    auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);8970    MIRBuilder.buildOr(NextResult, ResultReg, Shl);8971    ResultReg = NextResult;8972  }8973 8974  if (DstTy.isPointer()) {8975    if (MIRBuilder.getDataLayout().isNonIntegralAddressSpace(8976          DstTy.getAddressSpace())) {8977      LLVM_DEBUG(dbgs() << "Not casting nonintegral address space\n");8978      return UnableToLegalize;8979    }8980 8981    MIRBuilder.buildIntToPtr(DstReg, ResultReg);8982  }8983 8984  MI.eraseFromParent();8985  return Legalized;8986}8987 8988LegalizerHelper::LegalizeResult8989LegalizerHelper::lowerUnmergeValues(MachineInstr &MI) {8990  const unsigned NumDst = MI.getNumOperands() - 1;8991  Register SrcReg = MI.getOperand(NumDst).getReg();8992  Register Dst0Reg = MI.getOperand(0).getReg();8993  LLT DstTy = MRI.getType(Dst0Reg);8994  if (DstTy.isPointer())8995    return UnableToLegalize; // TODO8996 8997  SrcReg = coerceToScalar(SrcReg);8998  if (!SrcReg)8999    return UnableToLegalize;9000 9001  // Expand scalarizing unmerge as bitcast to integer and shift.9002  LLT IntTy = MRI.getType(SrcReg);9003 9004  MIRBuilder.buildTrunc(Dst0Reg, SrcReg);9005 9006  const unsigned DstSize = DstTy.getSizeInBits();9007  unsigned Offset = DstSize;9008  for (unsigned I = 1; I != NumDst; ++I, Offset += DstSize) {9009    auto ShiftAmt = MIRBuilder.buildConstant(IntTy, Offset);9010    auto Shift = MIRBuilder.buildLShr(IntTy, SrcReg, ShiftAmt);9011    MIRBuilder.buildTrunc(MI.getOperand(I), Shift);9012  }9013 9014  MI.eraseFromParent();9015  return Legalized;9016}9017 9018/// Lower a vector extract or insert by writing the vector to a stack temporary9019/// and reloading the element or vector.9020///9021/// %dst = G_EXTRACT_VECTOR_ELT %vec, %idx9022///  =>9023///  %stack_temp = G_FRAME_INDEX9024///  G_STORE %vec, %stack_temp9025///  %idx = clamp(%idx, %vec.getNumElements())9026///  %element_ptr = G_PTR_ADD %stack_temp, %idx9027///  %dst = G_LOAD %element_ptr9028LegalizerHelper::LegalizeResult9029LegalizerHelper::lowerExtractInsertVectorElt(MachineInstr &MI) {9030  Register DstReg = MI.getOperand(0).getReg();9031  Register SrcVec = MI.getOperand(1).getReg();9032  Register InsertVal;9033  if (MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)9034    InsertVal = MI.getOperand(2).getReg();9035 9036  Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();9037 9038  LLT VecTy = MRI.getType(SrcVec);9039  LLT EltTy = VecTy.getElementType();9040  unsigned NumElts = VecTy.getNumElements();9041 9042  int64_t IdxVal;9043  if (mi_match(Idx, MRI, m_ICst(IdxVal)) && IdxVal <= NumElts) {9044    SmallVector<Register, 8> SrcRegs;9045    extractParts(SrcVec, EltTy, NumElts, SrcRegs, MIRBuilder, MRI);9046 9047    if (InsertVal) {9048      SrcRegs[IdxVal] = MI.getOperand(2).getReg();9049      MIRBuilder.buildMergeLikeInstr(DstReg, SrcRegs);9050    } else {9051      MIRBuilder.buildCopy(DstReg, SrcRegs[IdxVal]);9052    }9053 9054    MI.eraseFromParent();9055    return Legalized;9056  }9057 9058  if (!EltTy.isByteSized()) { // Not implemented.9059    LLVM_DEBUG(dbgs() << "Can't handle non-byte element vectors yet\n");9060    return UnableToLegalize;9061  }9062 9063  unsigned EltBytes = EltTy.getSizeInBytes();9064  Align VecAlign = getStackTemporaryAlignment(VecTy);9065  Align EltAlign;9066 9067  MachinePointerInfo PtrInfo;9068  auto StackTemp = createStackTemporary(9069      TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign, PtrInfo);9070  MIRBuilder.buildStore(SrcVec, StackTemp, PtrInfo, VecAlign);9071 9072  // Get the pointer to the element, and be sure not to hit undefined behavior9073  // if the index is out of bounds.9074  Register EltPtr = getVectorElementPointer(StackTemp.getReg(0), VecTy, Idx);9075 9076  if (mi_match(Idx, MRI, m_ICst(IdxVal))) {9077    int64_t Offset = IdxVal * EltBytes;9078    PtrInfo = PtrInfo.getWithOffset(Offset);9079    EltAlign = commonAlignment(VecAlign, Offset);9080  } else {9081    // We lose information with a variable offset.9082    EltAlign = getStackTemporaryAlignment(EltTy);9083    PtrInfo = MachinePointerInfo(MRI.getType(EltPtr).getAddressSpace());9084  }9085 9086  if (InsertVal) {9087    // Write the inserted element9088    MIRBuilder.buildStore(InsertVal, EltPtr, PtrInfo, EltAlign);9089 9090    // Reload the whole vector.9091    MIRBuilder.buildLoad(DstReg, StackTemp, PtrInfo, VecAlign);9092  } else {9093    MIRBuilder.buildLoad(DstReg, EltPtr, PtrInfo, EltAlign);9094  }9095 9096  MI.eraseFromParent();9097  return Legalized;9098}9099 9100LegalizerHelper::LegalizeResult9101LegalizerHelper::lowerShuffleVector(MachineInstr &MI) {9102  auto [DstReg, DstTy, Src0Reg, Src0Ty, Src1Reg, Src1Ty] =9103      MI.getFirst3RegLLTs();9104  LLT IdxTy = LLT::scalar(32);9105 9106  ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();9107  Register Undef;9108  SmallVector<Register, 32> BuildVec;9109  LLT EltTy = DstTy.getScalarType();9110 9111  DenseMap<unsigned, Register> CachedExtract;9112 9113  for (int Idx : Mask) {9114    if (Idx < 0) {9115      if (!Undef.isValid())9116        Undef = MIRBuilder.buildUndef(EltTy).getReg(0);9117      BuildVec.push_back(Undef);9118      continue;9119    }9120 9121    assert(!Src0Ty.isScalar() && "Unexpected scalar G_SHUFFLE_VECTOR");9122 9123    int NumElts = Src0Ty.getNumElements();9124    Register SrcVec = Idx < NumElts ? Src0Reg : Src1Reg;9125    int ExtractIdx = Idx < NumElts ? Idx : Idx - NumElts;9126    auto [It, Inserted] = CachedExtract.try_emplace(Idx);9127    if (Inserted) {9128      auto IdxK = MIRBuilder.buildConstant(IdxTy, ExtractIdx);9129      It->second =9130          MIRBuilder.buildExtractVectorElement(EltTy, SrcVec, IdxK).getReg(0);9131    }9132    BuildVec.push_back(It->second);9133  }9134 9135  assert(DstTy.isVector() && "Unexpected scalar G_SHUFFLE_VECTOR");9136  MIRBuilder.buildBuildVector(DstReg, BuildVec);9137  MI.eraseFromParent();9138  return Legalized;9139}9140 9141LegalizerHelper::LegalizeResult9142LegalizerHelper::lowerVECTOR_COMPRESS(llvm::MachineInstr &MI) {9143  auto [Dst, DstTy, Vec, VecTy, Mask, MaskTy, Passthru, PassthruTy] =9144      MI.getFirst4RegLLTs();9145 9146  if (VecTy.isScalableVector())9147    report_fatal_error("Cannot expand masked_compress for scalable vectors.");9148 9149  Align VecAlign = getStackTemporaryAlignment(VecTy);9150  MachinePointerInfo PtrInfo;9151  Register StackPtr =9152      createStackTemporary(TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign,9153                           PtrInfo)9154          .getReg(0);9155  MachinePointerInfo ValPtrInfo =9156      MachinePointerInfo::getUnknownStack(*MI.getMF());9157 9158  LLT IdxTy = LLT::scalar(32);9159  LLT ValTy = VecTy.getElementType();9160  Align ValAlign = getStackTemporaryAlignment(ValTy);9161 9162  auto OutPos = MIRBuilder.buildConstant(IdxTy, 0);9163 9164  bool HasPassthru =9165      MRI.getVRegDef(Passthru)->getOpcode() != TargetOpcode::G_IMPLICIT_DEF;9166 9167  if (HasPassthru)9168    MIRBuilder.buildStore(Passthru, StackPtr, PtrInfo, VecAlign);9169 9170  Register LastWriteVal;9171  std::optional<APInt> PassthruSplatVal =9172      isConstantOrConstantSplatVector(*MRI.getVRegDef(Passthru), MRI);9173 9174  if (PassthruSplatVal.has_value()) {9175    LastWriteVal =9176        MIRBuilder.buildConstant(ValTy, PassthruSplatVal.value()).getReg(0);9177  } else if (HasPassthru) {9178    auto Popcount = MIRBuilder.buildZExt(MaskTy.changeElementSize(32), Mask);9179    Popcount = MIRBuilder.buildInstr(TargetOpcode::G_VECREDUCE_ADD,9180                                     {LLT::scalar(32)}, {Popcount});9181 9182    Register LastElmtPtr =9183        getVectorElementPointer(StackPtr, VecTy, Popcount.getReg(0));9184    LastWriteVal =9185        MIRBuilder.buildLoad(ValTy, LastElmtPtr, ValPtrInfo, ValAlign)9186            .getReg(0);9187  }9188 9189  unsigned NumElmts = VecTy.getNumElements();9190  for (unsigned I = 0; I < NumElmts; ++I) {9191    auto Idx = MIRBuilder.buildConstant(IdxTy, I);9192    auto Val = MIRBuilder.buildExtractVectorElement(ValTy, Vec, Idx);9193    Register ElmtPtr =9194        getVectorElementPointer(StackPtr, VecTy, OutPos.getReg(0));9195    MIRBuilder.buildStore(Val, ElmtPtr, ValPtrInfo, ValAlign);9196 9197    LLT MaskITy = MaskTy.getElementType();9198    auto MaskI = MIRBuilder.buildExtractVectorElement(MaskITy, Mask, Idx);9199    if (MaskITy.getSizeInBits() > 1)9200      MaskI = MIRBuilder.buildTrunc(LLT::scalar(1), MaskI);9201 9202    MaskI = MIRBuilder.buildZExt(IdxTy, MaskI);9203    OutPos = MIRBuilder.buildAdd(IdxTy, OutPos, MaskI);9204 9205    if (HasPassthru && I == NumElmts - 1) {9206      auto EndOfVector =9207          MIRBuilder.buildConstant(IdxTy, VecTy.getNumElements() - 1);9208      auto AllLanesSelected = MIRBuilder.buildICmp(9209          CmpInst::ICMP_UGT, LLT::scalar(1), OutPos, EndOfVector);9210      OutPos = MIRBuilder.buildInstr(TargetOpcode::G_UMIN, {IdxTy},9211                                     {OutPos, EndOfVector});9212      ElmtPtr = getVectorElementPointer(StackPtr, VecTy, OutPos.getReg(0));9213 9214      LastWriteVal =9215          MIRBuilder.buildSelect(ValTy, AllLanesSelected, Val, LastWriteVal)9216              .getReg(0);9217      MIRBuilder.buildStore(LastWriteVal, ElmtPtr, ValPtrInfo, ValAlign);9218    }9219  }9220 9221  // TODO: Use StackPtr's FrameIndex alignment.9222  MIRBuilder.buildLoad(Dst, StackPtr, PtrInfo, VecAlign);9223 9224  MI.eraseFromParent();9225  return Legalized;9226}9227 9228Register LegalizerHelper::getDynStackAllocTargetPtr(Register SPReg,9229                                                    Register AllocSize,9230                                                    Align Alignment,9231                                                    LLT PtrTy) {9232  LLT IntPtrTy = LLT::scalar(PtrTy.getSizeInBits());9233 9234  auto SPTmp = MIRBuilder.buildCopy(PtrTy, SPReg);9235  SPTmp = MIRBuilder.buildCast(IntPtrTy, SPTmp);9236 9237  // Subtract the final alloc from the SP. We use G_PTRTOINT here so we don't9238  // have to generate an extra instruction to negate the alloc and then use9239  // G_PTR_ADD to add the negative offset.9240  auto Alloc = MIRBuilder.buildSub(IntPtrTy, SPTmp, AllocSize);9241  if (Alignment > Align(1)) {9242    APInt AlignMask(IntPtrTy.getSizeInBits(), Alignment.value(), true);9243    AlignMask.negate();9244    auto AlignCst = MIRBuilder.buildConstant(IntPtrTy, AlignMask);9245    Alloc = MIRBuilder.buildAnd(IntPtrTy, Alloc, AlignCst);9246  }9247 9248  return MIRBuilder.buildCast(PtrTy, Alloc).getReg(0);9249}9250 9251LegalizerHelper::LegalizeResult9252LegalizerHelper::lowerDynStackAlloc(MachineInstr &MI) {9253  const auto &MF = *MI.getMF();9254  const auto &TFI = *MF.getSubtarget().getFrameLowering();9255  if (TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp)9256    return UnableToLegalize;9257 9258  Register Dst = MI.getOperand(0).getReg();9259  Register AllocSize = MI.getOperand(1).getReg();9260  Align Alignment = assumeAligned(MI.getOperand(2).getImm());9261 9262  LLT PtrTy = MRI.getType(Dst);9263  Register SPReg = TLI.getStackPointerRegisterToSaveRestore();9264  Register SPTmp =9265      getDynStackAllocTargetPtr(SPReg, AllocSize, Alignment, PtrTy);9266 9267  MIRBuilder.buildCopy(SPReg, SPTmp);9268  MIRBuilder.buildCopy(Dst, SPTmp);9269 9270  MI.eraseFromParent();9271  return Legalized;9272}9273 9274LegalizerHelper::LegalizeResult9275LegalizerHelper::lowerStackSave(MachineInstr &MI) {9276  Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();9277  if (!StackPtr)9278    return UnableToLegalize;9279 9280  MIRBuilder.buildCopy(MI.getOperand(0), StackPtr);9281  MI.eraseFromParent();9282  return Legalized;9283}9284 9285LegalizerHelper::LegalizeResult9286LegalizerHelper::lowerStackRestore(MachineInstr &MI) {9287  Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();9288  if (!StackPtr)9289    return UnableToLegalize;9290 9291  MIRBuilder.buildCopy(StackPtr, MI.getOperand(0));9292  MI.eraseFromParent();9293  return Legalized;9294}9295 9296LegalizerHelper::LegalizeResult9297LegalizerHelper::lowerExtract(MachineInstr &MI) {9298  auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();9299  unsigned Offset = MI.getOperand(2).getImm();9300 9301  // Extract sub-vector or one element9302  if (SrcTy.isVector()) {9303    unsigned SrcEltSize = SrcTy.getElementType().getSizeInBits();9304    unsigned DstSize = DstTy.getSizeInBits();9305 9306    if ((Offset % SrcEltSize == 0) && (DstSize % SrcEltSize == 0) &&9307        (Offset + DstSize <= SrcTy.getSizeInBits())) {9308      // Unmerge and allow access to each Src element for the artifact combiner.9309      auto Unmerge = MIRBuilder.buildUnmerge(SrcTy.getElementType(), SrcReg);9310 9311      // Take element(s) we need to extract and copy it (merge them).9312      SmallVector<Register, 8> SubVectorElts;9313      for (unsigned Idx = Offset / SrcEltSize;9314           Idx < (Offset + DstSize) / SrcEltSize; ++Idx) {9315        SubVectorElts.push_back(Unmerge.getReg(Idx));9316      }9317      if (SubVectorElts.size() == 1)9318        MIRBuilder.buildCopy(DstReg, SubVectorElts[0]);9319      else9320        MIRBuilder.buildMergeLikeInstr(DstReg, SubVectorElts);9321 9322      MI.eraseFromParent();9323      return Legalized;9324    }9325  }9326 9327  if (DstTy.isScalar() &&9328      (SrcTy.isScalar() ||9329       (SrcTy.isVector() && DstTy == SrcTy.getElementType()))) {9330    LLT SrcIntTy = SrcTy;9331    if (!SrcTy.isScalar()) {9332      SrcIntTy = LLT::scalar(SrcTy.getSizeInBits());9333      SrcReg = MIRBuilder.buildBitcast(SrcIntTy, SrcReg).getReg(0);9334    }9335 9336    if (Offset == 0)9337      MIRBuilder.buildTrunc(DstReg, SrcReg);9338    else {9339      auto ShiftAmt = MIRBuilder.buildConstant(SrcIntTy, Offset);9340      auto Shr = MIRBuilder.buildLShr(SrcIntTy, SrcReg, ShiftAmt);9341      MIRBuilder.buildTrunc(DstReg, Shr);9342    }9343 9344    MI.eraseFromParent();9345    return Legalized;9346  }9347 9348  return UnableToLegalize;9349}9350 9351LegalizerHelper::LegalizeResult LegalizerHelper::lowerInsert(MachineInstr &MI) {9352  auto [Dst, Src, InsertSrc] = MI.getFirst3Regs();9353  uint64_t Offset = MI.getOperand(3).getImm();9354 9355  LLT DstTy = MRI.getType(Src);9356  LLT InsertTy = MRI.getType(InsertSrc);9357 9358  // Insert sub-vector or one element9359  if (DstTy.isVector() && !InsertTy.isPointer()) {9360    LLT EltTy = DstTy.getElementType();9361    unsigned EltSize = EltTy.getSizeInBits();9362    unsigned InsertSize = InsertTy.getSizeInBits();9363 9364    if ((Offset % EltSize == 0) && (InsertSize % EltSize == 0) &&9365        (Offset + InsertSize <= DstTy.getSizeInBits())) {9366      auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, Src);9367      SmallVector<Register, 8> DstElts;9368      unsigned Idx = 0;9369      // Elements from Src before insert start Offset9370      for (; Idx < Offset / EltSize; ++Idx) {9371        DstElts.push_back(UnmergeSrc.getReg(Idx));9372      }9373 9374      // Replace elements in Src with elements from InsertSrc9375      if (InsertTy.getSizeInBits() > EltSize) {9376        auto UnmergeInsertSrc = MIRBuilder.buildUnmerge(EltTy, InsertSrc);9377        for (unsigned i = 0; Idx < (Offset + InsertSize) / EltSize;9378             ++Idx, ++i) {9379          DstElts.push_back(UnmergeInsertSrc.getReg(i));9380        }9381      } else {9382        DstElts.push_back(InsertSrc);9383        ++Idx;9384      }9385 9386      // Remaining elements from Src after insert9387      for (; Idx < DstTy.getNumElements(); ++Idx) {9388        DstElts.push_back(UnmergeSrc.getReg(Idx));9389      }9390 9391      MIRBuilder.buildMergeLikeInstr(Dst, DstElts);9392      MI.eraseFromParent();9393      return Legalized;9394    }9395  }9396 9397  if (InsertTy.isVector() ||9398      (DstTy.isVector() && DstTy.getElementType() != InsertTy))9399    return UnableToLegalize;9400 9401  const DataLayout &DL = MIRBuilder.getDataLayout();9402  if ((DstTy.isPointer() &&9403       DL.isNonIntegralAddressSpace(DstTy.getAddressSpace())) ||9404      (InsertTy.isPointer() &&9405       DL.isNonIntegralAddressSpace(InsertTy.getAddressSpace()))) {9406    LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");9407    return UnableToLegalize;9408  }9409 9410  LLT IntDstTy = DstTy;9411 9412  if (!DstTy.isScalar()) {9413    IntDstTy = LLT::scalar(DstTy.getSizeInBits());9414    Src = MIRBuilder.buildCast(IntDstTy, Src).getReg(0);9415  }9416 9417  if (!InsertTy.isScalar()) {9418    const LLT IntInsertTy = LLT::scalar(InsertTy.getSizeInBits());9419    InsertSrc = MIRBuilder.buildPtrToInt(IntInsertTy, InsertSrc).getReg(0);9420  }9421 9422  Register ExtInsSrc = MIRBuilder.buildZExt(IntDstTy, InsertSrc).getReg(0);9423  if (Offset != 0) {9424    auto ShiftAmt = MIRBuilder.buildConstant(IntDstTy, Offset);9425    ExtInsSrc = MIRBuilder.buildShl(IntDstTy, ExtInsSrc, ShiftAmt).getReg(0);9426  }9427 9428  APInt MaskVal = APInt::getBitsSetWithWrap(9429      DstTy.getSizeInBits(), Offset + InsertTy.getSizeInBits(), Offset);9430 9431  auto Mask = MIRBuilder.buildConstant(IntDstTy, MaskVal);9432  auto MaskedSrc = MIRBuilder.buildAnd(IntDstTy, Src, Mask);9433  auto Or = MIRBuilder.buildOr(IntDstTy, MaskedSrc, ExtInsSrc);9434 9435  MIRBuilder.buildCast(Dst, Or);9436  MI.eraseFromParent();9437  return Legalized;9438}9439 9440LegalizerHelper::LegalizeResult9441LegalizerHelper::lowerSADDO_SSUBO(MachineInstr &MI) {9442  auto [Dst0, Dst0Ty, Dst1, Dst1Ty, LHS, LHSTy, RHS, RHSTy] =9443      MI.getFirst4RegLLTs();9444  const bool IsAdd = MI.getOpcode() == TargetOpcode::G_SADDO;9445 9446  LLT Ty = Dst0Ty;9447  LLT BoolTy = Dst1Ty;9448 9449  Register NewDst0 = MRI.cloneVirtualRegister(Dst0);9450 9451  if (IsAdd)9452    MIRBuilder.buildAdd(NewDst0, LHS, RHS);9453  else9454    MIRBuilder.buildSub(NewDst0, LHS, RHS);9455 9456  // TODO: If SADDSAT/SSUBSAT is legal, compare results to detect overflow.9457 9458  auto Zero = MIRBuilder.buildConstant(Ty, 0);9459 9460  // For an addition, the result should be less than one of the operands (LHS)9461  // if and only if the other operand (RHS) is negative, otherwise there will9462  // be overflow.9463  // For a subtraction, the result should be less than one of the operands9464  // (LHS) if and only if the other operand (RHS) is (non-zero) positive,9465  // otherwise there will be overflow.9466  auto ResultLowerThanLHS =9467      MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, LHS);9468  auto ConditionRHS = MIRBuilder.buildICmp(9469      IsAdd ? CmpInst::ICMP_SLT : CmpInst::ICMP_SGT, BoolTy, RHS, Zero);9470 9471  MIRBuilder.buildXor(Dst1, ConditionRHS, ResultLowerThanLHS);9472 9473  MIRBuilder.buildCopy(Dst0, NewDst0);9474  MI.eraseFromParent();9475 9476  return Legalized;9477}9478 9479LegalizerHelper::LegalizeResult LegalizerHelper::lowerSADDE(MachineInstr &MI) {9480  auto [Res, OvOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();9481  const LLT Ty = MRI.getType(Res);9482 9483  // sum = LHS + RHS + zext(CarryIn)9484  auto Tmp = MIRBuilder.buildAdd(Ty, LHS, RHS);9485  auto CarryZ = MIRBuilder.buildZExt(Ty, CarryIn);9486  auto Sum = MIRBuilder.buildAdd(Ty, Tmp, CarryZ);9487  MIRBuilder.buildCopy(Res, Sum);9488 9489  // OvOut = icmp slt ((sum ^ lhs) & (sum ^ rhs)), 09490  auto AX = MIRBuilder.buildXor(Ty, Sum, LHS);9491  auto BX = MIRBuilder.buildXor(Ty, Sum, RHS);9492  auto T = MIRBuilder.buildAnd(Ty, AX, BX);9493 9494  auto Zero = MIRBuilder.buildConstant(Ty, 0);9495  MIRBuilder.buildICmp(CmpInst::ICMP_SLT, OvOut, T, Zero);9496 9497  MI.eraseFromParent();9498  return Legalized;9499}9500 9501LegalizerHelper::LegalizeResult LegalizerHelper::lowerSSUBE(MachineInstr &MI) {9502  auto [Res, OvOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();9503  const LLT Ty = MRI.getType(Res);9504 9505  // Diff = LHS - (RHS + zext(CarryIn))9506  auto CarryZ = MIRBuilder.buildZExt(Ty, CarryIn);9507  auto RHSPlusCI = MIRBuilder.buildAdd(Ty, RHS, CarryZ);9508  auto Diff = MIRBuilder.buildSub(Ty, LHS, RHSPlusCI);9509  MIRBuilder.buildCopy(Res, Diff);9510 9511  // ov = msb((LHS ^ RHS) & (LHS ^ Diff))9512  auto X1 = MIRBuilder.buildXor(Ty, LHS, RHS);9513  auto X2 = MIRBuilder.buildXor(Ty, LHS, Diff);9514  auto T = MIRBuilder.buildAnd(Ty, X1, X2);9515  auto Zero = MIRBuilder.buildConstant(Ty, 0);9516  MIRBuilder.buildICmp(CmpInst::ICMP_SLT, OvOut, T, Zero);9517 9518  MI.eraseFromParent();9519  return Legalized;9520}9521 9522LegalizerHelper::LegalizeResult9523LegalizerHelper::lowerAddSubSatToMinMax(MachineInstr &MI) {9524  auto [Res, LHS, RHS] = MI.getFirst3Regs();9525  LLT Ty = MRI.getType(Res);9526  bool IsSigned;9527  bool IsAdd;9528  unsigned BaseOp;9529  switch (MI.getOpcode()) {9530  default:9531    llvm_unreachable("unexpected addsat/subsat opcode");9532  case TargetOpcode::G_UADDSAT:9533    IsSigned = false;9534    IsAdd = true;9535    BaseOp = TargetOpcode::G_ADD;9536    break;9537  case TargetOpcode::G_SADDSAT:9538    IsSigned = true;9539    IsAdd = true;9540    BaseOp = TargetOpcode::G_ADD;9541    break;9542  case TargetOpcode::G_USUBSAT:9543    IsSigned = false;9544    IsAdd = false;9545    BaseOp = TargetOpcode::G_SUB;9546    break;9547  case TargetOpcode::G_SSUBSAT:9548    IsSigned = true;9549    IsAdd = false;9550    BaseOp = TargetOpcode::G_SUB;9551    break;9552  }9553 9554  if (IsSigned) {9555    // sadd.sat(a, b) ->9556    //   hi = 0x7fffffff - smax(a, 0)9557    //   lo = 0x80000000 - smin(a, 0)9558    //   a + smin(smax(lo, b), hi)9559    // ssub.sat(a, b) ->9560    //   lo = smax(a, -1) - 0x7fffffff9561    //   hi = smin(a, -1) - 0x800000009562    //   a - smin(smax(lo, b), hi)9563    // TODO: AMDGPU can use a "median of 3" instruction here:9564    //   a +/- med3(lo, b, hi)9565    uint64_t NumBits = Ty.getScalarSizeInBits();9566    auto MaxVal =9567        MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(NumBits));9568    auto MinVal =9569        MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));9570    MachineInstrBuilder Hi, Lo;9571    if (IsAdd) {9572      auto Zero = MIRBuilder.buildConstant(Ty, 0);9573      Hi = MIRBuilder.buildSub(Ty, MaxVal, MIRBuilder.buildSMax(Ty, LHS, Zero));9574      Lo = MIRBuilder.buildSub(Ty, MinVal, MIRBuilder.buildSMin(Ty, LHS, Zero));9575    } else {9576      auto NegOne = MIRBuilder.buildConstant(Ty, -1);9577      Lo = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMax(Ty, LHS, NegOne),9578                               MaxVal);9579      Hi = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMin(Ty, LHS, NegOne),9580                               MinVal);9581    }9582    auto RHSClamped =9583        MIRBuilder.buildSMin(Ty, MIRBuilder.buildSMax(Ty, Lo, RHS), Hi);9584    MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, RHSClamped});9585  } else {9586    // uadd.sat(a, b) -> a + umin(~a, b)9587    // usub.sat(a, b) -> a - umin(a, b)9588    Register Not = IsAdd ? MIRBuilder.buildNot(Ty, LHS).getReg(0) : LHS;9589    auto Min = MIRBuilder.buildUMin(Ty, Not, RHS);9590    MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, Min});9591  }9592 9593  MI.eraseFromParent();9594  return Legalized;9595}9596 9597LegalizerHelper::LegalizeResult9598LegalizerHelper::lowerAddSubSatToAddoSubo(MachineInstr &MI) {9599  auto [Res, LHS, RHS] = MI.getFirst3Regs();9600  LLT Ty = MRI.getType(Res);9601  LLT BoolTy = Ty.changeElementSize(1);9602  bool IsSigned;9603  bool IsAdd;9604  unsigned OverflowOp;9605  switch (MI.getOpcode()) {9606  default:9607    llvm_unreachable("unexpected addsat/subsat opcode");9608  case TargetOpcode::G_UADDSAT:9609    IsSigned = false;9610    IsAdd = true;9611    OverflowOp = TargetOpcode::G_UADDO;9612    break;9613  case TargetOpcode::G_SADDSAT:9614    IsSigned = true;9615    IsAdd = true;9616    OverflowOp = TargetOpcode::G_SADDO;9617    break;9618  case TargetOpcode::G_USUBSAT:9619    IsSigned = false;9620    IsAdd = false;9621    OverflowOp = TargetOpcode::G_USUBO;9622    break;9623  case TargetOpcode::G_SSUBSAT:9624    IsSigned = true;9625    IsAdd = false;9626    OverflowOp = TargetOpcode::G_SSUBO;9627    break;9628  }9629 9630  auto OverflowRes =9631      MIRBuilder.buildInstr(OverflowOp, {Ty, BoolTy}, {LHS, RHS});9632  Register Tmp = OverflowRes.getReg(0);9633  Register Ov = OverflowRes.getReg(1);9634  MachineInstrBuilder Clamp;9635  if (IsSigned) {9636    // sadd.sat(a, b) ->9637    //   {tmp, ov} = saddo(a, b)9638    //   ov ? (tmp >>s 31) + 0x80000000 : r9639    // ssub.sat(a, b) ->9640    //   {tmp, ov} = ssubo(a, b)9641    //   ov ? (tmp >>s 31) + 0x80000000 : r9642    uint64_t NumBits = Ty.getScalarSizeInBits();9643    auto ShiftAmount = MIRBuilder.buildConstant(Ty, NumBits - 1);9644    auto Sign = MIRBuilder.buildAShr(Ty, Tmp, ShiftAmount);9645    auto MinVal =9646        MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));9647    Clamp = MIRBuilder.buildAdd(Ty, Sign, MinVal);9648  } else {9649    // uadd.sat(a, b) ->9650    //   {tmp, ov} = uaddo(a, b)9651    //   ov ? 0xffffffff : tmp9652    // usub.sat(a, b) ->9653    //   {tmp, ov} = usubo(a, b)9654    //   ov ? 0 : tmp9655    Clamp = MIRBuilder.buildConstant(Ty, IsAdd ? -1 : 0);9656  }9657  MIRBuilder.buildSelect(Res, Ov, Clamp, Tmp);9658 9659  MI.eraseFromParent();9660  return Legalized;9661}9662 9663LegalizerHelper::LegalizeResult9664LegalizerHelper::lowerShlSat(MachineInstr &MI) {9665  assert((MI.getOpcode() == TargetOpcode::G_SSHLSAT ||9666          MI.getOpcode() == TargetOpcode::G_USHLSAT) &&9667         "Expected shlsat opcode!");9668  bool IsSigned = MI.getOpcode() == TargetOpcode::G_SSHLSAT;9669  auto [Res, LHS, RHS] = MI.getFirst3Regs();9670  LLT Ty = MRI.getType(Res);9671  LLT BoolTy = Ty.changeElementSize(1);9672 9673  unsigned BW = Ty.getScalarSizeInBits();9674  auto Result = MIRBuilder.buildShl(Ty, LHS, RHS);9675  auto Orig = IsSigned ? MIRBuilder.buildAShr(Ty, Result, RHS)9676                       : MIRBuilder.buildLShr(Ty, Result, RHS);9677 9678  MachineInstrBuilder SatVal;9679  if (IsSigned) {9680    auto SatMin = MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(BW));9681    auto SatMax = MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(BW));9682    auto Cmp = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS,9683                                    MIRBuilder.buildConstant(Ty, 0));9684    SatVal = MIRBuilder.buildSelect(Ty, Cmp, SatMin, SatMax);9685  } else {9686    SatVal = MIRBuilder.buildConstant(Ty, APInt::getMaxValue(BW));9687  }9688  auto Ov = MIRBuilder.buildICmp(CmpInst::ICMP_NE, BoolTy, LHS, Orig);9689  MIRBuilder.buildSelect(Res, Ov, SatVal, Result);9690 9691  MI.eraseFromParent();9692  return Legalized;9693}9694 9695LegalizerHelper::LegalizeResult LegalizerHelper::lowerBswap(MachineInstr &MI) {9696  auto [Dst, Src] = MI.getFirst2Regs();9697  const LLT Ty = MRI.getType(Src);9698  unsigned SizeInBytes = (Ty.getScalarSizeInBits() + 7) / 8;9699  unsigned BaseShiftAmt = (SizeInBytes - 1) * 8;9700 9701  // Swap most and least significant byte, set remaining bytes in Res to zero.9702  auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt);9703  auto LSByteShiftedLeft = MIRBuilder.buildShl(Ty, Src, ShiftAmt);9704  auto MSByteShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);9705  auto Res = MIRBuilder.buildOr(Ty, MSByteShiftedRight, LSByteShiftedLeft);9706 9707  // Set i-th high/low byte in Res to i-th low/high byte from Src.9708  for (unsigned i = 1; i < SizeInBytes / 2; ++i) {9709    // AND with Mask leaves byte i unchanged and sets remaining bytes to 0.9710    APInt APMask(SizeInBytes * 8, 0xFF << (i * 8));9711    auto Mask = MIRBuilder.buildConstant(Ty, APMask);9712    auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt - 16 * i);9713    // Low byte shifted left to place of high byte: (Src & Mask) << ShiftAmt.9714    auto LoByte = MIRBuilder.buildAnd(Ty, Src, Mask);9715    auto LoShiftedLeft = MIRBuilder.buildShl(Ty, LoByte, ShiftAmt);9716    Res = MIRBuilder.buildOr(Ty, Res, LoShiftedLeft);9717    // High byte shifted right to place of low byte: (Src >> ShiftAmt) & Mask.9718    auto SrcShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);9719    auto HiShiftedRight = MIRBuilder.buildAnd(Ty, SrcShiftedRight, Mask);9720    Res = MIRBuilder.buildOr(Ty, Res, HiShiftedRight);9721  }9722  Res.getInstr()->getOperand(0).setReg(Dst);9723 9724  MI.eraseFromParent();9725  return Legalized;9726}9727 9728//{ (Src & Mask) >> N } | { (Src << N) & Mask }9729static MachineInstrBuilder SwapN(unsigned N, DstOp Dst, MachineIRBuilder &B,9730                                 MachineInstrBuilder Src, const APInt &Mask) {9731  const LLT Ty = Dst.getLLTTy(*B.getMRI());9732  MachineInstrBuilder C_N = B.buildConstant(Ty, N);9733  MachineInstrBuilder MaskLoNTo0 = B.buildConstant(Ty, Mask);9734  auto LHS = B.buildLShr(Ty, B.buildAnd(Ty, Src, MaskLoNTo0), C_N);9735  auto RHS = B.buildAnd(Ty, B.buildShl(Ty, Src, C_N), MaskLoNTo0);9736  return B.buildOr(Dst, LHS, RHS);9737}9738 9739LegalizerHelper::LegalizeResult9740LegalizerHelper::lowerBitreverse(MachineInstr &MI) {9741  auto [Dst, Src] = MI.getFirst2Regs();9742  const LLT SrcTy = MRI.getType(Src);9743  unsigned Size = SrcTy.getScalarSizeInBits();9744  unsigned VSize = SrcTy.getSizeInBits();9745 9746  if (Size >= 8) {9747    if (SrcTy.isVector() && (VSize % 8 == 0) &&9748        (LI.isLegal({TargetOpcode::G_BITREVERSE,9749                     {LLT::fixed_vector(VSize / 8, 8),9750                      LLT::fixed_vector(VSize / 8, 8)}}))) {9751      // If bitreverse is legal for i8 vector of the same size, then cast9752      // to i8 vector type.9753      // e.g. v4s32 -> v16s89754      LLT VTy = LLT::fixed_vector(VSize / 8, 8);9755      auto BSWAP = MIRBuilder.buildBSwap(SrcTy, Src);9756      auto Cast = MIRBuilder.buildBitcast(VTy, BSWAP);9757      auto RBIT = MIRBuilder.buildBitReverse(VTy, Cast);9758      MIRBuilder.buildBitcast(Dst, RBIT);9759    } else {9760      MachineInstrBuilder BSWAP =9761          MIRBuilder.buildInstr(TargetOpcode::G_BSWAP, {SrcTy}, {Src});9762 9763      // swap high and low 4 bits in 8 bit blocks 7654|3210 -> 3210|76549764      //    [(val & 0xF0F0F0F0) >> 4] | [(val & 0x0F0F0F0F) << 4]9765      // -> [(val & 0xF0F0F0F0) >> 4] | [(val << 4) & 0xF0F0F0F0]9766      MachineInstrBuilder Swap4 = SwapN(4, SrcTy, MIRBuilder, BSWAP,9767                                        APInt::getSplat(Size, APInt(8, 0xF0)));9768 9769      // swap high and low 2 bits in 4 bit blocks 32|10 76|54 -> 10|32 54|769770      //    [(val & 0xCCCCCCCC) >> 2] & [(val & 0x33333333) << 2]9771      // -> [(val & 0xCCCCCCCC) >> 2] & [(val << 2) & 0xCCCCCCCC]9772      MachineInstrBuilder Swap2 = SwapN(2, SrcTy, MIRBuilder, Swap4,9773                                        APInt::getSplat(Size, APInt(8, 0xCC)));9774 9775      // swap high and low 1 bit in 2 bit blocks 1|0 3|2 5|4 7|6 -> 0|1 2|3 4|59776      // 6|79777      //    [(val & 0xAAAAAAAA) >> 1] & [(val & 0x55555555) << 1]9778      // -> [(val & 0xAAAAAAAA) >> 1] & [(val << 1) & 0xAAAAAAAA]9779      SwapN(1, Dst, MIRBuilder, Swap2, APInt::getSplat(Size, APInt(8, 0xAA)));9780    }9781  } else {9782    // Expand bitreverse for types smaller than 8 bits.9783    MachineInstrBuilder Tmp;9784    for (unsigned I = 0, J = Size - 1; I < Size; ++I, --J) {9785      MachineInstrBuilder Tmp2;9786      if (I < J) {9787        auto ShAmt = MIRBuilder.buildConstant(SrcTy, J - I);9788        Tmp2 = MIRBuilder.buildShl(SrcTy, Src, ShAmt);9789      } else {9790        auto ShAmt = MIRBuilder.buildConstant(SrcTy, I - J);9791        Tmp2 = MIRBuilder.buildLShr(SrcTy, Src, ShAmt);9792      }9793 9794      auto Mask = MIRBuilder.buildConstant(SrcTy, 1ULL << J);9795      Tmp2 = MIRBuilder.buildAnd(SrcTy, Tmp2, Mask);9796      if (I == 0)9797        Tmp = Tmp2;9798      else9799        Tmp = MIRBuilder.buildOr(SrcTy, Tmp, Tmp2);9800    }9801    MIRBuilder.buildCopy(Dst, Tmp);9802  }9803 9804  MI.eraseFromParent();9805  return Legalized;9806}9807 9808LegalizerHelper::LegalizeResult9809LegalizerHelper::lowerReadWriteRegister(MachineInstr &MI) {9810  MachineFunction &MF = MIRBuilder.getMF();9811 9812  bool IsRead = MI.getOpcode() == TargetOpcode::G_READ_REGISTER;9813  int NameOpIdx = IsRead ? 1 : 0;9814  int ValRegIndex = IsRead ? 0 : 1;9815 9816  Register ValReg = MI.getOperand(ValRegIndex).getReg();9817  const LLT Ty = MRI.getType(ValReg);9818  const MDString *RegStr = cast<MDString>(9819    cast<MDNode>(MI.getOperand(NameOpIdx).getMetadata())->getOperand(0));9820 9821  Register PhysReg = TLI.getRegisterByName(RegStr->getString().data(), Ty, MF);9822  if (!PhysReg) {9823    const Function &Fn = MF.getFunction();9824    Fn.getContext().diagnose(DiagnosticInfoGenericWithLoc(9825        "invalid register \"" + Twine(RegStr->getString().data()) + "\" for " +9826            (IsRead ? "llvm.read_register" : "llvm.write_register"),9827        Fn, MI.getDebugLoc()));9828    if (IsRead)9829      MIRBuilder.buildUndef(ValReg);9830 9831    MI.eraseFromParent();9832    return Legalized;9833  }9834 9835  if (IsRead)9836    MIRBuilder.buildCopy(ValReg, PhysReg);9837  else9838    MIRBuilder.buildCopy(PhysReg, ValReg);9839 9840  MI.eraseFromParent();9841  return Legalized;9842}9843 9844LegalizerHelper::LegalizeResult9845LegalizerHelper::lowerSMULH_UMULH(MachineInstr &MI) {9846  bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULH;9847  unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;9848  Register Result = MI.getOperand(0).getReg();9849  LLT OrigTy = MRI.getType(Result);9850  auto SizeInBits = OrigTy.getScalarSizeInBits();9851  LLT WideTy = OrigTy.changeElementSize(SizeInBits * 2);9852 9853  auto LHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(1)});9854  auto RHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(2)});9855  auto Mul = MIRBuilder.buildMul(WideTy, LHS, RHS);9856  unsigned ShiftOp = IsSigned ? TargetOpcode::G_ASHR : TargetOpcode::G_LSHR;9857 9858  auto ShiftAmt = MIRBuilder.buildConstant(WideTy, SizeInBits);9859  auto Shifted = MIRBuilder.buildInstr(ShiftOp, {WideTy}, {Mul, ShiftAmt});9860  MIRBuilder.buildTrunc(Result, Shifted);9861 9862  MI.eraseFromParent();9863  return Legalized;9864}9865 9866LegalizerHelper::LegalizeResult9867LegalizerHelper::lowerISFPCLASS(MachineInstr &MI) {9868  auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();9869  FPClassTest Mask = static_cast<FPClassTest>(MI.getOperand(2).getImm());9870 9871  if (Mask == fcNone) {9872    MIRBuilder.buildConstant(DstReg, 0);9873    MI.eraseFromParent();9874    return Legalized;9875  }9876  if (Mask == fcAllFlags) {9877    MIRBuilder.buildConstant(DstReg, 1);9878    MI.eraseFromParent();9879    return Legalized;9880  }9881 9882  // TODO: Try inverting the test with getInvertedFPClassTest like the DAG9883  // version9884 9885  unsigned BitSize = SrcTy.getScalarSizeInBits();9886  const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());9887 9888  LLT IntTy = LLT::scalar(BitSize);9889  if (SrcTy.isVector())9890    IntTy = LLT::vector(SrcTy.getElementCount(), IntTy);9891  auto AsInt = MIRBuilder.buildCopy(IntTy, SrcReg);9892 9893  // Various masks.9894  APInt SignBit = APInt::getSignMask(BitSize);9895  APInt ValueMask = APInt::getSignedMaxValue(BitSize);     // All bits but sign.9896  APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit.9897  APInt ExpMask = Inf;9898  APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;9899  APInt QNaNBitMask =9900      APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);9901  APInt InversionMask = APInt::getAllOnes(DstTy.getScalarSizeInBits());9902 9903  auto SignBitC = MIRBuilder.buildConstant(IntTy, SignBit);9904  auto ValueMaskC = MIRBuilder.buildConstant(IntTy, ValueMask);9905  auto InfC = MIRBuilder.buildConstant(IntTy, Inf);9906  auto ExpMaskC = MIRBuilder.buildConstant(IntTy, ExpMask);9907  auto ZeroC = MIRBuilder.buildConstant(IntTy, 0);9908 9909  auto Abs = MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC);9910  auto Sign =9911      MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, AsInt, Abs);9912 9913  auto Res = MIRBuilder.buildConstant(DstTy, 0);9914  // Clang doesn't support capture of structured bindings:9915  LLT DstTyCopy = DstTy;9916  const auto appendToRes = [&](MachineInstrBuilder ToAppend) {9917    Res = MIRBuilder.buildOr(DstTyCopy, Res, ToAppend);9918  };9919 9920  // Tests that involve more than one class should be processed first.9921  if ((Mask & fcFinite) == fcFinite) {9922    // finite(V) ==> abs(V) u< exp_mask9923    appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,9924                                     ExpMaskC));9925    Mask &= ~fcFinite;9926  } else if ((Mask & fcFinite) == fcPosFinite) {9927    // finite(V) && V > 0 ==> V u< exp_mask9928    appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, AsInt,9929                                     ExpMaskC));9930    Mask &= ~fcPosFinite;9931  } else if ((Mask & fcFinite) == fcNegFinite) {9932    // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 19933    auto Cmp = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,9934                                    ExpMaskC);9935    auto And = MIRBuilder.buildAnd(DstTy, Cmp, Sign);9936    appendToRes(And);9937    Mask &= ~fcNegFinite;9938  }9939 9940  if (FPClassTest PartialCheck = Mask & (fcZero | fcSubnormal)) {9941    // fcZero | fcSubnormal => test all exponent bits are 09942    // TODO: Handle sign bit specific cases9943    // TODO: Handle inverted case9944    if (PartialCheck == (fcZero | fcSubnormal)) {9945      auto ExpBits = MIRBuilder.buildAnd(IntTy, AsInt, ExpMaskC);9946      appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,9947                                       ExpBits, ZeroC));9948      Mask &= ~PartialCheck;9949    }9950  }9951 9952  // Check for individual classes.9953  if (FPClassTest PartialCheck = Mask & fcZero) {9954    if (PartialCheck == fcPosZero)9955      appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,9956                                       AsInt, ZeroC));9957    else if (PartialCheck == fcZero)9958      appendToRes(9959          MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, ZeroC));9960    else // fcNegZero9961      appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,9962                                       AsInt, SignBitC));9963  }9964 9965  if (FPClassTest PartialCheck = Mask & fcSubnormal) {9966    // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set)9967    // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set)9968    auto V = (PartialCheck == fcPosSubnormal) ? AsInt : Abs;9969    auto OneC = MIRBuilder.buildConstant(IntTy, 1);9970    auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC);9971    auto SubnormalRes =9972        MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, VMinusOne,9973                             MIRBuilder.buildConstant(IntTy, AllOneMantissa));9974    if (PartialCheck == fcNegSubnormal)9975      SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign);9976    appendToRes(SubnormalRes);9977  }9978 9979  if (FPClassTest PartialCheck = Mask & fcInf) {9980    if (PartialCheck == fcPosInf)9981      appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,9982                                       AsInt, InfC));9983    else if (PartialCheck == fcInf)9984      appendToRes(9985          MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, InfC));9986    else { // fcNegInf9987      APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();9988      auto NegInfC = MIRBuilder.buildConstant(IntTy, NegInf);9989      appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,9990                                       AsInt, NegInfC));9991    }9992  }9993 9994  if (FPClassTest PartialCheck = Mask & fcNan) {9995    auto InfWithQnanBitC = MIRBuilder.buildConstant(IntTy, Inf | QNaNBitMask);9996    if (PartialCheck == fcNan) {9997      // isnan(V) ==> abs(V) u> int(inf)9998      appendToRes(9999          MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));10000    } else if (PartialCheck == fcQNan) {10001      // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit)10002      appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, Abs,10003                                       InfWithQnanBitC));10004    } else { // fcSNan10005      // issignaling(V) ==> abs(V) u> unsigned(Inf) &&10006      //                    abs(V) u< (unsigned(Inf) | quiet_bit)10007      auto IsNan =10008          MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC);10009      auto IsNotQnan = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy,10010                                            Abs, InfWithQnanBitC);10011      appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan));10012    }10013  }10014 10015  if (FPClassTest PartialCheck = Mask & fcNormal) {10016    // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u<10017    // (max_exp-1))10018    APInt ExpLSB = ExpMask & ~(ExpMask.shl(1));10019    auto ExpMinusOne = MIRBuilder.buildSub(10020        IntTy, Abs, MIRBuilder.buildConstant(IntTy, ExpLSB));10021    APInt MaxExpMinusOne = ExpMask - ExpLSB;10022    auto NormalRes =10023        MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, ExpMinusOne,10024                             MIRBuilder.buildConstant(IntTy, MaxExpMinusOne));10025    if (PartialCheck == fcNegNormal)10026      NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign);10027    else if (PartialCheck == fcPosNormal) {10028      auto PosSign = MIRBuilder.buildXor(10029          DstTy, Sign, MIRBuilder.buildConstant(DstTy, InversionMask));10030      NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign);10031    }10032    appendToRes(NormalRes);10033  }10034 10035  MIRBuilder.buildCopy(DstReg, Res);10036  MI.eraseFromParent();10037  return Legalized;10038}10039 10040LegalizerHelper::LegalizeResult LegalizerHelper::lowerSelect(MachineInstr &MI) {10041  // Implement G_SELECT in terms of XOR, AND, OR.10042  auto [DstReg, DstTy, MaskReg, MaskTy, Op1Reg, Op1Ty, Op2Reg, Op2Ty] =10043      MI.getFirst4RegLLTs();10044 10045  bool IsEltPtr = DstTy.isPointerOrPointerVector();10046  if (IsEltPtr) {10047    LLT ScalarPtrTy = LLT::scalar(DstTy.getScalarSizeInBits());10048    LLT NewTy = DstTy.changeElementType(ScalarPtrTy);10049    Op1Reg = MIRBuilder.buildPtrToInt(NewTy, Op1Reg).getReg(0);10050    Op2Reg = MIRBuilder.buildPtrToInt(NewTy, Op2Reg).getReg(0);10051    DstTy = NewTy;10052  }10053 10054  if (MaskTy.isScalar()) {10055    // Turn the scalar condition into a vector condition mask if needed.10056 10057    Register MaskElt = MaskReg;10058 10059    // The condition was potentially zero extended before, but we want a sign10060    // extended boolean.10061    if (MaskTy != LLT::scalar(1))10062      MaskElt = MIRBuilder.buildSExtInReg(MaskTy, MaskElt, 1).getReg(0);10063 10064    // Continue the sign extension (or truncate) to match the data type.10065    MaskElt =10066        MIRBuilder.buildSExtOrTrunc(DstTy.getScalarType(), MaskElt).getReg(0);10067 10068    if (DstTy.isVector()) {10069      // Generate a vector splat idiom.10070      auto ShufSplat = MIRBuilder.buildShuffleSplat(DstTy, MaskElt);10071      MaskReg = ShufSplat.getReg(0);10072    } else {10073      MaskReg = MaskElt;10074    }10075    MaskTy = DstTy;10076  } else if (!DstTy.isVector()) {10077    // Cannot handle the case that mask is a vector and dst is a scalar.10078    return UnableToLegalize;10079  }10080 10081  if (MaskTy.getSizeInBits() != DstTy.getSizeInBits()) {10082    return UnableToLegalize;10083  }10084 10085  auto NotMask = MIRBuilder.buildNot(MaskTy, MaskReg);10086  auto NewOp1 = MIRBuilder.buildAnd(MaskTy, Op1Reg, MaskReg);10087  auto NewOp2 = MIRBuilder.buildAnd(MaskTy, Op2Reg, NotMask);10088  if (IsEltPtr) {10089    auto Or = MIRBuilder.buildOr(DstTy, NewOp1, NewOp2);10090    MIRBuilder.buildIntToPtr(DstReg, Or);10091  } else {10092    MIRBuilder.buildOr(DstReg, NewOp1, NewOp2);10093  }10094  MI.eraseFromParent();10095  return Legalized;10096}10097 10098LegalizerHelper::LegalizeResult LegalizerHelper::lowerDIVREM(MachineInstr &MI) {10099  // Split DIVREM into individual instructions.10100  unsigned Opcode = MI.getOpcode();10101 10102  MIRBuilder.buildInstr(10103      Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SDIV10104                                        : TargetOpcode::G_UDIV,10105      {MI.getOperand(0).getReg()}, {MI.getOperand(2), MI.getOperand(3)});10106  MIRBuilder.buildInstr(10107      Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SREM10108                                        : TargetOpcode::G_UREM,10109      {MI.getOperand(1).getReg()}, {MI.getOperand(2), MI.getOperand(3)});10110  MI.eraseFromParent();10111  return Legalized;10112}10113 10114LegalizerHelper::LegalizeResult10115LegalizerHelper::lowerAbsToAddXor(MachineInstr &MI) {10116  // Expand %res = G_ABS %a into:10117  // %v1 = G_ASHR %a, scalar_size-110118  // %v2 = G_ADD %a, %v110119  // %res = G_XOR %v2, %v110120  LLT DstTy = MRI.getType(MI.getOperand(0).getReg());10121  Register OpReg = MI.getOperand(1).getReg();10122  auto ShiftAmt =10123      MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - 1);10124  auto Shift = MIRBuilder.buildAShr(DstTy, OpReg, ShiftAmt);10125  auto Add = MIRBuilder.buildAdd(DstTy, OpReg, Shift);10126  MIRBuilder.buildXor(MI.getOperand(0).getReg(), Add, Shift);10127  MI.eraseFromParent();10128  return Legalized;10129}10130 10131LegalizerHelper::LegalizeResult10132LegalizerHelper::lowerAbsToMaxNeg(MachineInstr &MI) {10133  // Expand %res = G_ABS %a into:10134  // %v1 = G_CONSTANT 010135  // %v2 = G_SUB %v1, %a10136  // %res = G_SMAX %a, %v210137  Register SrcReg = MI.getOperand(1).getReg();10138  LLT Ty = MRI.getType(SrcReg);10139  auto Zero = MIRBuilder.buildConstant(Ty, 0);10140  auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg);10141  MIRBuilder.buildSMax(MI.getOperand(0), SrcReg, Sub);10142  MI.eraseFromParent();10143  return Legalized;10144}10145 10146LegalizerHelper::LegalizeResult10147LegalizerHelper::lowerAbsToCNeg(MachineInstr &MI) {10148  Register SrcReg = MI.getOperand(1).getReg();10149  Register DestReg = MI.getOperand(0).getReg();10150  LLT Ty = MRI.getType(SrcReg), IType = LLT::scalar(1);10151  auto Zero = MIRBuilder.buildConstant(Ty, 0).getReg(0);10152  auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg).getReg(0);10153  auto ICmp = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, IType, SrcReg, Zero);10154  MIRBuilder.buildSelect(DestReg, ICmp, SrcReg, Sub);10155  MI.eraseFromParent();10156  return Legalized;10157}10158 10159LegalizerHelper::LegalizeResult10160LegalizerHelper::lowerAbsDiffToSelect(MachineInstr &MI) {10161  assert((MI.getOpcode() == TargetOpcode::G_ABDS ||10162          MI.getOpcode() == TargetOpcode::G_ABDU) &&10163         "Expected G_ABDS or G_ABDU instruction");10164 10165  auto [DstReg, LHS, RHS] = MI.getFirst3Regs();10166  LLT Ty = MRI.getType(LHS);10167 10168  // abds(lhs, rhs) -> select(sgt(lhs,rhs), sub(lhs,rhs), sub(rhs,lhs))10169  // abdu(lhs, rhs) -> select(ugt(lhs,rhs), sub(lhs,rhs), sub(rhs,lhs))10170  Register LHSSub = MIRBuilder.buildSub(Ty, LHS, RHS).getReg(0);10171  Register RHSSub = MIRBuilder.buildSub(Ty, RHS, LHS).getReg(0);10172  CmpInst::Predicate Pred = (MI.getOpcode() == TargetOpcode::G_ABDS)10173                                ? CmpInst::ICMP_SGT10174                                : CmpInst::ICMP_UGT;10175  auto ICmp = MIRBuilder.buildICmp(Pred, LLT::scalar(1), LHS, RHS);10176  MIRBuilder.buildSelect(DstReg, ICmp, LHSSub, RHSSub);10177 10178  MI.eraseFromParent();10179  return Legalized;10180}10181 10182LegalizerHelper::LegalizeResult10183LegalizerHelper::lowerAbsDiffToMinMax(MachineInstr &MI) {10184  assert((MI.getOpcode() == TargetOpcode::G_ABDS ||10185          MI.getOpcode() == TargetOpcode::G_ABDU) &&10186         "Expected G_ABDS or G_ABDU instruction");10187 10188  auto [DstReg, LHS, RHS] = MI.getFirst3Regs();10189  LLT Ty = MRI.getType(LHS);10190 10191  // abds(lhs, rhs) -→ sub(smax(lhs, rhs), smin(lhs, rhs))10192  // abdu(lhs, rhs) -→ sub(umax(lhs, rhs), umin(lhs, rhs))10193  Register MaxReg, MinReg;10194  if (MI.getOpcode() == TargetOpcode::G_ABDS) {10195    MaxReg = MIRBuilder.buildSMax(Ty, LHS, RHS).getReg(0);10196    MinReg = MIRBuilder.buildSMin(Ty, LHS, RHS).getReg(0);10197  } else {10198    MaxReg = MIRBuilder.buildUMax(Ty, LHS, RHS).getReg(0);10199    MinReg = MIRBuilder.buildUMin(Ty, LHS, RHS).getReg(0);10200  }10201  MIRBuilder.buildSub(DstReg, MaxReg, MinReg);10202 10203  MI.eraseFromParent();10204  return Legalized;10205}10206 10207LegalizerHelper::LegalizeResult LegalizerHelper::lowerFAbs(MachineInstr &MI) {10208  Register SrcReg = MI.getOperand(1).getReg();10209  Register DstReg = MI.getOperand(0).getReg();10210 10211  LLT Ty = MRI.getType(DstReg);10212 10213  // Reset sign bit10214  MIRBuilder.buildAnd(10215      DstReg, SrcReg,10216      MIRBuilder.buildConstant(10217          Ty, APInt::getSignedMaxValue(Ty.getScalarSizeInBits())));10218 10219  MI.eraseFromParent();10220  return Legalized;10221}10222 10223LegalizerHelper::LegalizeResult10224LegalizerHelper::lowerVectorReduction(MachineInstr &MI) {10225  Register SrcReg = MI.getOperand(1).getReg();10226  LLT SrcTy = MRI.getType(SrcReg);10227  LLT DstTy = MRI.getType(SrcReg);10228 10229  // The source could be a scalar if the IR type was <1 x sN>.10230  if (SrcTy.isScalar()) {10231    if (DstTy.getSizeInBits() > SrcTy.getSizeInBits())10232      return UnableToLegalize; // FIXME: handle extension.10233    // This can be just a plain copy.10234    Observer.changingInstr(MI);10235    MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::COPY));10236    Observer.changedInstr(MI);10237    return Legalized;10238  }10239  return UnableToLegalize;10240}10241 10242LegalizerHelper::LegalizeResult LegalizerHelper::lowerVAArg(MachineInstr &MI) {10243  MachineFunction &MF = *MI.getMF();10244  const DataLayout &DL = MIRBuilder.getDataLayout();10245  LLVMContext &Ctx = MF.getFunction().getContext();10246  Register ListPtr = MI.getOperand(1).getReg();10247  LLT PtrTy = MRI.getType(ListPtr);10248 10249  // LstPtr is a pointer to the head of the list. Get the address10250  // of the head of the list.10251  Align PtrAlignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));10252  MachineMemOperand *PtrLoadMMO = MF.getMachineMemOperand(10253      MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, PtrAlignment);10254  auto VAList = MIRBuilder.buildLoad(PtrTy, ListPtr, *PtrLoadMMO).getReg(0);10255 10256  const Align A(MI.getOperand(2).getImm());10257  LLT PtrTyAsScalarTy = LLT::scalar(PtrTy.getSizeInBits());10258  if (A > TLI.getMinStackArgumentAlignment()) {10259    Register AlignAmt =10260        MIRBuilder.buildConstant(PtrTyAsScalarTy, A.value() - 1).getReg(0);10261    auto AddDst = MIRBuilder.buildPtrAdd(PtrTy, VAList, AlignAmt);10262    auto AndDst = MIRBuilder.buildMaskLowPtrBits(PtrTy, AddDst, Log2(A));10263    VAList = AndDst.getReg(0);10264  }10265 10266  // Increment the pointer, VAList, to the next vaarg10267  // The list should be bumped by the size of element in the current head of10268  // list.10269  Register Dst = MI.getOperand(0).getReg();10270  LLT LLTTy = MRI.getType(Dst);10271  Type *Ty = getTypeForLLT(LLTTy, Ctx);10272  auto IncAmt =10273      MIRBuilder.buildConstant(PtrTyAsScalarTy, DL.getTypeAllocSize(Ty));10274  auto Succ = MIRBuilder.buildPtrAdd(PtrTy, VAList, IncAmt);10275 10276  // Store the increment VAList to the legalized pointer10277  MachineMemOperand *StoreMMO = MF.getMachineMemOperand(10278      MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, PtrAlignment);10279  MIRBuilder.buildStore(Succ, ListPtr, *StoreMMO);10280  // Load the actual argument out of the pointer VAList10281  Align EltAlignment = DL.getABITypeAlign(Ty);10282  MachineMemOperand *EltLoadMMO = MF.getMachineMemOperand(10283      MachinePointerInfo(), MachineMemOperand::MOLoad, LLTTy, EltAlignment);10284  MIRBuilder.buildLoad(Dst, VAList, *EltLoadMMO);10285 10286  MI.eraseFromParent();10287  return Legalized;10288}10289 10290static bool shouldLowerMemFuncForSize(const MachineFunction &MF) {10291  // On Darwin, -Os means optimize for size without hurting performance, so10292  // only really optimize for size when -Oz (MinSize) is used.10293  if (MF.getTarget().getTargetTriple().isOSDarwin())10294    return MF.getFunction().hasMinSize();10295  return MF.getFunction().hasOptSize();10296}10297 10298// Returns a list of types to use for memory op lowering in MemOps. A partial10299// port of findOptimalMemOpLowering in TargetLowering.10300static bool findGISelOptimalMemOpLowering(std::vector<LLT> &MemOps,10301                                          unsigned Limit, const MemOp &Op,10302                                          unsigned DstAS, unsigned SrcAS,10303                                          const AttributeList &FuncAttributes,10304                                          const TargetLowering &TLI) {10305  if (Op.isMemcpyWithFixedDstAlign() && Op.getSrcAlign() < Op.getDstAlign())10306    return false;10307 10308  LLT Ty = TLI.getOptimalMemOpLLT(Op, FuncAttributes);10309 10310  if (Ty == LLT()) {10311    // Use the largest scalar type whose alignment constraints are satisfied.10312    // We only need to check DstAlign here as SrcAlign is always greater or10313    // equal to DstAlign (or zero).10314    Ty = LLT::scalar(64);10315    if (Op.isFixedDstAlign())10316      while (Op.getDstAlign() < Ty.getSizeInBytes() &&10317             !TLI.allowsMisalignedMemoryAccesses(Ty, DstAS, Op.getDstAlign()))10318        Ty = LLT::scalar(Ty.getSizeInBytes());10319    assert(Ty.getSizeInBits() > 0 && "Could not find valid type");10320    // FIXME: check for the largest legal type we can load/store to.10321  }10322 10323  unsigned NumMemOps = 0;10324  uint64_t Size = Op.size();10325  while (Size) {10326    unsigned TySize = Ty.getSizeInBytes();10327    while (TySize > Size) {10328      // For now, only use non-vector load / store's for the left-over pieces.10329      LLT NewTy = Ty;10330      // FIXME: check for mem op safety and legality of the types. Not all of10331      // SDAGisms map cleanly to GISel concepts.10332      if (NewTy.isVector())10333        NewTy = NewTy.getSizeInBits() > 64 ? LLT::scalar(64) : LLT::scalar(32);10334      NewTy = LLT::scalar(llvm::bit_floor(NewTy.getSizeInBits() - 1));10335      unsigned NewTySize = NewTy.getSizeInBytes();10336      assert(NewTySize > 0 && "Could not find appropriate type");10337 10338      // If the new LLT cannot cover all of the remaining bits, then consider10339      // issuing a (or a pair of) unaligned and overlapping load / store.10340      unsigned Fast;10341      // Need to get a VT equivalent for allowMisalignedMemoryAccesses().10342      MVT VT = getMVTForLLT(Ty);10343      if (NumMemOps && Op.allowOverlap() && NewTySize < Size &&10344          TLI.allowsMisalignedMemoryAccesses(10345              VT, DstAS, Op.isFixedDstAlign() ? Op.getDstAlign() : Align(1),10346              MachineMemOperand::MONone, &Fast) &&10347          Fast)10348        TySize = Size;10349      else {10350        Ty = NewTy;10351        TySize = NewTySize;10352      }10353    }10354 10355    if (++NumMemOps > Limit)10356      return false;10357 10358    MemOps.push_back(Ty);10359    Size -= TySize;10360  }10361 10362  return true;10363}10364 10365// Get a vectorized representation of the memset value operand, GISel edition.10366static Register getMemsetValue(Register Val, LLT Ty, MachineIRBuilder &MIB) {10367  MachineRegisterInfo &MRI = *MIB.getMRI();10368  unsigned NumBits = Ty.getScalarSizeInBits();10369  auto ValVRegAndVal = getIConstantVRegValWithLookThrough(Val, MRI);10370  if (!Ty.isVector() && ValVRegAndVal) {10371    APInt Scalar = ValVRegAndVal->Value.trunc(8);10372    APInt SplatVal = APInt::getSplat(NumBits, Scalar);10373    return MIB.buildConstant(Ty, SplatVal).getReg(0);10374  }10375 10376  // Extend the byte value to the larger type, and then multiply by a magic10377  // value 0x010101... in order to replicate it across every byte.10378  // Unless it's zero, in which case just emit a larger G_CONSTANT 0.10379  if (ValVRegAndVal && ValVRegAndVal->Value == 0) {10380    return MIB.buildConstant(Ty, 0).getReg(0);10381  }10382 10383  LLT ExtType = Ty.getScalarType();10384  auto ZExt = MIB.buildZExtOrTrunc(ExtType, Val);10385  if (NumBits > 8) {10386    APInt Magic = APInt::getSplat(NumBits, APInt(8, 0x01));10387    auto MagicMI = MIB.buildConstant(ExtType, Magic);10388    Val = MIB.buildMul(ExtType, ZExt, MagicMI).getReg(0);10389  }10390 10391  // For vector types create a G_BUILD_VECTOR.10392  if (Ty.isVector())10393    Val = MIB.buildSplatBuildVector(Ty, Val).getReg(0);10394 10395  return Val;10396}10397 10398LegalizerHelper::LegalizeResult10399LegalizerHelper::lowerMemset(MachineInstr &MI, Register Dst, Register Val,10400                             uint64_t KnownLen, Align Alignment,10401                             bool IsVolatile) {10402  auto &MF = *MI.getParent()->getParent();10403  const auto &TLI = *MF.getSubtarget().getTargetLowering();10404  auto &DL = MF.getDataLayout();10405  LLVMContext &C = MF.getFunction().getContext();10406 10407  assert(KnownLen != 0 && "Have a zero length memset length!");10408 10409  bool DstAlignCanChange = false;10410  MachineFrameInfo &MFI = MF.getFrameInfo();10411  bool OptSize = shouldLowerMemFuncForSize(MF);10412 10413  MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);10414  if (FIDef && !MFI.isFixedObjectIndex(FIDef->getOperand(1).getIndex()))10415    DstAlignCanChange = true;10416 10417  unsigned Limit = TLI.getMaxStoresPerMemset(OptSize);10418  std::vector<LLT> MemOps;10419 10420  const auto &DstMMO = **MI.memoperands_begin();10421  MachinePointerInfo DstPtrInfo = DstMMO.getPointerInfo();10422 10423  auto ValVRegAndVal = getIConstantVRegValWithLookThrough(Val, MRI);10424  bool IsZeroVal = ValVRegAndVal && ValVRegAndVal->Value == 0;10425 10426  if (!findGISelOptimalMemOpLowering(MemOps, Limit,10427                                     MemOp::Set(KnownLen, DstAlignCanChange,10428                                                Alignment,10429                                                /*IsZeroMemset=*/IsZeroVal,10430                                                /*IsVolatile=*/IsVolatile),10431                                     DstPtrInfo.getAddrSpace(), ~0u,10432                                     MF.getFunction().getAttributes(), TLI))10433    return UnableToLegalize;10434 10435  if (DstAlignCanChange) {10436    // Get an estimate of the type from the LLT.10437    Type *IRTy = getTypeForLLT(MemOps[0], C);10438    Align NewAlign = DL.getABITypeAlign(IRTy);10439    if (NewAlign > Alignment) {10440      Alignment = NewAlign;10441      unsigned FI = FIDef->getOperand(1).getIndex();10442      // Give the stack frame object a larger alignment if needed.10443      if (MFI.getObjectAlign(FI) < Alignment)10444        MFI.setObjectAlignment(FI, Alignment);10445    }10446  }10447 10448  MachineIRBuilder MIB(MI);10449  // Find the largest store and generate the bit pattern for it.10450  LLT LargestTy = MemOps[0];10451  for (unsigned i = 1; i < MemOps.size(); i++)10452    if (MemOps[i].getSizeInBits() > LargestTy.getSizeInBits())10453      LargestTy = MemOps[i];10454 10455  // The memset stored value is always defined as an s8, so in order to make it10456  // work with larger store types we need to repeat the bit pattern across the10457  // wider type.10458  Register MemSetValue = getMemsetValue(Val, LargestTy, MIB);10459 10460  if (!MemSetValue)10461    return UnableToLegalize;10462 10463  // Generate the stores. For each store type in the list, we generate the10464  // matching store of that type to the destination address.10465  LLT PtrTy = MRI.getType(Dst);10466  unsigned DstOff = 0;10467  unsigned Size = KnownLen;10468  for (unsigned I = 0; I < MemOps.size(); I++) {10469    LLT Ty = MemOps[I];10470    unsigned TySize = Ty.getSizeInBytes();10471    if (TySize > Size) {10472      // Issuing an unaligned load / store pair that overlaps with the previous10473      // pair. Adjust the offset accordingly.10474      assert(I == MemOps.size() - 1 && I != 0);10475      DstOff -= TySize - Size;10476    }10477 10478    // If this store is smaller than the largest store see whether we can get10479    // the smaller value for free with a truncate.10480    Register Value = MemSetValue;10481    if (Ty.getSizeInBits() < LargestTy.getSizeInBits()) {10482      MVT VT = getMVTForLLT(Ty);10483      MVT LargestVT = getMVTForLLT(LargestTy);10484      if (!LargestTy.isVector() && !Ty.isVector() &&10485          TLI.isTruncateFree(LargestVT, VT))10486        Value = MIB.buildTrunc(Ty, MemSetValue).getReg(0);10487      else10488        Value = getMemsetValue(Val, Ty, MIB);10489      if (!Value)10490        return UnableToLegalize;10491    }10492 10493    auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, DstOff, Ty);10494 10495    Register Ptr = Dst;10496    if (DstOff != 0) {10497      auto Offset =10498          MIB.buildConstant(LLT::scalar(PtrTy.getSizeInBits()), DstOff);10499      Ptr = MIB.buildObjectPtrOffset(PtrTy, Dst, Offset).getReg(0);10500    }10501 10502    MIB.buildStore(Value, Ptr, *StoreMMO);10503    DstOff += Ty.getSizeInBytes();10504    Size -= TySize;10505  }10506 10507  MI.eraseFromParent();10508  return Legalized;10509}10510 10511LegalizerHelper::LegalizeResult10512LegalizerHelper::lowerMemcpyInline(MachineInstr &MI) {10513  assert(MI.getOpcode() == TargetOpcode::G_MEMCPY_INLINE);10514 10515  auto [Dst, Src, Len] = MI.getFirst3Regs();10516 10517  const auto *MMOIt = MI.memoperands_begin();10518  const MachineMemOperand *MemOp = *MMOIt;10519  bool IsVolatile = MemOp->isVolatile();10520 10521  // See if this is a constant length copy10522  auto LenVRegAndVal = getIConstantVRegValWithLookThrough(Len, MRI);10523  // FIXME: support dynamically sized G_MEMCPY_INLINE10524  assert(LenVRegAndVal &&10525         "inline memcpy with dynamic size is not yet supported");10526  uint64_t KnownLen = LenVRegAndVal->Value.getZExtValue();10527  if (KnownLen == 0) {10528    MI.eraseFromParent();10529    return Legalized;10530  }10531 10532  const auto &DstMMO = **MI.memoperands_begin();10533  const auto &SrcMMO = **std::next(MI.memoperands_begin());10534  Align DstAlign = DstMMO.getBaseAlign();10535  Align SrcAlign = SrcMMO.getBaseAlign();10536 10537  return lowerMemcpyInline(MI, Dst, Src, KnownLen, DstAlign, SrcAlign,10538                           IsVolatile);10539}10540 10541LegalizerHelper::LegalizeResult10542LegalizerHelper::lowerMemcpyInline(MachineInstr &MI, Register Dst, Register Src,10543                                   uint64_t KnownLen, Align DstAlign,10544                                   Align SrcAlign, bool IsVolatile) {10545  assert(MI.getOpcode() == TargetOpcode::G_MEMCPY_INLINE);10546  return lowerMemcpy(MI, Dst, Src, KnownLen,10547                     std::numeric_limits<uint64_t>::max(), DstAlign, SrcAlign,10548                     IsVolatile);10549}10550 10551LegalizerHelper::LegalizeResult10552LegalizerHelper::lowerMemcpy(MachineInstr &MI, Register Dst, Register Src,10553                             uint64_t KnownLen, uint64_t Limit, Align DstAlign,10554                             Align SrcAlign, bool IsVolatile) {10555  auto &MF = *MI.getParent()->getParent();10556  const auto &TLI = *MF.getSubtarget().getTargetLowering();10557  auto &DL = MF.getDataLayout();10558  LLVMContext &C = MF.getFunction().getContext();10559 10560  assert(KnownLen != 0 && "Have a zero length memcpy length!");10561 10562  bool DstAlignCanChange = false;10563  MachineFrameInfo &MFI = MF.getFrameInfo();10564  Align Alignment = std::min(DstAlign, SrcAlign);10565 10566  MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);10567  if (FIDef && !MFI.isFixedObjectIndex(FIDef->getOperand(1).getIndex()))10568    DstAlignCanChange = true;10569 10570  // FIXME: infer better src pointer alignment like SelectionDAG does here.10571  // FIXME: also use the equivalent of isMemSrcFromConstant and alwaysinlining10572  // if the memcpy is in a tail call position.10573 10574  std::vector<LLT> MemOps;10575 10576  const auto &DstMMO = **MI.memoperands_begin();10577  const auto &SrcMMO = **std::next(MI.memoperands_begin());10578  MachinePointerInfo DstPtrInfo = DstMMO.getPointerInfo();10579  MachinePointerInfo SrcPtrInfo = SrcMMO.getPointerInfo();10580 10581  if (!findGISelOptimalMemOpLowering(10582          MemOps, Limit,10583          MemOp::Copy(KnownLen, DstAlignCanChange, Alignment, SrcAlign,10584                      IsVolatile),10585          DstPtrInfo.getAddrSpace(), SrcPtrInfo.getAddrSpace(),10586          MF.getFunction().getAttributes(), TLI))10587    return UnableToLegalize;10588 10589  if (DstAlignCanChange) {10590    // Get an estimate of the type from the LLT.10591    Type *IRTy = getTypeForLLT(MemOps[0], C);10592    Align NewAlign = DL.getABITypeAlign(IRTy);10593 10594    // Don't promote to an alignment that would require dynamic stack10595    // realignment.10596    const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();10597    if (!TRI->hasStackRealignment(MF))10598      if (MaybeAlign StackAlign = DL.getStackAlignment())10599        NewAlign = std::min(NewAlign, *StackAlign);10600 10601    if (NewAlign > Alignment) {10602      Alignment = NewAlign;10603      unsigned FI = FIDef->getOperand(1).getIndex();10604      // Give the stack frame object a larger alignment if needed.10605      if (MFI.getObjectAlign(FI) < Alignment)10606        MFI.setObjectAlignment(FI, Alignment);10607    }10608  }10609 10610  LLVM_DEBUG(dbgs() << "Inlining memcpy: " << MI << " into loads & stores\n");10611 10612  MachineIRBuilder MIB(MI);10613  // Now we need to emit a pair of load and stores for each of the types we've10614  // collected. I.e. for each type, generate a load from the source pointer of10615  // that type width, and then generate a corresponding store to the dest buffer10616  // of that value loaded. This can result in a sequence of loads and stores10617  // mixed types, depending on what the target specifies as good types to use.10618  unsigned CurrOffset = 0;10619  unsigned Size = KnownLen;10620  for (auto CopyTy : MemOps) {10621    // Issuing an unaligned load / store pair  that overlaps with the previous10622    // pair. Adjust the offset accordingly.10623    if (CopyTy.getSizeInBytes() > Size)10624      CurrOffset -= CopyTy.getSizeInBytes() - Size;10625 10626    // Construct MMOs for the accesses.10627    auto *LoadMMO =10628        MF.getMachineMemOperand(&SrcMMO, CurrOffset, CopyTy.getSizeInBytes());10629    auto *StoreMMO =10630        MF.getMachineMemOperand(&DstMMO, CurrOffset, CopyTy.getSizeInBytes());10631 10632    // Create the load.10633    Register LoadPtr = Src;10634    Register Offset;10635    if (CurrOffset != 0) {10636      LLT SrcTy = MRI.getType(Src);10637      Offset = MIB.buildConstant(LLT::scalar(SrcTy.getSizeInBits()), CurrOffset)10638                   .getReg(0);10639      LoadPtr = MIB.buildObjectPtrOffset(SrcTy, Src, Offset).getReg(0);10640    }10641    auto LdVal = MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO);10642 10643    // Create the store.10644    Register StorePtr = Dst;10645    if (CurrOffset != 0) {10646      LLT DstTy = MRI.getType(Dst);10647      StorePtr = MIB.buildObjectPtrOffset(DstTy, Dst, Offset).getReg(0);10648    }10649    MIB.buildStore(LdVal, StorePtr, *StoreMMO);10650    CurrOffset += CopyTy.getSizeInBytes();10651    Size -= CopyTy.getSizeInBytes();10652  }10653 10654  MI.eraseFromParent();10655  return Legalized;10656}10657 10658LegalizerHelper::LegalizeResult10659LegalizerHelper::lowerMemmove(MachineInstr &MI, Register Dst, Register Src,10660                              uint64_t KnownLen, Align DstAlign, Align SrcAlign,10661                              bool IsVolatile) {10662  auto &MF = *MI.getParent()->getParent();10663  const auto &TLI = *MF.getSubtarget().getTargetLowering();10664  auto &DL = MF.getDataLayout();10665  LLVMContext &C = MF.getFunction().getContext();10666 10667  assert(KnownLen != 0 && "Have a zero length memmove length!");10668 10669  bool DstAlignCanChange = false;10670  MachineFrameInfo &MFI = MF.getFrameInfo();10671  bool OptSize = shouldLowerMemFuncForSize(MF);10672  Align Alignment = std::min(DstAlign, SrcAlign);10673 10674  MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);10675  if (FIDef && !MFI.isFixedObjectIndex(FIDef->getOperand(1).getIndex()))10676    DstAlignCanChange = true;10677 10678  unsigned Limit = TLI.getMaxStoresPerMemmove(OptSize);10679  std::vector<LLT> MemOps;10680 10681  const auto &DstMMO = **MI.memoperands_begin();10682  const auto &SrcMMO = **std::next(MI.memoperands_begin());10683  MachinePointerInfo DstPtrInfo = DstMMO.getPointerInfo();10684  MachinePointerInfo SrcPtrInfo = SrcMMO.getPointerInfo();10685 10686  // FIXME: SelectionDAG always passes false for 'AllowOverlap', apparently due10687  // to a bug in it's findOptimalMemOpLowering implementation. For now do the10688  // same thing here.10689  if (!findGISelOptimalMemOpLowering(10690          MemOps, Limit,10691          MemOp::Copy(KnownLen, DstAlignCanChange, Alignment, SrcAlign,10692                      /*IsVolatile*/ true),10693          DstPtrInfo.getAddrSpace(), SrcPtrInfo.getAddrSpace(),10694          MF.getFunction().getAttributes(), TLI))10695    return UnableToLegalize;10696 10697  if (DstAlignCanChange) {10698    // Get an estimate of the type from the LLT.10699    Type *IRTy = getTypeForLLT(MemOps[0], C);10700    Align NewAlign = DL.getABITypeAlign(IRTy);10701 10702    // Don't promote to an alignment that would require dynamic stack10703    // realignment.10704    const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();10705    if (!TRI->hasStackRealignment(MF))10706      if (MaybeAlign StackAlign = DL.getStackAlignment())10707        NewAlign = std::min(NewAlign, *StackAlign);10708 10709    if (NewAlign > Alignment) {10710      Alignment = NewAlign;10711      unsigned FI = FIDef->getOperand(1).getIndex();10712      // Give the stack frame object a larger alignment if needed.10713      if (MFI.getObjectAlign(FI) < Alignment)10714        MFI.setObjectAlignment(FI, Alignment);10715    }10716  }10717 10718  LLVM_DEBUG(dbgs() << "Inlining memmove: " << MI << " into loads & stores\n");10719 10720  MachineIRBuilder MIB(MI);10721  // Memmove requires that we perform the loads first before issuing the stores.10722  // Apart from that, this loop is pretty much doing the same thing as the10723  // memcpy codegen function.10724  unsigned CurrOffset = 0;10725  SmallVector<Register, 16> LoadVals;10726  for (auto CopyTy : MemOps) {10727    // Construct MMO for the load.10728    auto *LoadMMO =10729        MF.getMachineMemOperand(&SrcMMO, CurrOffset, CopyTy.getSizeInBytes());10730 10731    // Create the load.10732    Register LoadPtr = Src;10733    if (CurrOffset != 0) {10734      LLT SrcTy = MRI.getType(Src);10735      auto Offset =10736          MIB.buildConstant(LLT::scalar(SrcTy.getSizeInBits()), CurrOffset);10737      LoadPtr = MIB.buildObjectPtrOffset(SrcTy, Src, Offset).getReg(0);10738    }10739    LoadVals.push_back(MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO).getReg(0));10740    CurrOffset += CopyTy.getSizeInBytes();10741  }10742 10743  CurrOffset = 0;10744  for (unsigned I = 0; I < MemOps.size(); ++I) {10745    LLT CopyTy = MemOps[I];10746    // Now store the values loaded.10747    auto *StoreMMO =10748        MF.getMachineMemOperand(&DstMMO, CurrOffset, CopyTy.getSizeInBytes());10749 10750    Register StorePtr = Dst;10751    if (CurrOffset != 0) {10752      LLT DstTy = MRI.getType(Dst);10753      auto Offset =10754          MIB.buildConstant(LLT::scalar(DstTy.getSizeInBits()), CurrOffset);10755      StorePtr = MIB.buildObjectPtrOffset(DstTy, Dst, Offset).getReg(0);10756    }10757    MIB.buildStore(LoadVals[I], StorePtr, *StoreMMO);10758    CurrOffset += CopyTy.getSizeInBytes();10759  }10760  MI.eraseFromParent();10761  return Legalized;10762}10763 10764LegalizerHelper::LegalizeResult10765LegalizerHelper::lowerMemCpyFamily(MachineInstr &MI, unsigned MaxLen) {10766  const unsigned Opc = MI.getOpcode();10767  // This combine is fairly complex so it's not written with a separate10768  // matcher function.10769  assert((Opc == TargetOpcode::G_MEMCPY || Opc == TargetOpcode::G_MEMMOVE ||10770          Opc == TargetOpcode::G_MEMSET) &&10771         "Expected memcpy like instruction");10772 10773  auto MMOIt = MI.memoperands_begin();10774  const MachineMemOperand *MemOp = *MMOIt;10775 10776  Align DstAlign = MemOp->getBaseAlign();10777  Align SrcAlign;10778  auto [Dst, Src, Len] = MI.getFirst3Regs();10779 10780  if (Opc != TargetOpcode::G_MEMSET) {10781    assert(MMOIt != MI.memoperands_end() && "Expected a second MMO on MI");10782    MemOp = *(++MMOIt);10783    SrcAlign = MemOp->getBaseAlign();10784  }10785 10786  // See if this is a constant length copy10787  auto LenVRegAndVal = getIConstantVRegValWithLookThrough(Len, MRI);10788  if (!LenVRegAndVal)10789    return UnableToLegalize;10790  uint64_t KnownLen = LenVRegAndVal->Value.getZExtValue();10791 10792  if (KnownLen == 0) {10793    MI.eraseFromParent();10794    return Legalized;10795  }10796 10797  if (MaxLen && KnownLen > MaxLen)10798    return UnableToLegalize;10799 10800  bool IsVolatile = MemOp->isVolatile();10801  if (Opc == TargetOpcode::G_MEMCPY) {10802    auto &MF = *MI.getParent()->getParent();10803    const auto &TLI = *MF.getSubtarget().getTargetLowering();10804    bool OptSize = shouldLowerMemFuncForSize(MF);10805    uint64_t Limit = TLI.getMaxStoresPerMemcpy(OptSize);10806    return lowerMemcpy(MI, Dst, Src, KnownLen, Limit, DstAlign, SrcAlign,10807                       IsVolatile);10808  }10809  if (Opc == TargetOpcode::G_MEMMOVE)10810    return lowerMemmove(MI, Dst, Src, KnownLen, DstAlign, SrcAlign, IsVolatile);10811  if (Opc == TargetOpcode::G_MEMSET)10812    return lowerMemset(MI, Dst, Src, KnownLen, DstAlign, IsVolatile);10813  return UnableToLegalize;10814}10815