181ad6265SDimitry Andric //=- LoongArchInstrInfo.cpp - LoongArch Instruction Information -*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // This file contains the LoongArch implementation of the TargetInstrInfo class. 1081ad6265SDimitry Andric // 1181ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1281ad6265SDimitry Andric 1381ad6265SDimitry Andric #include "LoongArchInstrInfo.h" 1481ad6265SDimitry Andric #include "LoongArch.h" 15753f127fSDimitry Andric #include "LoongArchMachineFunctionInfo.h" 16bdd1243dSDimitry Andric #include "LoongArchRegisterInfo.h" 17bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h" 18bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchMatInt.h" 19bdd1243dSDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h" 2006c3fb27SDimitry Andric #include "llvm/MC/MCInstBuilder.h" 2181ad6265SDimitry Andric 2281ad6265SDimitry Andric using namespace llvm; 2381ad6265SDimitry Andric 2481ad6265SDimitry Andric #define GET_INSTRINFO_CTOR_DTOR 2581ad6265SDimitry Andric #include "LoongArchGenInstrInfo.inc" 2681ad6265SDimitry Andric 2781ad6265SDimitry Andric LoongArchInstrInfo::LoongArchInstrInfo(LoongArchSubtarget &STI) 28753f127fSDimitry Andric : LoongArchGenInstrInfo(LoongArch::ADJCALLSTACKDOWN, 29bdd1243dSDimitry Andric LoongArch::ADJCALLSTACKUP), 30bdd1243dSDimitry Andric STI(STI) {} 3181ad6265SDimitry Andric 3206c3fb27SDimitry Andric MCInst LoongArchInstrInfo::getNop() const { 3306c3fb27SDimitry Andric return MCInstBuilder(LoongArch::ANDI) 3406c3fb27SDimitry Andric .addReg(LoongArch::R0) 3506c3fb27SDimitry Andric .addReg(LoongArch::R0) 3606c3fb27SDimitry Andric .addImm(0); 3706c3fb27SDimitry Andric } 3806c3fb27SDimitry Andric 3981ad6265SDimitry Andric void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 4081ad6265SDimitry Andric MachineBasicBlock::iterator MBBI, 4181ad6265SDimitry Andric const DebugLoc &DL, MCRegister DstReg, 4281ad6265SDimitry Andric MCRegister SrcReg, bool KillSrc) const { 4381ad6265SDimitry Andric if (LoongArch::GPRRegClass.contains(DstReg, SrcReg)) { 4481ad6265SDimitry Andric BuildMI(MBB, MBBI, DL, get(LoongArch::OR), DstReg) 4581ad6265SDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)) 4681ad6265SDimitry Andric .addReg(LoongArch::R0); 4781ad6265SDimitry Andric return; 4881ad6265SDimitry Andric } 4981ad6265SDimitry Andric 505f757f3fSDimitry Andric // VR->VR copies. 515f757f3fSDimitry Andric if (LoongArch::LSX128RegClass.contains(DstReg, SrcReg)) { 525f757f3fSDimitry Andric BuildMI(MBB, MBBI, DL, get(LoongArch::VORI_B), DstReg) 535f757f3fSDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)) 545f757f3fSDimitry Andric .addImm(0); 555f757f3fSDimitry Andric return; 565f757f3fSDimitry Andric } 575f757f3fSDimitry Andric 585f757f3fSDimitry Andric // XR->XR copies. 595f757f3fSDimitry Andric if (LoongArch::LASX256RegClass.contains(DstReg, SrcReg)) { 605f757f3fSDimitry Andric BuildMI(MBB, MBBI, DL, get(LoongArch::XVORI_B), DstReg) 615f757f3fSDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)) 625f757f3fSDimitry Andric .addImm(0); 635f757f3fSDimitry Andric return; 645f757f3fSDimitry Andric } 655f757f3fSDimitry Andric 66bdd1243dSDimitry Andric // GPR->CFR copy. 67bdd1243dSDimitry Andric if (LoongArch::CFRRegClass.contains(DstReg) && 68bdd1243dSDimitry Andric LoongArch::GPRRegClass.contains(SrcReg)) { 69bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, get(LoongArch::MOVGR2CF), DstReg) 70bdd1243dSDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)); 71bdd1243dSDimitry Andric return; 72bdd1243dSDimitry Andric } 73bdd1243dSDimitry Andric // CFR->GPR copy. 74bdd1243dSDimitry Andric if (LoongArch::GPRRegClass.contains(DstReg) && 75bdd1243dSDimitry Andric LoongArch::CFRRegClass.contains(SrcReg)) { 76bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, get(LoongArch::MOVCF2GR), DstReg) 77bdd1243dSDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)); 78bdd1243dSDimitry Andric return; 79bdd1243dSDimitry Andric } 80b121cb00SDimitry Andric // CFR->CFR copy. 81b121cb00SDimitry Andric if (LoongArch::CFRRegClass.contains(DstReg, SrcReg)) { 82b121cb00SDimitry Andric BuildMI(MBB, MBBI, DL, get(LoongArch::PseudoCopyCFR), DstReg) 83b121cb00SDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)); 84b121cb00SDimitry Andric return; 85b121cb00SDimitry Andric } 86bdd1243dSDimitry Andric 8781ad6265SDimitry Andric // FPR->FPR copies. 8881ad6265SDimitry Andric unsigned Opc; 8981ad6265SDimitry Andric if (LoongArch::FPR32RegClass.contains(DstReg, SrcReg)) { 9081ad6265SDimitry Andric Opc = LoongArch::FMOV_S; 9181ad6265SDimitry Andric } else if (LoongArch::FPR64RegClass.contains(DstReg, SrcReg)) { 9281ad6265SDimitry Andric Opc = LoongArch::FMOV_D; 935f757f3fSDimitry Andric } else if (LoongArch::GPRRegClass.contains(DstReg) && 945f757f3fSDimitry Andric LoongArch::FPR32RegClass.contains(SrcReg)) { 955f757f3fSDimitry Andric // FPR32 -> GPR copies 965f757f3fSDimitry Andric Opc = LoongArch::MOVFR2GR_S; 975f757f3fSDimitry Andric } else if (LoongArch::GPRRegClass.contains(DstReg) && 985f757f3fSDimitry Andric LoongArch::FPR64RegClass.contains(SrcReg)) { 995f757f3fSDimitry Andric // FPR64 -> GPR copies 1005f757f3fSDimitry Andric Opc = LoongArch::MOVFR2GR_D; 10181ad6265SDimitry Andric } else { 10281ad6265SDimitry Andric // TODO: support other copies. 10381ad6265SDimitry Andric llvm_unreachable("Impossible reg-to-reg copy"); 10481ad6265SDimitry Andric } 10581ad6265SDimitry Andric 10681ad6265SDimitry Andric BuildMI(MBB, MBBI, DL, get(Opc), DstReg) 10781ad6265SDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)); 10881ad6265SDimitry Andric } 109753f127fSDimitry Andric 110753f127fSDimitry Andric void LoongArchInstrInfo::storeRegToStackSlot( 111753f127fSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register SrcReg, 112753f127fSDimitry Andric bool IsKill, int FI, const TargetRegisterClass *RC, 113bdd1243dSDimitry Andric const TargetRegisterInfo *TRI, Register VReg) const { 114753f127fSDimitry Andric MachineFunction *MF = MBB.getParent(); 115753f127fSDimitry Andric MachineFrameInfo &MFI = MF->getFrameInfo(); 116753f127fSDimitry Andric 117753f127fSDimitry Andric unsigned Opcode; 118753f127fSDimitry Andric if (LoongArch::GPRRegClass.hasSubClassEq(RC)) 119753f127fSDimitry Andric Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32 120753f127fSDimitry Andric ? LoongArch::ST_W 121753f127fSDimitry Andric : LoongArch::ST_D; 122753f127fSDimitry Andric else if (LoongArch::FPR32RegClass.hasSubClassEq(RC)) 123753f127fSDimitry Andric Opcode = LoongArch::FST_S; 124753f127fSDimitry Andric else if (LoongArch::FPR64RegClass.hasSubClassEq(RC)) 125753f127fSDimitry Andric Opcode = LoongArch::FST_D; 1265f757f3fSDimitry Andric else if (LoongArch::LSX128RegClass.hasSubClassEq(RC)) 1275f757f3fSDimitry Andric Opcode = LoongArch::VST; 1285f757f3fSDimitry Andric else if (LoongArch::LASX256RegClass.hasSubClassEq(RC)) 1295f757f3fSDimitry Andric Opcode = LoongArch::XVST; 130bdd1243dSDimitry Andric else if (LoongArch::CFRRegClass.hasSubClassEq(RC)) 131bdd1243dSDimitry Andric Opcode = LoongArch::PseudoST_CFR; 132753f127fSDimitry Andric else 133753f127fSDimitry Andric llvm_unreachable("Can't store this register to stack slot"); 134753f127fSDimitry Andric 135753f127fSDimitry Andric MachineMemOperand *MMO = MF->getMachineMemOperand( 136753f127fSDimitry Andric MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOStore, 137753f127fSDimitry Andric MFI.getObjectSize(FI), MFI.getObjectAlign(FI)); 138753f127fSDimitry Andric 13906c3fb27SDimitry Andric BuildMI(MBB, I, DebugLoc(), get(Opcode)) 140753f127fSDimitry Andric .addReg(SrcReg, getKillRegState(IsKill)) 141753f127fSDimitry Andric .addFrameIndex(FI) 142753f127fSDimitry Andric .addImm(0) 143753f127fSDimitry Andric .addMemOperand(MMO); 144753f127fSDimitry Andric } 145753f127fSDimitry Andric 146bdd1243dSDimitry Andric void LoongArchInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, 147bdd1243dSDimitry Andric MachineBasicBlock::iterator I, 148bdd1243dSDimitry Andric Register DstReg, int FI, 149bdd1243dSDimitry Andric const TargetRegisterClass *RC, 150bdd1243dSDimitry Andric const TargetRegisterInfo *TRI, 151bdd1243dSDimitry Andric Register VReg) const { 152753f127fSDimitry Andric MachineFunction *MF = MBB.getParent(); 153753f127fSDimitry Andric MachineFrameInfo &MFI = MF->getFrameInfo(); 154753f127fSDimitry Andric 155753f127fSDimitry Andric unsigned Opcode; 156753f127fSDimitry Andric if (LoongArch::GPRRegClass.hasSubClassEq(RC)) 157753f127fSDimitry Andric Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32 158753f127fSDimitry Andric ? LoongArch::LD_W 159753f127fSDimitry Andric : LoongArch::LD_D; 160753f127fSDimitry Andric else if (LoongArch::FPR32RegClass.hasSubClassEq(RC)) 161753f127fSDimitry Andric Opcode = LoongArch::FLD_S; 162753f127fSDimitry Andric else if (LoongArch::FPR64RegClass.hasSubClassEq(RC)) 163753f127fSDimitry Andric Opcode = LoongArch::FLD_D; 1645f757f3fSDimitry Andric else if (LoongArch::LSX128RegClass.hasSubClassEq(RC)) 1655f757f3fSDimitry Andric Opcode = LoongArch::VLD; 1665f757f3fSDimitry Andric else if (LoongArch::LASX256RegClass.hasSubClassEq(RC)) 1675f757f3fSDimitry Andric Opcode = LoongArch::XVLD; 168bdd1243dSDimitry Andric else if (LoongArch::CFRRegClass.hasSubClassEq(RC)) 169bdd1243dSDimitry Andric Opcode = LoongArch::PseudoLD_CFR; 170753f127fSDimitry Andric else 171753f127fSDimitry Andric llvm_unreachable("Can't load this register from stack slot"); 172753f127fSDimitry Andric 173753f127fSDimitry Andric MachineMemOperand *MMO = MF->getMachineMemOperand( 174753f127fSDimitry Andric MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad, 175753f127fSDimitry Andric MFI.getObjectSize(FI), MFI.getObjectAlign(FI)); 176753f127fSDimitry Andric 17706c3fb27SDimitry Andric BuildMI(MBB, I, DebugLoc(), get(Opcode), DstReg) 178753f127fSDimitry Andric .addFrameIndex(FI) 179753f127fSDimitry Andric .addImm(0) 180753f127fSDimitry Andric .addMemOperand(MMO); 181753f127fSDimitry Andric } 182bdd1243dSDimitry Andric 183bdd1243dSDimitry Andric void LoongArchInstrInfo::movImm(MachineBasicBlock &MBB, 184bdd1243dSDimitry Andric MachineBasicBlock::iterator MBBI, 185bdd1243dSDimitry Andric const DebugLoc &DL, Register DstReg, 186bdd1243dSDimitry Andric uint64_t Val, MachineInstr::MIFlag Flag) const { 187bdd1243dSDimitry Andric Register SrcReg = LoongArch::R0; 188bdd1243dSDimitry Andric 189bdd1243dSDimitry Andric if (!STI.is64Bit() && !isInt<32>(Val)) 190bdd1243dSDimitry Andric report_fatal_error("Should only materialize 32-bit constants for LA32"); 191bdd1243dSDimitry Andric 192bdd1243dSDimitry Andric auto Seq = LoongArchMatInt::generateInstSeq(Val); 193bdd1243dSDimitry Andric assert(!Seq.empty()); 194bdd1243dSDimitry Andric 195bdd1243dSDimitry Andric for (auto &Inst : Seq) { 196bdd1243dSDimitry Andric switch (Inst.Opc) { 197bdd1243dSDimitry Andric case LoongArch::LU12I_W: 198bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg) 199bdd1243dSDimitry Andric .addImm(Inst.Imm) 200bdd1243dSDimitry Andric .setMIFlag(Flag); 201bdd1243dSDimitry Andric break; 202bdd1243dSDimitry Andric case LoongArch::ADDI_W: 203bdd1243dSDimitry Andric case LoongArch::ORI: 204bdd1243dSDimitry Andric case LoongArch::LU32I_D: // "rj" is needed due to InstrInfo pattern 205bdd1243dSDimitry Andric case LoongArch::LU52I_D: 206bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg) 207bdd1243dSDimitry Andric .addReg(SrcReg, RegState::Kill) 208bdd1243dSDimitry Andric .addImm(Inst.Imm) 209bdd1243dSDimitry Andric .setMIFlag(Flag); 210bdd1243dSDimitry Andric break; 211bdd1243dSDimitry Andric default: 212bdd1243dSDimitry Andric assert(false && "Unknown insn emitted by LoongArchMatInt"); 213bdd1243dSDimitry Andric } 214bdd1243dSDimitry Andric 215bdd1243dSDimitry Andric // Only the first instruction has $zero as its source. 216bdd1243dSDimitry Andric SrcReg = DstReg; 217bdd1243dSDimitry Andric } 218bdd1243dSDimitry Andric } 219bdd1243dSDimitry Andric 220bdd1243dSDimitry Andric unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { 221bdd1243dSDimitry Andric unsigned Opcode = MI.getOpcode(); 222bdd1243dSDimitry Andric 223bdd1243dSDimitry Andric if (Opcode == TargetOpcode::INLINEASM || 224bdd1243dSDimitry Andric Opcode == TargetOpcode::INLINEASM_BR) { 225bdd1243dSDimitry Andric const MachineFunction *MF = MI.getParent()->getParent(); 226bdd1243dSDimitry Andric const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo(); 227bdd1243dSDimitry Andric return getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI); 228bdd1243dSDimitry Andric } 229bdd1243dSDimitry Andric return MI.getDesc().getSize(); 230bdd1243dSDimitry Andric } 231bdd1243dSDimitry Andric 232*0fca6ea1SDimitry Andric bool LoongArchInstrInfo::isAsCheapAsAMove(const MachineInstr &MI) const { 233*0fca6ea1SDimitry Andric const unsigned Opcode = MI.getOpcode(); 234*0fca6ea1SDimitry Andric switch (Opcode) { 235*0fca6ea1SDimitry Andric default: 236*0fca6ea1SDimitry Andric break; 237*0fca6ea1SDimitry Andric case LoongArch::ADDI_D: 238*0fca6ea1SDimitry Andric case LoongArch::ORI: 239*0fca6ea1SDimitry Andric case LoongArch::XORI: 240*0fca6ea1SDimitry Andric return (MI.getOperand(1).isReg() && 241*0fca6ea1SDimitry Andric MI.getOperand(1).getReg() == LoongArch::R0) || 242*0fca6ea1SDimitry Andric (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0); 243*0fca6ea1SDimitry Andric } 244*0fca6ea1SDimitry Andric return MI.isAsCheapAsAMove(); 245*0fca6ea1SDimitry Andric } 246*0fca6ea1SDimitry Andric 247bdd1243dSDimitry Andric MachineBasicBlock * 248bdd1243dSDimitry Andric LoongArchInstrInfo::getBranchDestBlock(const MachineInstr &MI) const { 249bdd1243dSDimitry Andric assert(MI.getDesc().isBranch() && "Unexpected opcode!"); 250bdd1243dSDimitry Andric // The branch target is always the last operand. 251bdd1243dSDimitry Andric return MI.getOperand(MI.getNumExplicitOperands() - 1).getMBB(); 252bdd1243dSDimitry Andric } 253bdd1243dSDimitry Andric 254bdd1243dSDimitry Andric static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target, 255bdd1243dSDimitry Andric SmallVectorImpl<MachineOperand> &Cond) { 256bdd1243dSDimitry Andric // Block ends with fall-through condbranch. 257bdd1243dSDimitry Andric assert(LastInst.getDesc().isConditionalBranch() && 258bdd1243dSDimitry Andric "Unknown conditional branch"); 259bdd1243dSDimitry Andric int NumOp = LastInst.getNumExplicitOperands(); 260bdd1243dSDimitry Andric Target = LastInst.getOperand(NumOp - 1).getMBB(); 261bdd1243dSDimitry Andric 262bdd1243dSDimitry Andric Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode())); 263bdd1243dSDimitry Andric for (int i = 0; i < NumOp - 1; i++) 264bdd1243dSDimitry Andric Cond.push_back(LastInst.getOperand(i)); 265bdd1243dSDimitry Andric } 266bdd1243dSDimitry Andric 267bdd1243dSDimitry Andric bool LoongArchInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 268bdd1243dSDimitry Andric MachineBasicBlock *&TBB, 269bdd1243dSDimitry Andric MachineBasicBlock *&FBB, 270bdd1243dSDimitry Andric SmallVectorImpl<MachineOperand> &Cond, 271bdd1243dSDimitry Andric bool AllowModify) const { 272bdd1243dSDimitry Andric TBB = FBB = nullptr; 273bdd1243dSDimitry Andric Cond.clear(); 274bdd1243dSDimitry Andric 275bdd1243dSDimitry Andric // If the block has no terminators, it just falls into the block after it. 276bdd1243dSDimitry Andric MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); 277bdd1243dSDimitry Andric if (I == MBB.end() || !isUnpredicatedTerminator(*I)) 278bdd1243dSDimitry Andric return false; 279bdd1243dSDimitry Andric 280bdd1243dSDimitry Andric // Count the number of terminators and find the first unconditional or 281bdd1243dSDimitry Andric // indirect branch. 282bdd1243dSDimitry Andric MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end(); 283bdd1243dSDimitry Andric int NumTerminators = 0; 284bdd1243dSDimitry Andric for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(*J); 285bdd1243dSDimitry Andric J++) { 286bdd1243dSDimitry Andric NumTerminators++; 287bdd1243dSDimitry Andric if (J->getDesc().isUnconditionalBranch() || 288bdd1243dSDimitry Andric J->getDesc().isIndirectBranch()) { 289bdd1243dSDimitry Andric FirstUncondOrIndirectBr = J.getReverse(); 290bdd1243dSDimitry Andric } 291bdd1243dSDimitry Andric } 292bdd1243dSDimitry Andric 293bdd1243dSDimitry Andric // If AllowModify is true, we can erase any terminators after 294bdd1243dSDimitry Andric // FirstUncondOrIndirectBR. 295bdd1243dSDimitry Andric if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) { 296bdd1243dSDimitry Andric while (std::next(FirstUncondOrIndirectBr) != MBB.end()) { 297bdd1243dSDimitry Andric std::next(FirstUncondOrIndirectBr)->eraseFromParent(); 298bdd1243dSDimitry Andric NumTerminators--; 299bdd1243dSDimitry Andric } 300bdd1243dSDimitry Andric I = FirstUncondOrIndirectBr; 301bdd1243dSDimitry Andric } 302bdd1243dSDimitry Andric 303bdd1243dSDimitry Andric // Handle a single unconditional branch. 304bdd1243dSDimitry Andric if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) { 305bdd1243dSDimitry Andric TBB = getBranchDestBlock(*I); 306bdd1243dSDimitry Andric return false; 307bdd1243dSDimitry Andric } 308bdd1243dSDimitry Andric 309bdd1243dSDimitry Andric // Handle a single conditional branch. 310bdd1243dSDimitry Andric if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) { 311bdd1243dSDimitry Andric parseCondBranch(*I, TBB, Cond); 312bdd1243dSDimitry Andric return false; 313bdd1243dSDimitry Andric } 314bdd1243dSDimitry Andric 315bdd1243dSDimitry Andric // Handle a conditional branch followed by an unconditional branch. 316bdd1243dSDimitry Andric if (NumTerminators == 2 && std::prev(I)->getDesc().isConditionalBranch() && 317bdd1243dSDimitry Andric I->getDesc().isUnconditionalBranch()) { 318bdd1243dSDimitry Andric parseCondBranch(*std::prev(I), TBB, Cond); 319bdd1243dSDimitry Andric FBB = getBranchDestBlock(*I); 320bdd1243dSDimitry Andric return false; 321bdd1243dSDimitry Andric } 322bdd1243dSDimitry Andric 323bdd1243dSDimitry Andric // Otherwise, we can't handle this. 324bdd1243dSDimitry Andric return true; 325bdd1243dSDimitry Andric } 326bdd1243dSDimitry Andric 327bdd1243dSDimitry Andric bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp, 328bdd1243dSDimitry Andric int64_t BrOffset) const { 329bdd1243dSDimitry Andric switch (BranchOp) { 330bdd1243dSDimitry Andric default: 331bdd1243dSDimitry Andric llvm_unreachable("Unknown branch instruction!"); 332bdd1243dSDimitry Andric case LoongArch::BEQ: 333bdd1243dSDimitry Andric case LoongArch::BNE: 334bdd1243dSDimitry Andric case LoongArch::BLT: 335bdd1243dSDimitry Andric case LoongArch::BGE: 336bdd1243dSDimitry Andric case LoongArch::BLTU: 337bdd1243dSDimitry Andric case LoongArch::BGEU: 338bdd1243dSDimitry Andric return isInt<18>(BrOffset); 339bdd1243dSDimitry Andric case LoongArch::BEQZ: 340bdd1243dSDimitry Andric case LoongArch::BNEZ: 341bdd1243dSDimitry Andric case LoongArch::BCEQZ: 342bdd1243dSDimitry Andric case LoongArch::BCNEZ: 343bdd1243dSDimitry Andric return isInt<23>(BrOffset); 344bdd1243dSDimitry Andric case LoongArch::B: 345bdd1243dSDimitry Andric case LoongArch::PseudoBR: 346bdd1243dSDimitry Andric return isInt<28>(BrOffset); 347bdd1243dSDimitry Andric } 348bdd1243dSDimitry Andric } 349bdd1243dSDimitry Andric 350bdd1243dSDimitry Andric unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB, 351bdd1243dSDimitry Andric int *BytesRemoved) const { 352bdd1243dSDimitry Andric if (BytesRemoved) 353bdd1243dSDimitry Andric *BytesRemoved = 0; 354bdd1243dSDimitry Andric MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); 355bdd1243dSDimitry Andric if (I == MBB.end()) 356bdd1243dSDimitry Andric return 0; 357bdd1243dSDimitry Andric 358bdd1243dSDimitry Andric if (!I->getDesc().isBranch()) 359bdd1243dSDimitry Andric return 0; 360bdd1243dSDimitry Andric 361bdd1243dSDimitry Andric // Remove the branch. 362bdd1243dSDimitry Andric if (BytesRemoved) 363bdd1243dSDimitry Andric *BytesRemoved += getInstSizeInBytes(*I); 364bdd1243dSDimitry Andric I->eraseFromParent(); 365bdd1243dSDimitry Andric 366bdd1243dSDimitry Andric I = MBB.end(); 367bdd1243dSDimitry Andric 368bdd1243dSDimitry Andric if (I == MBB.begin()) 369bdd1243dSDimitry Andric return 1; 370bdd1243dSDimitry Andric --I; 371bdd1243dSDimitry Andric if (!I->getDesc().isConditionalBranch()) 372bdd1243dSDimitry Andric return 1; 373bdd1243dSDimitry Andric 374bdd1243dSDimitry Andric // Remove the branch. 375bdd1243dSDimitry Andric if (BytesRemoved) 376bdd1243dSDimitry Andric *BytesRemoved += getInstSizeInBytes(*I); 377bdd1243dSDimitry Andric I->eraseFromParent(); 378bdd1243dSDimitry Andric return 2; 379bdd1243dSDimitry Andric } 380bdd1243dSDimitry Andric 381bdd1243dSDimitry Andric // Inserts a branch into the end of the specific MachineBasicBlock, returning 382bdd1243dSDimitry Andric // the number of instructions inserted. 383bdd1243dSDimitry Andric unsigned LoongArchInstrInfo::insertBranch( 384bdd1243dSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, 385bdd1243dSDimitry Andric ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { 386bdd1243dSDimitry Andric if (BytesAdded) 387bdd1243dSDimitry Andric *BytesAdded = 0; 388bdd1243dSDimitry Andric 389bdd1243dSDimitry Andric // Shouldn't be a fall through. 390bdd1243dSDimitry Andric assert(TBB && "insertBranch must not be told to insert a fallthrough"); 391bdd1243dSDimitry Andric assert(Cond.size() <= 3 && Cond.size() != 1 && 392bdd1243dSDimitry Andric "LoongArch branch conditions have at most two components!"); 393bdd1243dSDimitry Andric 394bdd1243dSDimitry Andric // Unconditional branch. 395bdd1243dSDimitry Andric if (Cond.empty()) { 396bdd1243dSDimitry Andric MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(TBB); 397bdd1243dSDimitry Andric if (BytesAdded) 398bdd1243dSDimitry Andric *BytesAdded += getInstSizeInBytes(MI); 399bdd1243dSDimitry Andric return 1; 400bdd1243dSDimitry Andric } 401bdd1243dSDimitry Andric 402bdd1243dSDimitry Andric // Either a one or two-way conditional branch. 403bdd1243dSDimitry Andric MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(Cond[0].getImm())); 404bdd1243dSDimitry Andric for (unsigned i = 1; i < Cond.size(); ++i) 405bdd1243dSDimitry Andric MIB.add(Cond[i]); 406bdd1243dSDimitry Andric MIB.addMBB(TBB); 407bdd1243dSDimitry Andric if (BytesAdded) 408bdd1243dSDimitry Andric *BytesAdded += getInstSizeInBytes(*MIB); 409bdd1243dSDimitry Andric 410bdd1243dSDimitry Andric // One-way conditional branch. 411bdd1243dSDimitry Andric if (!FBB) 412bdd1243dSDimitry Andric return 1; 413bdd1243dSDimitry Andric 414bdd1243dSDimitry Andric // Two-way conditional branch. 415bdd1243dSDimitry Andric MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(FBB); 416bdd1243dSDimitry Andric if (BytesAdded) 417bdd1243dSDimitry Andric *BytesAdded += getInstSizeInBytes(MI); 418bdd1243dSDimitry Andric return 2; 419bdd1243dSDimitry Andric } 420bdd1243dSDimitry Andric 421bdd1243dSDimitry Andric void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB, 422bdd1243dSDimitry Andric MachineBasicBlock &DestBB, 423bdd1243dSDimitry Andric MachineBasicBlock &RestoreBB, 424bdd1243dSDimitry Andric const DebugLoc &DL, 425bdd1243dSDimitry Andric int64_t BrOffset, 426bdd1243dSDimitry Andric RegScavenger *RS) const { 427bdd1243dSDimitry Andric assert(RS && "RegScavenger required for long branching"); 428bdd1243dSDimitry Andric assert(MBB.empty() && 429bdd1243dSDimitry Andric "new block should be inserted for expanding unconditional branch"); 430bdd1243dSDimitry Andric assert(MBB.pred_size() == 1); 431bdd1243dSDimitry Andric 432bdd1243dSDimitry Andric MachineFunction *MF = MBB.getParent(); 433bdd1243dSDimitry Andric MachineRegisterInfo &MRI = MF->getRegInfo(); 434bdd1243dSDimitry Andric const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); 435bdd1243dSDimitry Andric LoongArchMachineFunctionInfo *LAFI = 436bdd1243dSDimitry Andric MF->getInfo<LoongArchMachineFunctionInfo>(); 437bdd1243dSDimitry Andric 438bdd1243dSDimitry Andric if (!isInt<32>(BrOffset)) 439bdd1243dSDimitry Andric report_fatal_error( 440bdd1243dSDimitry Andric "Branch offsets outside of the signed 32-bit range not supported"); 441bdd1243dSDimitry Andric 442bdd1243dSDimitry Andric Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass); 443bdd1243dSDimitry Andric auto II = MBB.end(); 444bdd1243dSDimitry Andric 445bdd1243dSDimitry Andric MachineInstr &PCALAU12I = 446bdd1243dSDimitry Andric *BuildMI(MBB, II, DL, get(LoongArch::PCALAU12I), ScratchReg) 447bdd1243dSDimitry Andric .addMBB(&DestBB, LoongArchII::MO_PCREL_HI); 448bdd1243dSDimitry Andric MachineInstr &ADDI = 449bdd1243dSDimitry Andric *BuildMI(MBB, II, DL, 450bdd1243dSDimitry Andric get(STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W), 451bdd1243dSDimitry Andric ScratchReg) 452bdd1243dSDimitry Andric .addReg(ScratchReg) 453bdd1243dSDimitry Andric .addMBB(&DestBB, LoongArchII::MO_PCREL_LO); 454bdd1243dSDimitry Andric BuildMI(MBB, II, DL, get(LoongArch::PseudoBRIND)) 455bdd1243dSDimitry Andric .addReg(ScratchReg, RegState::Kill) 456bdd1243dSDimitry Andric .addImm(0); 457bdd1243dSDimitry Andric 458bdd1243dSDimitry Andric RS->enterBasicBlockEnd(MBB); 459bdd1243dSDimitry Andric Register Scav = RS->scavengeRegisterBackwards( 460bdd1243dSDimitry Andric LoongArch::GPRRegClass, PCALAU12I.getIterator(), /*RestoreAfter=*/false, 461bdd1243dSDimitry Andric /*SPAdj=*/0, /*AllowSpill=*/false); 462bdd1243dSDimitry Andric if (Scav != LoongArch::NoRegister) 463bdd1243dSDimitry Andric RS->setRegUsed(Scav); 464bdd1243dSDimitry Andric else { 465bdd1243dSDimitry Andric // When there is no scavenged register, it needs to specify a register. 466bdd1243dSDimitry Andric // Specify t8 register because it won't be used too often. 467bdd1243dSDimitry Andric Scav = LoongArch::R20; 468bdd1243dSDimitry Andric int FrameIndex = LAFI->getBranchRelaxationSpillFrameIndex(); 469bdd1243dSDimitry Andric if (FrameIndex == -1) 470bdd1243dSDimitry Andric report_fatal_error("The function size is incorrectly estimated."); 471bdd1243dSDimitry Andric storeRegToStackSlot(MBB, PCALAU12I, Scav, /*IsKill=*/true, FrameIndex, 472bdd1243dSDimitry Andric &LoongArch::GPRRegClass, TRI, Register()); 473bdd1243dSDimitry Andric TRI->eliminateFrameIndex(std::prev(PCALAU12I.getIterator()), 474bdd1243dSDimitry Andric /*SpAdj=*/0, /*FIOperandNum=*/1); 475bdd1243dSDimitry Andric PCALAU12I.getOperand(1).setMBB(&RestoreBB); 476bdd1243dSDimitry Andric ADDI.getOperand(2).setMBB(&RestoreBB); 477bdd1243dSDimitry Andric loadRegFromStackSlot(RestoreBB, RestoreBB.end(), Scav, FrameIndex, 478bdd1243dSDimitry Andric &LoongArch::GPRRegClass, TRI, Register()); 479bdd1243dSDimitry Andric TRI->eliminateFrameIndex(RestoreBB.back(), 480bdd1243dSDimitry Andric /*SpAdj=*/0, /*FIOperandNum=*/1); 481bdd1243dSDimitry Andric } 482bdd1243dSDimitry Andric MRI.replaceRegWith(ScratchReg, Scav); 483bdd1243dSDimitry Andric MRI.clearVirtRegs(); 484bdd1243dSDimitry Andric } 485bdd1243dSDimitry Andric 486bdd1243dSDimitry Andric static unsigned getOppositeBranchOpc(unsigned Opc) { 487bdd1243dSDimitry Andric switch (Opc) { 488bdd1243dSDimitry Andric default: 489bdd1243dSDimitry Andric llvm_unreachable("Unrecognized conditional branch"); 490bdd1243dSDimitry Andric case LoongArch::BEQ: 491bdd1243dSDimitry Andric return LoongArch::BNE; 492bdd1243dSDimitry Andric case LoongArch::BNE: 493bdd1243dSDimitry Andric return LoongArch::BEQ; 494bdd1243dSDimitry Andric case LoongArch::BEQZ: 495bdd1243dSDimitry Andric return LoongArch::BNEZ; 496bdd1243dSDimitry Andric case LoongArch::BNEZ: 497bdd1243dSDimitry Andric return LoongArch::BEQZ; 498bdd1243dSDimitry Andric case LoongArch::BCEQZ: 499bdd1243dSDimitry Andric return LoongArch::BCNEZ; 500bdd1243dSDimitry Andric case LoongArch::BCNEZ: 501bdd1243dSDimitry Andric return LoongArch::BCEQZ; 502bdd1243dSDimitry Andric case LoongArch::BLT: 503bdd1243dSDimitry Andric return LoongArch::BGE; 504bdd1243dSDimitry Andric case LoongArch::BGE: 505bdd1243dSDimitry Andric return LoongArch::BLT; 506bdd1243dSDimitry Andric case LoongArch::BLTU: 507bdd1243dSDimitry Andric return LoongArch::BGEU; 508bdd1243dSDimitry Andric case LoongArch::BGEU: 509bdd1243dSDimitry Andric return LoongArch::BLTU; 510bdd1243dSDimitry Andric } 511bdd1243dSDimitry Andric } 512bdd1243dSDimitry Andric 513bdd1243dSDimitry Andric bool LoongArchInstrInfo::reverseBranchCondition( 514bdd1243dSDimitry Andric SmallVectorImpl<MachineOperand> &Cond) const { 515bdd1243dSDimitry Andric assert((Cond.size() && Cond.size() <= 3) && "Invalid branch condition!"); 516bdd1243dSDimitry Andric Cond[0].setImm(getOppositeBranchOpc(Cond[0].getImm())); 517bdd1243dSDimitry Andric return false; 518bdd1243dSDimitry Andric } 519bdd1243dSDimitry Andric 520bdd1243dSDimitry Andric std::pair<unsigned, unsigned> 521bdd1243dSDimitry Andric LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const { 522bdd1243dSDimitry Andric return std::make_pair(TF, 0u); 523bdd1243dSDimitry Andric } 524bdd1243dSDimitry Andric 525bdd1243dSDimitry Andric ArrayRef<std::pair<unsigned, const char *>> 526bdd1243dSDimitry Andric LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const { 527bdd1243dSDimitry Andric using namespace LoongArchII; 528bdd1243dSDimitry Andric // TODO: Add more target flags. 529bdd1243dSDimitry Andric static const std::pair<unsigned, const char *> TargetFlags[] = { 530bdd1243dSDimitry Andric {MO_CALL, "loongarch-call"}, 531bdd1243dSDimitry Andric {MO_CALL_PLT, "loongarch-call-plt"}, 532bdd1243dSDimitry Andric {MO_PCREL_HI, "loongarch-pcrel-hi"}, 533bdd1243dSDimitry Andric {MO_PCREL_LO, "loongarch-pcrel-lo"}, 53406c3fb27SDimitry Andric {MO_PCREL64_LO, "loongarch-pcrel64-lo"}, 53506c3fb27SDimitry Andric {MO_PCREL64_HI, "loongarch-pcrel64-hi"}, 536bdd1243dSDimitry Andric {MO_GOT_PC_HI, "loongarch-got-pc-hi"}, 537bdd1243dSDimitry Andric {MO_GOT_PC_LO, "loongarch-got-pc-lo"}, 53806c3fb27SDimitry Andric {MO_GOT_PC64_LO, "loongarch-got-pc64-lo"}, 53906c3fb27SDimitry Andric {MO_GOT_PC64_HI, "loongarch-got-pc64-hi"}, 540bdd1243dSDimitry Andric {MO_LE_HI, "loongarch-le-hi"}, 541bdd1243dSDimitry Andric {MO_LE_LO, "loongarch-le-lo"}, 54206c3fb27SDimitry Andric {MO_LE64_LO, "loongarch-le64-lo"}, 54306c3fb27SDimitry Andric {MO_LE64_HI, "loongarch-le64-hi"}, 544bdd1243dSDimitry Andric {MO_IE_PC_HI, "loongarch-ie-pc-hi"}, 545bdd1243dSDimitry Andric {MO_IE_PC_LO, "loongarch-ie-pc-lo"}, 54606c3fb27SDimitry Andric {MO_IE_PC64_LO, "loongarch-ie-pc64-lo"}, 54706c3fb27SDimitry Andric {MO_IE_PC64_HI, "loongarch-ie-pc64-hi"}, 548*0fca6ea1SDimitry Andric {MO_DESC_PC_HI, "loongarch-desc-pc-hi"}, 549*0fca6ea1SDimitry Andric {MO_DESC_PC_LO, "loongarch-desc-pc-lo"}, 550*0fca6ea1SDimitry Andric {MO_DESC64_PC_LO, "loongarch-desc64-pc-lo"}, 551*0fca6ea1SDimitry Andric {MO_DESC64_PC_HI, "loongarch-desc64-pc-hi"}, 552*0fca6ea1SDimitry Andric {MO_DESC_LD, "loongarch-desc-ld"}, 553*0fca6ea1SDimitry Andric {MO_DESC_CALL, "loongarch-desc-call"}, 554bdd1243dSDimitry Andric {MO_LD_PC_HI, "loongarch-ld-pc-hi"}, 555bdd1243dSDimitry Andric {MO_GD_PC_HI, "loongarch-gd-pc-hi"}}; 556bdd1243dSDimitry Andric return ArrayRef(TargetFlags); 557bdd1243dSDimitry Andric } 558*0fca6ea1SDimitry Andric 559*0fca6ea1SDimitry Andric // Returns true if this is the sext.w pattern, addi.w rd, rs, 0. 560*0fca6ea1SDimitry Andric bool LoongArch::isSEXT_W(const MachineInstr &MI) { 561*0fca6ea1SDimitry Andric return MI.getOpcode() == LoongArch::ADDI_W && MI.getOperand(1).isReg() && 562*0fca6ea1SDimitry Andric MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0; 563*0fca6ea1SDimitry Andric } 564