brintos

brintos / llvm-project-archived public Read only

0
0
Text · 30.7 KiB · 9fc862a Raw
922 lines · cpp
1//=- LoongArchInstrInfo.cpp - LoongArch Instruction Information -*- C++ -*-===//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 contains the LoongArch implementation of the TargetInstrInfo class.10//11//===----------------------------------------------------------------------===//12 13#include "LoongArchInstrInfo.h"14#include "LoongArch.h"15#include "LoongArchMachineFunctionInfo.h"16#include "LoongArchRegisterInfo.h"17#include "MCTargetDesc/LoongArchMCTargetDesc.h"18#include "MCTargetDesc/LoongArchMatInt.h"19#include "llvm/CodeGen/RegisterScavenging.h"20#include "llvm/CodeGen/StackMaps.h"21#include "llvm/MC/MCInstBuilder.h"22 23using namespace llvm;24 25#define GET_INSTRINFO_CTOR_DTOR26#include "LoongArchGenInstrInfo.inc"27 28LoongArchInstrInfo::LoongArchInstrInfo(const LoongArchSubtarget &STI)29    : LoongArchGenInstrInfo(STI, RegInfo, LoongArch::ADJCALLSTACKDOWN,30                            LoongArch::ADJCALLSTACKUP),31      RegInfo(STI.getHwMode()), STI(STI) {}32 33MCInst LoongArchInstrInfo::getNop() const {34  return MCInstBuilder(LoongArch::ANDI)35      .addReg(LoongArch::R0)36      .addReg(LoongArch::R0)37      .addImm(0);38}39 40void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock &MBB,41                                     MachineBasicBlock::iterator MBBI,42                                     const DebugLoc &DL, Register DstReg,43                                     Register SrcReg, bool KillSrc,44                                     bool RenamableDest,45                                     bool RenamableSrc) const {46  if (LoongArch::GPRRegClass.contains(DstReg, SrcReg)) {47    BuildMI(MBB, MBBI, DL, get(LoongArch::OR), DstReg)48        .addReg(SrcReg, getKillRegState(KillSrc))49        .addReg(LoongArch::R0);50    return;51  }52 53  // VR->VR copies.54  if (LoongArch::LSX128RegClass.contains(DstReg, SrcReg)) {55    BuildMI(MBB, MBBI, DL, get(LoongArch::VORI_B), DstReg)56        .addReg(SrcReg, getKillRegState(KillSrc))57        .addImm(0);58    return;59  }60 61  // XR->XR copies.62  if (LoongArch::LASX256RegClass.contains(DstReg, SrcReg)) {63    BuildMI(MBB, MBBI, DL, get(LoongArch::XVORI_B), DstReg)64        .addReg(SrcReg, getKillRegState(KillSrc))65        .addImm(0);66    return;67  }68 69  // GPR->CFR copy.70  if (LoongArch::CFRRegClass.contains(DstReg) &&71      LoongArch::GPRRegClass.contains(SrcReg)) {72    BuildMI(MBB, MBBI, DL, get(LoongArch::MOVGR2CF), DstReg)73        .addReg(SrcReg, getKillRegState(KillSrc));74    return;75  }76  // CFR->GPR copy.77  if (LoongArch::GPRRegClass.contains(DstReg) &&78      LoongArch::CFRRegClass.contains(SrcReg)) {79    BuildMI(MBB, MBBI, DL, get(LoongArch::MOVCF2GR), DstReg)80        .addReg(SrcReg, getKillRegState(KillSrc));81    return;82  }83  // CFR->CFR copy.84  if (LoongArch::CFRRegClass.contains(DstReg, SrcReg)) {85    BuildMI(MBB, MBBI, DL, get(LoongArch::PseudoCopyCFR), DstReg)86        .addReg(SrcReg, getKillRegState(KillSrc));87    return;88  }89 90  // FPR->FPR copies.91  unsigned Opc;92  if (LoongArch::FPR32RegClass.contains(DstReg, SrcReg)) {93    Opc = LoongArch::FMOV_S;94  } else if (LoongArch::FPR64RegClass.contains(DstReg, SrcReg)) {95    Opc = LoongArch::FMOV_D;96  } else if (LoongArch::GPRRegClass.contains(DstReg) &&97             LoongArch::FPR32RegClass.contains(SrcReg)) {98    // FPR32 -> GPR copies99    Opc = LoongArch::MOVFR2GR_S;100  } else if (LoongArch::GPRRegClass.contains(DstReg) &&101             LoongArch::FPR64RegClass.contains(SrcReg)) {102    // FPR64 -> GPR copies103    Opc = LoongArch::MOVFR2GR_D;104  } else {105    // TODO: support other copies.106    llvm_unreachable("Impossible reg-to-reg copy");107  }108 109  BuildMI(MBB, MBBI, DL, get(Opc), DstReg)110      .addReg(SrcReg, getKillRegState(KillSrc));111}112 113void LoongArchInstrInfo::storeRegToStackSlot(114    MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register SrcReg,115    bool IsKill, int FI, const TargetRegisterClass *RC,116 117    Register VReg, MachineInstr::MIFlag Flags) const {118  MachineFunction *MF = MBB.getParent();119  MachineFrameInfo &MFI = MF->getFrameInfo();120 121  unsigned Opcode;122  if (LoongArch::GPRRegClass.hasSubClassEq(RC))123    Opcode = TRI.getRegSizeInBits(LoongArch::GPRRegClass) == 32124                 ? LoongArch::ST_W125                 : LoongArch::ST_D;126  else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))127    Opcode = LoongArch::FST_S;128  else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))129    Opcode = LoongArch::FST_D;130  else if (LoongArch::LSX128RegClass.hasSubClassEq(RC))131    Opcode = LoongArch::VST;132  else if (LoongArch::LASX256RegClass.hasSubClassEq(RC))133    Opcode = LoongArch::XVST;134  else if (LoongArch::CFRRegClass.hasSubClassEq(RC))135    Opcode = LoongArch::PseudoST_CFR;136  else137    llvm_unreachable("Can't store this register to stack slot");138 139  MachineMemOperand *MMO = MF->getMachineMemOperand(140      MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOStore,141      MFI.getObjectSize(FI), MFI.getObjectAlign(FI));142 143  BuildMI(MBB, I, DebugLoc(), get(Opcode))144      .addReg(SrcReg, getKillRegState(IsKill))145      .addFrameIndex(FI)146      .addImm(0)147      .addMemOperand(MMO);148}149 150void LoongArchInstrInfo::loadRegFromStackSlot(151    MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register DstReg,152    int FI, const TargetRegisterClass *RC, Register VReg,153    MachineInstr::MIFlag Flags) const {154  MachineFunction *MF = MBB.getParent();155  MachineFrameInfo &MFI = MF->getFrameInfo();156  DebugLoc DL;157  if (I != MBB.end())158    DL = I->getDebugLoc();159 160  unsigned Opcode;161  if (LoongArch::GPRRegClass.hasSubClassEq(RC))162    Opcode = RegInfo.getRegSizeInBits(LoongArch::GPRRegClass) == 32163                 ? LoongArch::LD_W164                 : LoongArch::LD_D;165  else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))166    Opcode = LoongArch::FLD_S;167  else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))168    Opcode = LoongArch::FLD_D;169  else if (LoongArch::LSX128RegClass.hasSubClassEq(RC))170    Opcode = LoongArch::VLD;171  else if (LoongArch::LASX256RegClass.hasSubClassEq(RC))172    Opcode = LoongArch::XVLD;173  else if (LoongArch::CFRRegClass.hasSubClassEq(RC))174    Opcode = LoongArch::PseudoLD_CFR;175  else176    llvm_unreachable("Can't load this register from stack slot");177 178  MachineMemOperand *MMO = MF->getMachineMemOperand(179      MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad,180      MFI.getObjectSize(FI), MFI.getObjectAlign(FI));181 182  BuildMI(MBB, I, DL, get(Opcode), DstReg)183      .addFrameIndex(FI)184      .addImm(0)185      .addMemOperand(MMO);186}187 188void LoongArchInstrInfo::movImm(MachineBasicBlock &MBB,189                                MachineBasicBlock::iterator MBBI,190                                const DebugLoc &DL, Register DstReg,191                                uint64_t Val, MachineInstr::MIFlag Flag) const {192  Register SrcReg = LoongArch::R0;193 194  if (!STI.is64Bit() && !isInt<32>(Val))195    report_fatal_error("Should only materialize 32-bit constants for LA32");196 197  auto Seq = LoongArchMatInt::generateInstSeq(Val);198  assert(!Seq.empty());199 200  for (auto &Inst : Seq) {201    switch (Inst.Opc) {202    case LoongArch::LU12I_W:203      BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)204          .addImm(Inst.Imm)205          .setMIFlag(Flag);206      break;207    case LoongArch::ADDI_W:208    case LoongArch::ORI:209    case LoongArch::LU32I_D: // "rj" is needed due to InstrInfo pattern210    case LoongArch::LU52I_D:211      BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)212          .addReg(SrcReg, RegState::Kill)213          .addImm(Inst.Imm)214          .setMIFlag(Flag);215      break;216    case LoongArch::BSTRINS_D:217      BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)218          .addReg(SrcReg, RegState::Kill)219          .addReg(SrcReg, RegState::Kill)220          .addImm(Inst.Imm >> 32)221          .addImm(Inst.Imm & 0xFF)222          .setMIFlag(Flag);223      break;224    default:225      assert(false && "Unknown insn emitted by LoongArchMatInt");226    }227 228    // Only the first instruction has $zero as its source.229    SrcReg = DstReg;230  }231}232 233unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {234  unsigned Opcode = MI.getOpcode();235 236  if (Opcode == TargetOpcode::INLINEASM ||237      Opcode == TargetOpcode::INLINEASM_BR) {238    const MachineFunction *MF = MI.getParent()->getParent();239    const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();240    return getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI);241  }242 243  unsigned NumBytes = 0;244  const MCInstrDesc &Desc = MI.getDesc();245 246  // Size should be preferably set in247  // llvm/lib/Target/LoongArch/LoongArch*InstrInfo.td (default case).248  // Specific cases handle instructions of variable sizes.249  switch (Desc.getOpcode()) {250  default:251    return Desc.getSize();252  case TargetOpcode::STATEPOINT:253    NumBytes = StatepointOpers(&MI).getNumPatchBytes();254    assert(NumBytes % 4 == 0 && "Invalid number of NOP bytes requested!");255    // No patch bytes means a normal call inst (i.e. `bl`) is emitted.256    if (NumBytes == 0)257      NumBytes = 4;258    break;259  }260  return NumBytes;261}262 263bool LoongArchInstrInfo::isAsCheapAsAMove(const MachineInstr &MI) const {264  const unsigned Opcode = MI.getOpcode();265  switch (Opcode) {266  default:267    break;268  case LoongArch::ADDI_D:269  case LoongArch::ORI:270  case LoongArch::XORI:271    return (MI.getOperand(1).isReg() &&272            MI.getOperand(1).getReg() == LoongArch::R0) ||273           (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0);274  }275  return MI.isAsCheapAsAMove();276}277 278MachineBasicBlock *279LoongArchInstrInfo::getBranchDestBlock(const MachineInstr &MI) const {280  assert(MI.getDesc().isBranch() && "Unexpected opcode!");281  // The branch target is always the last operand.282  return MI.getOperand(MI.getNumExplicitOperands() - 1).getMBB();283}284 285static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target,286                            SmallVectorImpl<MachineOperand> &Cond) {287  // Block ends with fall-through condbranch.288  assert(LastInst.getDesc().isConditionalBranch() &&289         "Unknown conditional branch");290  int NumOp = LastInst.getNumExplicitOperands();291  Target = LastInst.getOperand(NumOp - 1).getMBB();292 293  Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode()));294  for (int i = 0; i < NumOp - 1; i++)295    Cond.push_back(LastInst.getOperand(i));296}297 298bool LoongArchInstrInfo::analyzeBranch(MachineBasicBlock &MBB,299                                       MachineBasicBlock *&TBB,300                                       MachineBasicBlock *&FBB,301                                       SmallVectorImpl<MachineOperand> &Cond,302                                       bool AllowModify) const {303  TBB = FBB = nullptr;304  Cond.clear();305 306  // If the block has no terminators, it just falls into the block after it.307  MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();308  if (I == MBB.end() || !isUnpredicatedTerminator(*I))309    return false;310 311  // Count the number of terminators and find the first unconditional or312  // indirect branch.313  MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end();314  int NumTerminators = 0;315  for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(*J);316       J++) {317    NumTerminators++;318    if (J->getDesc().isUnconditionalBranch() ||319        J->getDesc().isIndirectBranch()) {320      FirstUncondOrIndirectBr = J.getReverse();321    }322  }323 324  // If AllowModify is true, we can erase any terminators after325  // FirstUncondOrIndirectBR.326  if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) {327    while (std::next(FirstUncondOrIndirectBr) != MBB.end()) {328      std::next(FirstUncondOrIndirectBr)->eraseFromParent();329      NumTerminators--;330    }331    I = FirstUncondOrIndirectBr;332  }333 334  // Handle a single unconditional branch.335  if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) {336    TBB = getBranchDestBlock(*I);337    return false;338  }339 340  // Handle a single conditional branch.341  if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) {342    parseCondBranch(*I, TBB, Cond);343    return false;344  }345 346  // Handle a conditional branch followed by an unconditional branch.347  if (NumTerminators == 2 && std::prev(I)->getDesc().isConditionalBranch() &&348      I->getDesc().isUnconditionalBranch()) {349    parseCondBranch(*std::prev(I), TBB, Cond);350    FBB = getBranchDestBlock(*I);351    return false;352  }353 354  // Otherwise, we can't handle this.355  return true;356}357 358bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp,359                                               int64_t BrOffset) const {360  switch (BranchOp) {361  default:362    llvm_unreachable("Unknown branch instruction!");363  case LoongArch::BEQ:364  case LoongArch::BNE:365  case LoongArch::BLT:366  case LoongArch::BGE:367  case LoongArch::BLTU:368  case LoongArch::BGEU:369    return isInt<18>(BrOffset);370  case LoongArch::BEQZ:371  case LoongArch::BNEZ:372  case LoongArch::BCEQZ:373  case LoongArch::BCNEZ:374    return isInt<23>(BrOffset);375  case LoongArch::B:376  case LoongArch::PseudoBR:377    return isInt<28>(BrOffset);378  }379}380 381bool LoongArchInstrInfo::isSafeToMove(const MachineInstr &MI,382                                      const MachineBasicBlock *MBB,383                                      const MachineFunction &MF) const {384  auto MII = MI.getIterator();385  auto MIE = MBB->end();386 387  // According to psABI v2.30:388  //389  // https://github.com/loongson/la-abi-specs/releases/tag/v2.30390  //391  // The following instruction patterns are prohibited from being reordered:392  //393  // * pcalau12i $a0, %pc_hi20(s)394  //   addi.d $a1, $zero, %pc_lo12(s)395  //   lu32i.d $a1, %pc64_lo20(s)396  //   lu52i.d $a1, $a1, %pc64_hi12(s)397  //398  // * pcalau12i $a0, %got_pc_hi20(s) | %ld_pc_hi20(s) | %gd_pc_hi20(s)399  //   addi.d $a1, $zero, %got_pc_lo12(s)400  //   lu32i.d $a1, %got64_pc_lo20(s)401  //   lu52i.d $a1, $a1, %got64_pc_hi12(s)402  //403  // * pcalau12i $a0, %ie_pc_hi20(s)404  //   addi.d $a1, $zero, %ie_pc_lo12(s)405  //   lu32i.d $a1, %ie64_pc_lo20(s)406  //   lu52i.d $a1, $a1, %ie64_pc_hi12(s)407  //408  // * pcalau12i $a0, %desc_pc_hi20(s)409  //   addi.d $a1, $zero, %desc_pc_lo12(s)410  //   lu32i.d $a1, %desc64_pc_lo20(s)411  //   lu52i.d $a1, $a1, %desc64_pc_hi12(s)412  //413  // For simplicity, only pcalau12i and lu52i.d are marked as scheduling414  // boundaries, and the instructions between them are guaranteed to be415  // ordered according to data dependencies.416  switch (MI.getOpcode()) {417  case LoongArch::PCALAU12I: {418    auto AddI = std::next(MII);419    if (AddI == MIE || AddI->getOpcode() != LoongArch::ADDI_D)420      break;421    auto Lu32I = std::next(AddI);422    if (Lu32I == MIE || Lu32I->getOpcode() != LoongArch::LU32I_D)423      break;424    auto MO0 = MI.getOperand(1).getTargetFlags();425    auto MO1 = AddI->getOperand(2).getTargetFlags();426    auto MO2 = Lu32I->getOperand(2).getTargetFlags();427    if (MO0 == LoongArchII::MO_PCREL_HI && MO1 == LoongArchII::MO_PCREL_LO &&428        MO2 == LoongArchII::MO_PCREL64_LO)429      return false;430    if ((MO0 == LoongArchII::MO_GOT_PC_HI || MO0 == LoongArchII::MO_LD_PC_HI ||431         MO0 == LoongArchII::MO_GD_PC_HI) &&432        MO1 == LoongArchII::MO_GOT_PC_LO && MO2 == LoongArchII::MO_GOT_PC64_LO)433      return false;434    if (MO0 == LoongArchII::MO_IE_PC_HI && MO1 == LoongArchII::MO_IE_PC_LO &&435        MO2 == LoongArchII::MO_IE_PC64_LO)436      return false;437    if (MO0 == LoongArchII::MO_DESC_PC_HI &&438        MO1 == LoongArchII::MO_DESC_PC_LO &&439        MO2 == LoongArchII::MO_DESC64_PC_LO)440      return false;441    break;442  }443  case LoongArch::LU52I_D: {444    auto MO = MI.getOperand(2).getTargetFlags();445    if (MO == LoongArchII::MO_PCREL64_HI || MO == LoongArchII::MO_GOT_PC64_HI ||446        MO == LoongArchII::MO_IE_PC64_HI || MO == LoongArchII::MO_DESC64_PC_HI)447      return false;448    break;449  }450  default:451    break;452  }453 454  const auto &STI = MF.getSubtarget<LoongArchSubtarget>();455  if (STI.hasFeature(LoongArch::FeatureRelax)) {456    // When linker relaxation enabled, the following instruction patterns are457    // prohibited from being reordered:458    //459    // * pcalau12i $a0, %pc_hi20(s)460    //   addi.w/d $a0, $a0, %pc_lo12(s)461    //462    // * pcalau12i $a0, %got_pc_hi20(s)463    //   ld.w/d $a0, $a0, %got_pc_lo12(s)464    //465    // * pcalau12i $a0, %ld_pc_hi20(s) | %gd_pc_hi20(s)466    //   addi.w/d $a0, $a0, %got_pc_lo12(s)467    //468    // * pcalau12i $a0, %desc_pc_hi20(s)469    //   addi.w/d  $a0, $a0, %desc_pc_lo12(s)470    //   ld.w/d    $ra, $a0, %desc_ld(s)471    //   jirl      $ra, $ra, %desc_call(s)472    unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;473    unsigned LdOp = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;474    switch (MI.getOpcode()) {475    case LoongArch::PCALAU12I: {476      auto MO0 = LoongArchII::getDirectFlags(MI.getOperand(1));477      auto SecondOp = std::next(MII);478      if (MO0 == LoongArchII::MO_DESC_PC_HI) {479        if (SecondOp == MIE || SecondOp->getOpcode() != AddiOp)480          break;481        auto Ld = std::next(SecondOp);482        if (Ld == MIE || Ld->getOpcode() != LdOp)483          break;484        auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));485        auto MO2 = LoongArchII::getDirectFlags(Ld->getOperand(2));486        if (MO1 == LoongArchII::MO_DESC_PC_LO && MO2 == LoongArchII::MO_DESC_LD)487          return false;488        break;489      }490      if (SecondOp == MIE ||491          (SecondOp->getOpcode() != AddiOp && SecondOp->getOpcode() != LdOp))492        break;493      auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));494      if (MO0 == LoongArchII::MO_PCREL_HI && SecondOp->getOpcode() == AddiOp &&495          MO1 == LoongArchII::MO_PCREL_LO)496        return false;497      if (MO0 == LoongArchII::MO_GOT_PC_HI && SecondOp->getOpcode() == LdOp &&498          MO1 == LoongArchII::MO_GOT_PC_LO)499        return false;500      if ((MO0 == LoongArchII::MO_LD_PC_HI ||501           MO0 == LoongArchII::MO_GD_PC_HI) &&502          SecondOp->getOpcode() == AddiOp && MO1 == LoongArchII::MO_GOT_PC_LO)503        return false;504      break;505    }506    case LoongArch::ADDI_W:507    case LoongArch::ADDI_D: {508      auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));509      if (MO == LoongArchII::MO_PCREL_LO || MO == LoongArchII::MO_GOT_PC_LO)510        return false;511      break;512    }513    case LoongArch::LD_W:514    case LoongArch::LD_D: {515      auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));516      if (MO == LoongArchII::MO_GOT_PC_LO)517        return false;518      break;519    }520    case LoongArch::PseudoDESC_CALL: {521      auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));522      if (MO == LoongArchII::MO_DESC_CALL)523        return false;524      break;525    }526    default:527      break;528    }529  }530 531  return true;532}533 534bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,535                                              const MachineBasicBlock *MBB,536                                              const MachineFunction &MF) const {537  if (TargetInstrInfo::isSchedulingBoundary(MI, MBB, MF))538    return true;539 540  if (!isSafeToMove(MI, MBB, MF))541    return true;542 543  return false;544}545 546unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB,547                                          int *BytesRemoved) const {548  if (BytesRemoved)549    *BytesRemoved = 0;550  MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();551  if (I == MBB.end())552    return 0;553 554  if (!I->getDesc().isBranch())555    return 0;556 557  // Remove the branch.558  if (BytesRemoved)559    *BytesRemoved += getInstSizeInBytes(*I);560  I->eraseFromParent();561 562  I = MBB.end();563 564  if (I == MBB.begin())565    return 1;566  --I;567  if (!I->getDesc().isConditionalBranch())568    return 1;569 570  // Remove the branch.571  if (BytesRemoved)572    *BytesRemoved += getInstSizeInBytes(*I);573  I->eraseFromParent();574  return 2;575}576 577// Inserts a branch into the end of the specific MachineBasicBlock, returning578// the number of instructions inserted.579unsigned LoongArchInstrInfo::insertBranch(580    MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,581    ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {582  if (BytesAdded)583    *BytesAdded = 0;584 585  // Shouldn't be a fall through.586  assert(TBB && "insertBranch must not be told to insert a fallthrough");587  assert(Cond.size() <= 3 && Cond.size() != 1 &&588         "LoongArch branch conditions have at most two components!");589 590  // Unconditional branch.591  if (Cond.empty()) {592    MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(TBB);593    if (BytesAdded)594      *BytesAdded += getInstSizeInBytes(MI);595    return 1;596  }597 598  // Either a one or two-way conditional branch.599  MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(Cond[0].getImm()));600  for (unsigned i = 1; i < Cond.size(); ++i)601    MIB.add(Cond[i]);602  MIB.addMBB(TBB);603  if (BytesAdded)604    *BytesAdded += getInstSizeInBytes(*MIB);605 606  // One-way conditional branch.607  if (!FBB)608    return 1;609 610  // Two-way conditional branch.611  MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(FBB);612  if (BytesAdded)613    *BytesAdded += getInstSizeInBytes(MI);614  return 2;615}616 617void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,618                                              MachineBasicBlock &DestBB,619                                              MachineBasicBlock &RestoreBB,620                                              const DebugLoc &DL,621                                              int64_t BrOffset,622                                              RegScavenger *RS) const {623  assert(RS && "RegScavenger required for long branching");624  assert(MBB.empty() &&625         "new block should be inserted for expanding unconditional branch");626  assert(MBB.pred_size() == 1);627 628  MachineFunction *MF = MBB.getParent();629  MachineRegisterInfo &MRI = MF->getRegInfo();630  const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();631  LoongArchMachineFunctionInfo *LAFI =632      MF->getInfo<LoongArchMachineFunctionInfo>();633 634  if (!isInt<32>(BrOffset))635    report_fatal_error(636        "Branch offsets outside of the signed 32-bit range not supported");637 638  Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);639  auto II = MBB.end();640 641  MachineInstr &PCALAU12I =642      *BuildMI(MBB, II, DL, get(LoongArch::PCALAU12I), ScratchReg)643           .addMBB(&DestBB, LoongArchII::MO_PCREL_HI);644  MachineInstr &ADDI =645      *BuildMI(MBB, II, DL,646               get(STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W),647               ScratchReg)648           .addReg(ScratchReg)649           .addMBB(&DestBB, LoongArchII::MO_PCREL_LO);650  BuildMI(MBB, II, DL, get(LoongArch::PseudoBRIND))651      .addReg(ScratchReg, RegState::Kill)652      .addImm(0);653 654  RS->enterBasicBlockEnd(MBB);655  Register Scav = RS->scavengeRegisterBackwards(656      LoongArch::GPRRegClass, PCALAU12I.getIterator(), /*RestoreAfter=*/false,657      /*SPAdj=*/0, /*AllowSpill=*/false);658  if (Scav != LoongArch::NoRegister)659    RS->setRegUsed(Scav);660  else {661    // When there is no scavenged register, it needs to specify a register.662    // Specify t8 register because it won't be used too often.663    Scav = LoongArch::R20;664    int FrameIndex = LAFI->getBranchRelaxationSpillFrameIndex();665    if (FrameIndex == -1)666      report_fatal_error("The function size is incorrectly estimated.");667    storeRegToStackSlot(MBB, PCALAU12I, Scav, /*IsKill=*/true, FrameIndex,668                        &LoongArch::GPRRegClass, Register());669    TRI->eliminateFrameIndex(std::prev(PCALAU12I.getIterator()),670                             /*SpAdj=*/0, /*FIOperandNum=*/1);671    PCALAU12I.getOperand(1).setMBB(&RestoreBB);672    ADDI.getOperand(2).setMBB(&RestoreBB);673    loadRegFromStackSlot(RestoreBB, RestoreBB.end(), Scav, FrameIndex,674                         &LoongArch::GPRRegClass, Register());675    TRI->eliminateFrameIndex(RestoreBB.back(),676                             /*SpAdj=*/0, /*FIOperandNum=*/1);677  }678  MRI.replaceRegWith(ScratchReg, Scav);679  MRI.clearVirtRegs();680}681 682static unsigned getOppositeBranchOpc(unsigned Opc) {683  switch (Opc) {684  default:685    llvm_unreachable("Unrecognized conditional branch");686  case LoongArch::BEQ:687    return LoongArch::BNE;688  case LoongArch::BNE:689    return LoongArch::BEQ;690  case LoongArch::BEQZ:691    return LoongArch::BNEZ;692  case LoongArch::BNEZ:693    return LoongArch::BEQZ;694  case LoongArch::BCEQZ:695    return LoongArch::BCNEZ;696  case LoongArch::BCNEZ:697    return LoongArch::BCEQZ;698  case LoongArch::BLT:699    return LoongArch::BGE;700  case LoongArch::BGE:701    return LoongArch::BLT;702  case LoongArch::BLTU:703    return LoongArch::BGEU;704  case LoongArch::BGEU:705    return LoongArch::BLTU;706  }707}708 709bool LoongArchInstrInfo::reverseBranchCondition(710    SmallVectorImpl<MachineOperand> &Cond) const {711  assert((Cond.size() && Cond.size() <= 3) && "Invalid branch condition!");712  Cond[0].setImm(getOppositeBranchOpc(Cond[0].getImm()));713  return false;714}715 716std::pair<unsigned, unsigned>717LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {718  const unsigned Mask = LoongArchII::MO_DIRECT_FLAG_MASK;719  return std::make_pair(TF & Mask, TF & ~Mask);720}721 722ArrayRef<std::pair<unsigned, const char *>>723LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {724  using namespace LoongArchII;725  // TODO: Add more target flags.726  static const std::pair<unsigned, const char *> TargetFlags[] = {727      {MO_CALL, "loongarch-call"},728      {MO_CALL_PLT, "loongarch-call-plt"},729      {MO_PCREL_HI, "loongarch-pcrel-hi"},730      {MO_PCREL_LO, "loongarch-pcrel-lo"},731      {MO_PCREL64_LO, "loongarch-pcrel64-lo"},732      {MO_PCREL64_HI, "loongarch-pcrel64-hi"},733      {MO_GOT_PC_HI, "loongarch-got-pc-hi"},734      {MO_GOT_PC_LO, "loongarch-got-pc-lo"},735      {MO_GOT_PC64_LO, "loongarch-got-pc64-lo"},736      {MO_GOT_PC64_HI, "loongarch-got-pc64-hi"},737      {MO_LE_HI, "loongarch-le-hi"},738      {MO_LE_LO, "loongarch-le-lo"},739      {MO_LE64_LO, "loongarch-le64-lo"},740      {MO_LE64_HI, "loongarch-le64-hi"},741      {MO_IE_PC_HI, "loongarch-ie-pc-hi"},742      {MO_IE_PC_LO, "loongarch-ie-pc-lo"},743      {MO_IE_PC64_LO, "loongarch-ie-pc64-lo"},744      {MO_IE_PC64_HI, "loongarch-ie-pc64-hi"},745      {MO_LD_PC_HI, "loongarch-ld-pc-hi"},746      {MO_GD_PC_HI, "loongarch-gd-pc-hi"},747      {MO_CALL36, "loongarch-call36"},748      {MO_DESC_PC_HI, "loongarch-desc-pc-hi"},749      {MO_DESC_PC_LO, "loongarch-desc-pc-lo"},750      {MO_DESC64_PC_LO, "loongarch-desc64-pc-lo"},751      {MO_DESC64_PC_HI, "loongarch-desc64-pc-hi"},752      {MO_DESC_LD, "loongarch-desc-ld"},753      {MO_DESC_CALL, "loongarch-desc-call"},754      {MO_LE_HI_R, "loongarch-le-hi-r"},755      {MO_LE_ADD_R, "loongarch-le-add-r"},756      {MO_LE_LO_R, "loongarch-le-lo-r"}};757  return ArrayRef(TargetFlags);758}759 760ArrayRef<std::pair<unsigned, const char *>>761LoongArchInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {762  using namespace LoongArchII;763  static const std::pair<unsigned, const char *> TargetFlags[] = {764      {MO_RELAX, "loongarch-relax"}};765  return ArrayRef(TargetFlags);766}767 768bool LoongArchInstrInfo::canFoldIntoAddrMode(const MachineInstr &MemI,769                                             Register Reg,770                                             const MachineInstr &AddrI,771                                             ExtAddrMode &AM) const {772  enum MemIOffsetType {773    Imm14Shift2,774    Imm12,775    Imm11Shift1,776    Imm10Shift2,777    Imm9Shift3,778    Imm8,779    Imm8Shift1,780    Imm8Shift2,781    Imm8Shift3782  };783 784  MemIOffsetType OT;785  switch (MemI.getOpcode()) {786  default:787    return false;788  case LoongArch::LDPTR_W:789  case LoongArch::LDPTR_D:790  case LoongArch::STPTR_W:791  case LoongArch::STPTR_D:792    OT = Imm14Shift2;793    break;794  case LoongArch::LD_B:795  case LoongArch::LD_H:796  case LoongArch::LD_W:797  case LoongArch::LD_D:798  case LoongArch::LD_BU:799  case LoongArch::LD_HU:800  case LoongArch::LD_WU:801  case LoongArch::ST_B:802  case LoongArch::ST_H:803  case LoongArch::ST_W:804  case LoongArch::ST_D:805  case LoongArch::FLD_S:806  case LoongArch::FLD_D:807  case LoongArch::FST_S:808  case LoongArch::FST_D:809  case LoongArch::VLD:810  case LoongArch::VST:811  case LoongArch::XVLD:812  case LoongArch::XVST:813  case LoongArch::VLDREPL_B:814  case LoongArch::XVLDREPL_B:815    OT = Imm12;816    break;817  case LoongArch::VLDREPL_H:818  case LoongArch::XVLDREPL_H:819    OT = Imm11Shift1;820    break;821  case LoongArch::VLDREPL_W:822  case LoongArch::XVLDREPL_W:823    OT = Imm10Shift2;824    break;825  case LoongArch::VLDREPL_D:826  case LoongArch::XVLDREPL_D:827    OT = Imm9Shift3;828    break;829  case LoongArch::VSTELM_B:830  case LoongArch::XVSTELM_B:831    OT = Imm8;832    break;833  case LoongArch::VSTELM_H:834  case LoongArch::XVSTELM_H:835    OT = Imm8Shift1;836    break;837  case LoongArch::VSTELM_W:838  case LoongArch::XVSTELM_W:839    OT = Imm8Shift2;840    break;841  case LoongArch::VSTELM_D:842  case LoongArch::XVSTELM_D:843    OT = Imm8Shift3;844    break;845  }846 847  if (MemI.getOperand(0).getReg() == Reg)848    return false;849 850  if ((AddrI.getOpcode() != LoongArch::ADDI_W &&851       AddrI.getOpcode() != LoongArch::ADDI_D) ||852      !AddrI.getOperand(1).isReg() || !AddrI.getOperand(2).isImm())853    return false;854 855  int64_t OldOffset = MemI.getOperand(2).getImm();856  int64_t Disp = AddrI.getOperand(2).getImm();857  int64_t NewOffset = OldOffset + Disp;858  if (!STI.is64Bit())859    NewOffset = SignExtend64<32>(NewOffset);860 861  if (!(OT == Imm14Shift2 && isShiftedInt<14, 2>(NewOffset) && STI.hasUAL()) &&862      !(OT == Imm12 && isInt<12>(NewOffset)) &&863      !(OT == Imm11Shift1 && isShiftedInt<11, 1>(NewOffset)) &&864      !(OT == Imm10Shift2 && isShiftedInt<10, 2>(NewOffset)) &&865      !(OT == Imm9Shift3 && isShiftedInt<9, 3>(NewOffset)) &&866      !(OT == Imm8 && isInt<8>(NewOffset)) &&867      !(OT == Imm8Shift1 && isShiftedInt<8, 1>(NewOffset)) &&868      !(OT == Imm8Shift2 && isShiftedInt<8, 2>(NewOffset)) &&869      !(OT == Imm8Shift3 && isShiftedInt<8, 3>(NewOffset)))870    return false;871 872  AM.BaseReg = AddrI.getOperand(1).getReg();873  AM.ScaledReg = 0;874  AM.Scale = 0;875  AM.Displacement = NewOffset;876  AM.Form = ExtAddrMode::Formula::Basic;877  return true;878}879 880MachineInstr *881LoongArchInstrInfo::emitLdStWithAddr(MachineInstr &MemI,882                                     const ExtAddrMode &AM) const {883  const DebugLoc &DL = MemI.getDebugLoc();884  MachineBasicBlock &MBB = *MemI.getParent();885 886  assert(AM.ScaledReg == 0 && AM.Scale == 0 &&887         "Addressing mode not supported for folding");888 889  unsigned MemIOp = MemI.getOpcode();890  switch (MemIOp) {891  default:892    return BuildMI(MBB, MemI, DL, get(MemIOp))893        .addReg(MemI.getOperand(0).getReg(),894                MemI.mayLoad() ? RegState::Define : 0)895        .addReg(AM.BaseReg)896        .addImm(AM.Displacement)897        .setMemRefs(MemI.memoperands())898        .setMIFlags(MemI.getFlags());899  case LoongArch::VSTELM_B:900  case LoongArch::VSTELM_H:901  case LoongArch::VSTELM_W:902  case LoongArch::VSTELM_D:903  case LoongArch::XVSTELM_B:904  case LoongArch::XVSTELM_H:905  case LoongArch::XVSTELM_W:906  case LoongArch::XVSTELM_D:907    return BuildMI(MBB, MemI, DL, get(MemIOp))908        .addReg(MemI.getOperand(0).getReg(), 0)909        .addReg(AM.BaseReg)910        .addImm(AM.Displacement)911        .addImm(MemI.getOperand(3).getImm())912        .setMemRefs(MemI.memoperands())913        .setMIFlags(MemI.getFlags());914  }915}916 917// Returns true if this is the sext.w pattern, addi.w rd, rs, 0.918bool LoongArch::isSEXT_W(const MachineInstr &MI) {919  return MI.getOpcode() == LoongArch::ADDI_W && MI.getOperand(1).isReg() &&920         MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0;921}922