brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.7 KiB · 442f0a4 Raw
476 lines · cpp
1//=- LoongArchISelDAGToDAG.cpp - A dag to dag inst selector for LoongArch -===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines an instruction selector for the LoongArch target.10//11//===----------------------------------------------------------------------===//12 13#include "LoongArchISelDAGToDAG.h"14#include "LoongArchISelLowering.h"15#include "MCTargetDesc/LoongArchMCTargetDesc.h"16#include "MCTargetDesc/LoongArchMatInt.h"17#include "llvm/Support/KnownBits.h"18#include "llvm/Support/raw_ostream.h"19 20using namespace llvm;21 22#define DEBUG_TYPE "loongarch-isel"23#define PASS_NAME "LoongArch DAG->DAG Pattern Instruction Selection"24 25char LoongArchDAGToDAGISelLegacy::ID;26 27LoongArchDAGToDAGISelLegacy::LoongArchDAGToDAGISelLegacy(28    LoongArchTargetMachine &TM, CodeGenOptLevel OptLevel)29    : SelectionDAGISelLegacy(30          ID, std::make_unique<LoongArchDAGToDAGISel>(TM, OptLevel)) {}31 32INITIALIZE_PASS(LoongArchDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false,33                false)34 35void LoongArchDAGToDAGISel::Select(SDNode *Node) {36  // If we have a custom node, we have already selected.37  if (Node->isMachineOpcode()) {38    LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");39    Node->setNodeId(-1);40    return;41  }42 43  // Instruction Selection not handled by the auto-generated tablegen selection44  // should be handled here.45  unsigned Opcode = Node->getOpcode();46  MVT GRLenVT = Subtarget->getGRLenVT();47  SDLoc DL(Node);48  MVT VT = Node->getSimpleValueType(0);49 50  switch (Opcode) {51  default:52    break;53  case ISD::Constant: {54    int64_t Imm = cast<ConstantSDNode>(Node)->getSExtValue();55    if (Imm == 0 && VT == GRLenVT) {56      SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL,57                                           LoongArch::R0, GRLenVT);58      ReplaceNode(Node, New.getNode());59      return;60    }61    SDNode *Result = nullptr;62    SDValue SrcReg = CurDAG->getRegister(LoongArch::R0, GRLenVT);63    // The instructions in the sequence are handled here.64    for (LoongArchMatInt::Inst &Inst : LoongArchMatInt::generateInstSeq(Imm)) {65      SDValue SDImm = CurDAG->getSignedTargetConstant(Inst.Imm, DL, GRLenVT);66      switch (Inst.Opc) {67      case LoongArch::LU12I_W:68        Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SDImm);69        break;70      case LoongArch::ADDI_W:71      case LoongArch::ORI:72      case LoongArch::LU32I_D:73      case LoongArch::LU52I_D:74        Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SrcReg, SDImm);75        break;76      case LoongArch::BSTRINS_D:77        Result = CurDAG->getMachineNode(78            Inst.Opc, DL, GRLenVT,79            {SrcReg, SrcReg,80             CurDAG->getSignedTargetConstant(Inst.Imm >> 32, DL, GRLenVT),81             CurDAG->getTargetConstant(Inst.Imm & 0xFF, DL, GRLenVT)});82        break;83      default:84        llvm_unreachable("unexpected opcode generated by LoongArchMatInt");85      }86      SrcReg = SDValue(Result, 0);87    }88 89    ReplaceNode(Node, Result);90    return;91  }92  case ISD::FrameIndex: {93    SDValue Imm = CurDAG->getTargetConstant(0, DL, GRLenVT);94    int FI = cast<FrameIndexSDNode>(Node)->getIndex();95    SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);96    unsigned ADDIOp =97        Subtarget->is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;98    ReplaceNode(Node, CurDAG->getMachineNode(ADDIOp, DL, VT, TFI, Imm));99    return;100  }101  case ISD::BITCAST: {102    if (VT.is128BitVector() || VT.is256BitVector()) {103      ReplaceUses(SDValue(Node, 0), Node->getOperand(0));104      CurDAG->RemoveDeadNode(Node);105      return;106    }107    break;108  }109  case ISD::BUILD_VECTOR: {110    // Select appropriate [x]vrepli.[bhwd] instructions for constant splats of111    // 128/256-bit when LSX/LASX is enabled.112    BuildVectorSDNode *BVN = cast<BuildVectorSDNode>(Node);113    APInt SplatValue, SplatUndef;114    unsigned SplatBitSize;115    bool HasAnyUndefs;116    unsigned Op = 0;117    EVT ResTy = BVN->getValueType(0);118    bool Is128Vec = BVN->getValueType(0).is128BitVector();119    bool Is256Vec = BVN->getValueType(0).is256BitVector();120    SDNode *Res;121 122    if (!Subtarget->hasExtLSX() || (!Is128Vec && !Is256Vec))123      break;124    if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,125                              HasAnyUndefs, 8))126      break;127 128    // If we have a signed 10 bit integer, we can splat it directly.129    if (SplatValue.isSignedIntN(10)) {130      switch (SplatBitSize) {131      default:132        break;133      case 8:134        Op = Is256Vec ? LoongArch::PseudoXVREPLI_B : LoongArch::PseudoVREPLI_B;135        break;136      case 16:137        Op = Is256Vec ? LoongArch::PseudoXVREPLI_H : LoongArch::PseudoVREPLI_H;138        break;139      case 32:140        Op = Is256Vec ? LoongArch::PseudoXVREPLI_W : LoongArch::PseudoVREPLI_W;141        break;142      case 64:143        Op = Is256Vec ? LoongArch::PseudoXVREPLI_D : LoongArch::PseudoVREPLI_D;144        break;145      }146 147      EVT EleType = ResTy.getVectorElementType();148      APInt Val = SplatValue.sextOrTrunc(EleType.getSizeInBits());149      SDValue Imm = CurDAG->getTargetConstant(Val, DL, EleType);150      Res = CurDAG->getMachineNode(Op, DL, ResTy, Imm);151      ReplaceNode(Node, Res);152      return;153    }154 155    // Select appropriate [x]vldi instructions for some special constant splats,156    // where the immediate value `imm[12] == 1` for used [x]vldi instructions.157    const auto &TLI =158        *static_cast<const LoongArchTargetLowering *>(getTargetLowering());159    std::pair<bool, uint64_t> ConvertVLDI =160        TLI.isImmVLDILegalForMode1(SplatValue, SplatBitSize);161    if (ConvertVLDI.first) {162      Op = Is256Vec ? LoongArch::XVLDI : LoongArch::VLDI;163      SDValue Imm = CurDAG->getSignedTargetConstant(164          SignExtend32<13>(ConvertVLDI.second), DL, MVT::i32);165      Res = CurDAG->getMachineNode(Op, DL, ResTy, Imm);166      ReplaceNode(Node, Res);167      return;168    }169    break;170  }171  }172 173  // Select the default instruction.174  SelectCode(Node);175}176 177bool LoongArchDAGToDAGISel::SelectInlineAsmMemoryOperand(178    const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,179    std::vector<SDValue> &OutOps) {180  SDValue Base = Op;181  SDValue Offset =182      CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getGRLenVT());183  switch (ConstraintID) {184  default:185    llvm_unreachable("unexpected asm memory constraint");186  // Reg+Reg addressing.187  case InlineAsm::ConstraintCode::k:188    Base = Op.getOperand(0);189    Offset = Op.getOperand(1);190    break;191  // Reg+simm12 addressing.192  case InlineAsm::ConstraintCode::m:193    if (CurDAG->isBaseWithConstantOffset(Op)) {194      ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));195      if (isIntN(12, CN->getSExtValue())) {196        Base = Op.getOperand(0);197        Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op),198                                           Op.getValueType());199      }200    }201    break;202  // Reg+0 addressing.203  case InlineAsm::ConstraintCode::ZB:204    break;205  // Reg+(simm14<<2) addressing.206  case InlineAsm::ConstraintCode::ZC:207    if (CurDAG->isBaseWithConstantOffset(Op)) {208      ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));209      if (isIntN(16, CN->getSExtValue()) &&210          isAligned(Align(4ULL), CN->getZExtValue())) {211        Base = Op.getOperand(0);212        Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op),213                                           Op.getValueType());214      }215    }216    break;217  }218  OutOps.push_back(Base);219  OutOps.push_back(Offset);220  return false;221}222 223bool LoongArchDAGToDAGISel::SelectBaseAddr(SDValue Addr, SDValue &Base) {224  // If this is FrameIndex, select it directly. Otherwise just let it get225  // selected to a register independently.226  if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr))227    Base =228        CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getGRLenVT());229  else230    Base = Addr;231  return true;232}233 234// Fold constant addresses.235bool LoongArchDAGToDAGISel::SelectAddrConstant(SDValue Addr, SDValue &Base,236                                               SDValue &Offset) {237  SDLoc DL(Addr);238  MVT VT = Addr.getSimpleValueType();239 240  if (!isa<ConstantSDNode>(Addr))241    return false;242 243  // If the constant is a simm12, we can fold the whole constant and use R0 as244  // the base.245  int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue();246  if (!isInt<12>(CVal))247    return false;248  Base = CurDAG->getRegister(LoongArch::R0, VT);249  Offset = CurDAG->getSignedTargetConstant(SignExtend64<12>(CVal), DL, VT);250  return true;251}252 253bool LoongArchDAGToDAGISel::selectNonFIBaseAddr(SDValue Addr, SDValue &Base) {254  // If this is FrameIndex, don't select it.255  if (isa<FrameIndexSDNode>(Addr))256    return false;257  Base = Addr;258  return true;259}260 261bool LoongArchDAGToDAGISel::SelectAddrRegImm12(SDValue Addr, SDValue &Base,262                                               SDValue &Offset) {263  SDLoc DL(Addr);264  MVT VT = Addr.getSimpleValueType();265 266  // The address is the result of an ADD. Here we only consider reg+simm12.267  if (CurDAG->isBaseWithConstantOffset(Addr)) {268    int64_t Imm = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue();269    if (isInt<12>(Imm)) {270      Base = Addr.getOperand(0);271      Offset = CurDAG->getSignedTargetConstant(SignExtend64<12>(Imm), DL, VT);272      return true;273    }274  }275 276  // Otherwise, we assume Addr as the base address and use constant 0 as the277  // offset.278  Base = Addr;279  Offset = CurDAG->getTargetConstant(0, DL, VT);280  return true;281}282 283bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,284                                            SDValue &ShAmt) {285  // Shift instructions on LoongArch only read the lower 5 or 6 bits of the286  // shift amount. If there is an AND on the shift amount, we can bypass it if287  // it doesn't affect any of those bits.288  if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) {289    const APInt &AndMask = N->getConstantOperandAPInt(1);290 291    // Since the max shift amount is a power of 2 we can subtract 1 to make a292    // mask that covers the bits needed to represent all shift amounts.293    assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");294    APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);295 296    if (ShMask.isSubsetOf(AndMask)) {297      ShAmt = N.getOperand(0);298      return true;299    }300 301    // SimplifyDemandedBits may have optimized the mask so try restoring any302    // bits that are known zero.303    KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0));304    if (ShMask.isSubsetOf(AndMask | Known.Zero)) {305      ShAmt = N.getOperand(0);306      return true;307    }308  } else if (N.getOpcode() == LoongArchISD::BSTRPICK) {309    // Similar to the above AND, if there is a BSTRPICK on the shift amount, we310    // can bypass it.311    assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");312    assert(isa<ConstantSDNode>(N.getOperand(1)) && "Illegal msb operand!");313    assert(isa<ConstantSDNode>(N.getOperand(2)) && "Illegal lsb operand!");314    uint64_t msb = N.getConstantOperandVal(1), lsb = N.getConstantOperandVal(2);315    if (lsb == 0 && Log2_32(ShiftWidth) <= msb + 1) {316      ShAmt = N.getOperand(0);317      return true;318    }319  } else if (N.getOpcode() == ISD::SUB &&320             isa<ConstantSDNode>(N.getOperand(0))) {321    uint64_t Imm = N.getConstantOperandVal(0);322    // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to323    // generate a NEG instead of a SUB of a constant.324    if (Imm != 0 && Imm % ShiftWidth == 0) {325      SDLoc DL(N);326      EVT VT = N.getValueType();327      SDValue Zero =328          CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, LoongArch::R0, VT);329      unsigned NegOpc = VT == MVT::i64 ? LoongArch::SUB_D : LoongArch::SUB_W;330      MachineSDNode *Neg =331          CurDAG->getMachineNode(NegOpc, DL, VT, Zero, N.getOperand(1));332      ShAmt = SDValue(Neg, 0);333      return true;334    }335  }336 337  ShAmt = N;338  return true;339}340 341bool LoongArchDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) {342  if (N.getOpcode() == ISD::SIGN_EXTEND_INREG &&343      cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) {344    Val = N.getOperand(0);345    return true;346  }347  if (N.getOpcode() == LoongArchISD::BSTRPICK &&348      N.getConstantOperandVal(1) < UINT64_C(0X1F) &&349      N.getConstantOperandVal(2) == UINT64_C(0)) {350    Val = N;351    return true;352  }353  MVT VT = N.getSimpleValueType();354  if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) {355    Val = N;356    return true;357  }358 359  return false;360}361 362bool LoongArchDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) {363  if (N.getOpcode() == ISD::AND) {364    auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1));365    if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) {366      Val = N.getOperand(0);367      return true;368    }369  }370  MVT VT = N.getSimpleValueType();371  APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32);372  if (CurDAG->MaskedValueIsZero(N, Mask)) {373    Val = N;374    return true;375  }376 377  return false;378}379 380bool LoongArchDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm,381                                         unsigned MinSizeInBits) const {382  if (!Subtarget->hasExtLSX())383    return false;384 385  BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N);386 387  if (!Node)388    return false;389 390  APInt SplatValue, SplatUndef;391  unsigned SplatBitSize;392  bool HasAnyUndefs;393 394  if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,395                             MinSizeInBits, /*IsBigEndian=*/false))396    return false;397 398  Imm = SplatValue;399 400  return true;401}402 403template <unsigned ImmBitSize, bool IsSigned>404bool LoongArchDAGToDAGISel::selectVSplatImm(SDValue N, SDValue &SplatVal) {405  APInt ImmValue;406  EVT EltTy = N->getValueType(0).getVectorElementType();407 408  if (N->getOpcode() == ISD::BITCAST)409    N = N->getOperand(0);410 411  if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&412      ImmValue.getBitWidth() == EltTy.getSizeInBits()) {413    if (IsSigned && ImmValue.isSignedIntN(ImmBitSize)) {414      SplatVal = CurDAG->getSignedTargetConstant(415          ImmValue.getSExtValue(), SDLoc(N), Subtarget->getGRLenVT());416      return true;417    }418    if (!IsSigned && ImmValue.isIntN(ImmBitSize)) {419      SplatVal = CurDAG->getTargetConstant(ImmValue.getZExtValue(), SDLoc(N),420                                           Subtarget->getGRLenVT());421      return true;422    }423  }424 425  return false;426}427 428bool LoongArchDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N,429                                                    SDValue &SplatImm) const {430  APInt ImmValue;431  EVT EltTy = N->getValueType(0).getVectorElementType();432 433  if (N->getOpcode() == ISD::BITCAST)434    N = N->getOperand(0);435 436  if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&437      ImmValue.getBitWidth() == EltTy.getSizeInBits()) {438    int32_t Log2 = (~ImmValue).exactLogBase2();439 440    if (Log2 != -1) {441      SplatImm = CurDAG->getSignedTargetConstant(Log2, SDLoc(N), EltTy);442      return true;443    }444  }445 446  return false;447}448 449bool LoongArchDAGToDAGISel::selectVSplatUimmPow2(SDValue N,450                                                 SDValue &SplatImm) const {451  APInt ImmValue;452  EVT EltTy = N->getValueType(0).getVectorElementType();453 454  if (N->getOpcode() == ISD::BITCAST)455    N = N->getOperand(0);456 457  if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&458      ImmValue.getBitWidth() == EltTy.getSizeInBits()) {459    int32_t Log2 = ImmValue.exactLogBase2();460 461    if (Log2 != -1) {462      SplatImm = CurDAG->getSignedTargetConstant(Log2, SDLoc(N), EltTy);463      return true;464    }465  }466 467  return false;468}469 470// This pass converts a legalized DAG into a LoongArch-specific DAG, ready471// for instruction scheduling.472FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM,473                                           CodeGenOptLevel OptLevel) {474  return new LoongArchDAGToDAGISelLegacy(TM, OptLevel);475}476