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" 16*bdd1243dSDimitry Andric #include "LoongArchRegisterInfo.h" 17*bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h" 18*bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchMatInt.h" 19*bdd1243dSDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h" 2081ad6265SDimitry Andric 2181ad6265SDimitry Andric using namespace llvm; 2281ad6265SDimitry Andric 2381ad6265SDimitry Andric #define GET_INSTRINFO_CTOR_DTOR 2481ad6265SDimitry Andric #include "LoongArchGenInstrInfo.inc" 2581ad6265SDimitry Andric 2681ad6265SDimitry Andric LoongArchInstrInfo::LoongArchInstrInfo(LoongArchSubtarget &STI) 27753f127fSDimitry Andric : LoongArchGenInstrInfo(LoongArch::ADJCALLSTACKDOWN, 28*bdd1243dSDimitry Andric LoongArch::ADJCALLSTACKUP), 29*bdd1243dSDimitry Andric STI(STI) {} 3081ad6265SDimitry Andric 3181ad6265SDimitry Andric void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 3281ad6265SDimitry Andric MachineBasicBlock::iterator MBBI, 3381ad6265SDimitry Andric const DebugLoc &DL, MCRegister DstReg, 3481ad6265SDimitry Andric MCRegister SrcReg, bool KillSrc) const { 3581ad6265SDimitry Andric if (LoongArch::GPRRegClass.contains(DstReg, SrcReg)) { 3681ad6265SDimitry Andric BuildMI(MBB, MBBI, DL, get(LoongArch::OR), DstReg) 3781ad6265SDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)) 3881ad6265SDimitry Andric .addReg(LoongArch::R0); 3981ad6265SDimitry Andric return; 4081ad6265SDimitry Andric } 4181ad6265SDimitry Andric 42*bdd1243dSDimitry Andric // GPR->CFR copy. 43*bdd1243dSDimitry Andric if (LoongArch::CFRRegClass.contains(DstReg) && 44*bdd1243dSDimitry Andric LoongArch::GPRRegClass.contains(SrcReg)) { 45*bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, get(LoongArch::MOVGR2CF), DstReg) 46*bdd1243dSDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)); 47*bdd1243dSDimitry Andric return; 48*bdd1243dSDimitry Andric } 49*bdd1243dSDimitry Andric // CFR->GPR copy. 50*bdd1243dSDimitry Andric if (LoongArch::GPRRegClass.contains(DstReg) && 51*bdd1243dSDimitry Andric LoongArch::CFRRegClass.contains(SrcReg)) { 52*bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, get(LoongArch::MOVCF2GR), DstReg) 53*bdd1243dSDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)); 54*bdd1243dSDimitry Andric return; 55*bdd1243dSDimitry Andric } 56*bdd1243dSDimitry Andric 5781ad6265SDimitry Andric // FPR->FPR copies. 5881ad6265SDimitry Andric unsigned Opc; 5981ad6265SDimitry Andric if (LoongArch::FPR32RegClass.contains(DstReg, SrcReg)) { 6081ad6265SDimitry Andric Opc = LoongArch::FMOV_S; 6181ad6265SDimitry Andric } else if (LoongArch::FPR64RegClass.contains(DstReg, SrcReg)) { 6281ad6265SDimitry Andric Opc = LoongArch::FMOV_D; 6381ad6265SDimitry Andric } else { 6481ad6265SDimitry Andric // TODO: support other copies. 6581ad6265SDimitry Andric llvm_unreachable("Impossible reg-to-reg copy"); 6681ad6265SDimitry Andric } 6781ad6265SDimitry Andric 6881ad6265SDimitry Andric BuildMI(MBB, MBBI, DL, get(Opc), DstReg) 6981ad6265SDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)); 7081ad6265SDimitry Andric } 71753f127fSDimitry Andric 72753f127fSDimitry Andric void LoongArchInstrInfo::storeRegToStackSlot( 73753f127fSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register SrcReg, 74753f127fSDimitry Andric bool IsKill, int FI, const TargetRegisterClass *RC, 75*bdd1243dSDimitry Andric const TargetRegisterInfo *TRI, Register VReg) const { 76753f127fSDimitry Andric DebugLoc DL; 77753f127fSDimitry Andric if (I != MBB.end()) 78753f127fSDimitry Andric DL = I->getDebugLoc(); 79753f127fSDimitry Andric MachineFunction *MF = MBB.getParent(); 80753f127fSDimitry Andric MachineFrameInfo &MFI = MF->getFrameInfo(); 81753f127fSDimitry Andric 82753f127fSDimitry Andric unsigned Opcode; 83753f127fSDimitry Andric if (LoongArch::GPRRegClass.hasSubClassEq(RC)) 84753f127fSDimitry Andric Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32 85753f127fSDimitry Andric ? LoongArch::ST_W 86753f127fSDimitry Andric : LoongArch::ST_D; 87753f127fSDimitry Andric else if (LoongArch::FPR32RegClass.hasSubClassEq(RC)) 88753f127fSDimitry Andric Opcode = LoongArch::FST_S; 89753f127fSDimitry Andric else if (LoongArch::FPR64RegClass.hasSubClassEq(RC)) 90753f127fSDimitry Andric Opcode = LoongArch::FST_D; 91*bdd1243dSDimitry Andric else if (LoongArch::CFRRegClass.hasSubClassEq(RC)) 92*bdd1243dSDimitry Andric Opcode = LoongArch::PseudoST_CFR; 93753f127fSDimitry Andric else 94753f127fSDimitry Andric llvm_unreachable("Can't store this register to stack slot"); 95753f127fSDimitry Andric 96753f127fSDimitry Andric MachineMemOperand *MMO = MF->getMachineMemOperand( 97753f127fSDimitry Andric MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOStore, 98753f127fSDimitry Andric MFI.getObjectSize(FI), MFI.getObjectAlign(FI)); 99753f127fSDimitry Andric 100753f127fSDimitry Andric BuildMI(MBB, I, DL, get(Opcode)) 101753f127fSDimitry Andric .addReg(SrcReg, getKillRegState(IsKill)) 102753f127fSDimitry Andric .addFrameIndex(FI) 103753f127fSDimitry Andric .addImm(0) 104753f127fSDimitry Andric .addMemOperand(MMO); 105753f127fSDimitry Andric } 106753f127fSDimitry Andric 107*bdd1243dSDimitry Andric void LoongArchInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, 108*bdd1243dSDimitry Andric MachineBasicBlock::iterator I, 109*bdd1243dSDimitry Andric Register DstReg, int FI, 110*bdd1243dSDimitry Andric const TargetRegisterClass *RC, 111*bdd1243dSDimitry Andric const TargetRegisterInfo *TRI, 112*bdd1243dSDimitry Andric Register VReg) const { 113753f127fSDimitry Andric DebugLoc DL; 114753f127fSDimitry Andric if (I != MBB.end()) 115753f127fSDimitry Andric DL = I->getDebugLoc(); 116753f127fSDimitry Andric MachineFunction *MF = MBB.getParent(); 117753f127fSDimitry Andric MachineFrameInfo &MFI = MF->getFrameInfo(); 118753f127fSDimitry Andric 119753f127fSDimitry Andric unsigned Opcode; 120753f127fSDimitry Andric if (LoongArch::GPRRegClass.hasSubClassEq(RC)) 121753f127fSDimitry Andric Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32 122753f127fSDimitry Andric ? LoongArch::LD_W 123753f127fSDimitry Andric : LoongArch::LD_D; 124753f127fSDimitry Andric else if (LoongArch::FPR32RegClass.hasSubClassEq(RC)) 125753f127fSDimitry Andric Opcode = LoongArch::FLD_S; 126753f127fSDimitry Andric else if (LoongArch::FPR64RegClass.hasSubClassEq(RC)) 127753f127fSDimitry Andric Opcode = LoongArch::FLD_D; 128*bdd1243dSDimitry Andric else if (LoongArch::CFRRegClass.hasSubClassEq(RC)) 129*bdd1243dSDimitry Andric Opcode = LoongArch::PseudoLD_CFR; 130753f127fSDimitry Andric else 131753f127fSDimitry Andric llvm_unreachable("Can't load this register from stack slot"); 132753f127fSDimitry Andric 133753f127fSDimitry Andric MachineMemOperand *MMO = MF->getMachineMemOperand( 134753f127fSDimitry Andric MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad, 135753f127fSDimitry Andric MFI.getObjectSize(FI), MFI.getObjectAlign(FI)); 136753f127fSDimitry Andric 137753f127fSDimitry Andric BuildMI(MBB, I, DL, get(Opcode), DstReg) 138753f127fSDimitry Andric .addFrameIndex(FI) 139753f127fSDimitry Andric .addImm(0) 140753f127fSDimitry Andric .addMemOperand(MMO); 141753f127fSDimitry Andric } 142*bdd1243dSDimitry Andric 143*bdd1243dSDimitry Andric void LoongArchInstrInfo::movImm(MachineBasicBlock &MBB, 144*bdd1243dSDimitry Andric MachineBasicBlock::iterator MBBI, 145*bdd1243dSDimitry Andric const DebugLoc &DL, Register DstReg, 146*bdd1243dSDimitry Andric uint64_t Val, MachineInstr::MIFlag Flag) const { 147*bdd1243dSDimitry Andric Register SrcReg = LoongArch::R0; 148*bdd1243dSDimitry Andric 149*bdd1243dSDimitry Andric if (!STI.is64Bit() && !isInt<32>(Val)) 150*bdd1243dSDimitry Andric report_fatal_error("Should only materialize 32-bit constants for LA32"); 151*bdd1243dSDimitry Andric 152*bdd1243dSDimitry Andric auto Seq = LoongArchMatInt::generateInstSeq(Val); 153*bdd1243dSDimitry Andric assert(!Seq.empty()); 154*bdd1243dSDimitry Andric 155*bdd1243dSDimitry Andric for (auto &Inst : Seq) { 156*bdd1243dSDimitry Andric switch (Inst.Opc) { 157*bdd1243dSDimitry Andric case LoongArch::LU12I_W: 158*bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg) 159*bdd1243dSDimitry Andric .addImm(Inst.Imm) 160*bdd1243dSDimitry Andric .setMIFlag(Flag); 161*bdd1243dSDimitry Andric break; 162*bdd1243dSDimitry Andric case LoongArch::ADDI_W: 163*bdd1243dSDimitry Andric case LoongArch::ORI: 164*bdd1243dSDimitry Andric case LoongArch::LU32I_D: // "rj" is needed due to InstrInfo pattern 165*bdd1243dSDimitry Andric case LoongArch::LU52I_D: 166*bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg) 167*bdd1243dSDimitry Andric .addReg(SrcReg, RegState::Kill) 168*bdd1243dSDimitry Andric .addImm(Inst.Imm) 169*bdd1243dSDimitry Andric .setMIFlag(Flag); 170*bdd1243dSDimitry Andric break; 171*bdd1243dSDimitry Andric default: 172*bdd1243dSDimitry Andric assert(false && "Unknown insn emitted by LoongArchMatInt"); 173*bdd1243dSDimitry Andric } 174*bdd1243dSDimitry Andric 175*bdd1243dSDimitry Andric // Only the first instruction has $zero as its source. 176*bdd1243dSDimitry Andric SrcReg = DstReg; 177*bdd1243dSDimitry Andric } 178*bdd1243dSDimitry Andric } 179*bdd1243dSDimitry Andric 180*bdd1243dSDimitry Andric unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { 181*bdd1243dSDimitry Andric unsigned Opcode = MI.getOpcode(); 182*bdd1243dSDimitry Andric 183*bdd1243dSDimitry Andric if (Opcode == TargetOpcode::INLINEASM || 184*bdd1243dSDimitry Andric Opcode == TargetOpcode::INLINEASM_BR) { 185*bdd1243dSDimitry Andric const MachineFunction *MF = MI.getParent()->getParent(); 186*bdd1243dSDimitry Andric const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo(); 187*bdd1243dSDimitry Andric return getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI); 188*bdd1243dSDimitry Andric } 189*bdd1243dSDimitry Andric return MI.getDesc().getSize(); 190*bdd1243dSDimitry Andric } 191*bdd1243dSDimitry Andric 192*bdd1243dSDimitry Andric MachineBasicBlock * 193*bdd1243dSDimitry Andric LoongArchInstrInfo::getBranchDestBlock(const MachineInstr &MI) const { 194*bdd1243dSDimitry Andric assert(MI.getDesc().isBranch() && "Unexpected opcode!"); 195*bdd1243dSDimitry Andric // The branch target is always the last operand. 196*bdd1243dSDimitry Andric return MI.getOperand(MI.getNumExplicitOperands() - 1).getMBB(); 197*bdd1243dSDimitry Andric } 198*bdd1243dSDimitry Andric 199*bdd1243dSDimitry Andric static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target, 200*bdd1243dSDimitry Andric SmallVectorImpl<MachineOperand> &Cond) { 201*bdd1243dSDimitry Andric // Block ends with fall-through condbranch. 202*bdd1243dSDimitry Andric assert(LastInst.getDesc().isConditionalBranch() && 203*bdd1243dSDimitry Andric "Unknown conditional branch"); 204*bdd1243dSDimitry Andric int NumOp = LastInst.getNumExplicitOperands(); 205*bdd1243dSDimitry Andric Target = LastInst.getOperand(NumOp - 1).getMBB(); 206*bdd1243dSDimitry Andric 207*bdd1243dSDimitry Andric Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode())); 208*bdd1243dSDimitry Andric for (int i = 0; i < NumOp - 1; i++) 209*bdd1243dSDimitry Andric Cond.push_back(LastInst.getOperand(i)); 210*bdd1243dSDimitry Andric } 211*bdd1243dSDimitry Andric 212*bdd1243dSDimitry Andric bool LoongArchInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 213*bdd1243dSDimitry Andric MachineBasicBlock *&TBB, 214*bdd1243dSDimitry Andric MachineBasicBlock *&FBB, 215*bdd1243dSDimitry Andric SmallVectorImpl<MachineOperand> &Cond, 216*bdd1243dSDimitry Andric bool AllowModify) const { 217*bdd1243dSDimitry Andric TBB = FBB = nullptr; 218*bdd1243dSDimitry Andric Cond.clear(); 219*bdd1243dSDimitry Andric 220*bdd1243dSDimitry Andric // If the block has no terminators, it just falls into the block after it. 221*bdd1243dSDimitry Andric MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); 222*bdd1243dSDimitry Andric if (I == MBB.end() || !isUnpredicatedTerminator(*I)) 223*bdd1243dSDimitry Andric return false; 224*bdd1243dSDimitry Andric 225*bdd1243dSDimitry Andric // Count the number of terminators and find the first unconditional or 226*bdd1243dSDimitry Andric // indirect branch. 227*bdd1243dSDimitry Andric MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end(); 228*bdd1243dSDimitry Andric int NumTerminators = 0; 229*bdd1243dSDimitry Andric for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(*J); 230*bdd1243dSDimitry Andric J++) { 231*bdd1243dSDimitry Andric NumTerminators++; 232*bdd1243dSDimitry Andric if (J->getDesc().isUnconditionalBranch() || 233*bdd1243dSDimitry Andric J->getDesc().isIndirectBranch()) { 234*bdd1243dSDimitry Andric FirstUncondOrIndirectBr = J.getReverse(); 235*bdd1243dSDimitry Andric } 236*bdd1243dSDimitry Andric } 237*bdd1243dSDimitry Andric 238*bdd1243dSDimitry Andric // If AllowModify is true, we can erase any terminators after 239*bdd1243dSDimitry Andric // FirstUncondOrIndirectBR. 240*bdd1243dSDimitry Andric if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) { 241*bdd1243dSDimitry Andric while (std::next(FirstUncondOrIndirectBr) != MBB.end()) { 242*bdd1243dSDimitry Andric std::next(FirstUncondOrIndirectBr)->eraseFromParent(); 243*bdd1243dSDimitry Andric NumTerminators--; 244*bdd1243dSDimitry Andric } 245*bdd1243dSDimitry Andric I = FirstUncondOrIndirectBr; 246*bdd1243dSDimitry Andric } 247*bdd1243dSDimitry Andric 248*bdd1243dSDimitry Andric // Handle a single unconditional branch. 249*bdd1243dSDimitry Andric if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) { 250*bdd1243dSDimitry Andric TBB = getBranchDestBlock(*I); 251*bdd1243dSDimitry Andric return false; 252*bdd1243dSDimitry Andric } 253*bdd1243dSDimitry Andric 254*bdd1243dSDimitry Andric // Handle a single conditional branch. 255*bdd1243dSDimitry Andric if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) { 256*bdd1243dSDimitry Andric parseCondBranch(*I, TBB, Cond); 257*bdd1243dSDimitry Andric return false; 258*bdd1243dSDimitry Andric } 259*bdd1243dSDimitry Andric 260*bdd1243dSDimitry Andric // Handle a conditional branch followed by an unconditional branch. 261*bdd1243dSDimitry Andric if (NumTerminators == 2 && std::prev(I)->getDesc().isConditionalBranch() && 262*bdd1243dSDimitry Andric I->getDesc().isUnconditionalBranch()) { 263*bdd1243dSDimitry Andric parseCondBranch(*std::prev(I), TBB, Cond); 264*bdd1243dSDimitry Andric FBB = getBranchDestBlock(*I); 265*bdd1243dSDimitry Andric return false; 266*bdd1243dSDimitry Andric } 267*bdd1243dSDimitry Andric 268*bdd1243dSDimitry Andric // Otherwise, we can't handle this. 269*bdd1243dSDimitry Andric return true; 270*bdd1243dSDimitry Andric } 271*bdd1243dSDimitry Andric 272*bdd1243dSDimitry Andric bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp, 273*bdd1243dSDimitry Andric int64_t BrOffset) const { 274*bdd1243dSDimitry Andric switch (BranchOp) { 275*bdd1243dSDimitry Andric default: 276*bdd1243dSDimitry Andric llvm_unreachable("Unknown branch instruction!"); 277*bdd1243dSDimitry Andric case LoongArch::BEQ: 278*bdd1243dSDimitry Andric case LoongArch::BNE: 279*bdd1243dSDimitry Andric case LoongArch::BLT: 280*bdd1243dSDimitry Andric case LoongArch::BGE: 281*bdd1243dSDimitry Andric case LoongArch::BLTU: 282*bdd1243dSDimitry Andric case LoongArch::BGEU: 283*bdd1243dSDimitry Andric return isInt<18>(BrOffset); 284*bdd1243dSDimitry Andric case LoongArch::BEQZ: 285*bdd1243dSDimitry Andric case LoongArch::BNEZ: 286*bdd1243dSDimitry Andric case LoongArch::BCEQZ: 287*bdd1243dSDimitry Andric case LoongArch::BCNEZ: 288*bdd1243dSDimitry Andric return isInt<23>(BrOffset); 289*bdd1243dSDimitry Andric case LoongArch::B: 290*bdd1243dSDimitry Andric case LoongArch::PseudoBR: 291*bdd1243dSDimitry Andric return isInt<28>(BrOffset); 292*bdd1243dSDimitry Andric } 293*bdd1243dSDimitry Andric } 294*bdd1243dSDimitry Andric 295*bdd1243dSDimitry Andric unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB, 296*bdd1243dSDimitry Andric int *BytesRemoved) const { 297*bdd1243dSDimitry Andric if (BytesRemoved) 298*bdd1243dSDimitry Andric *BytesRemoved = 0; 299*bdd1243dSDimitry Andric MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); 300*bdd1243dSDimitry Andric if (I == MBB.end()) 301*bdd1243dSDimitry Andric return 0; 302*bdd1243dSDimitry Andric 303*bdd1243dSDimitry Andric if (!I->getDesc().isBranch()) 304*bdd1243dSDimitry Andric return 0; 305*bdd1243dSDimitry Andric 306*bdd1243dSDimitry Andric // Remove the branch. 307*bdd1243dSDimitry Andric if (BytesRemoved) 308*bdd1243dSDimitry Andric *BytesRemoved += getInstSizeInBytes(*I); 309*bdd1243dSDimitry Andric I->eraseFromParent(); 310*bdd1243dSDimitry Andric 311*bdd1243dSDimitry Andric I = MBB.end(); 312*bdd1243dSDimitry Andric 313*bdd1243dSDimitry Andric if (I == MBB.begin()) 314*bdd1243dSDimitry Andric return 1; 315*bdd1243dSDimitry Andric --I; 316*bdd1243dSDimitry Andric if (!I->getDesc().isConditionalBranch()) 317*bdd1243dSDimitry Andric return 1; 318*bdd1243dSDimitry Andric 319*bdd1243dSDimitry Andric // Remove the branch. 320*bdd1243dSDimitry Andric if (BytesRemoved) 321*bdd1243dSDimitry Andric *BytesRemoved += getInstSizeInBytes(*I); 322*bdd1243dSDimitry Andric I->eraseFromParent(); 323*bdd1243dSDimitry Andric return 2; 324*bdd1243dSDimitry Andric } 325*bdd1243dSDimitry Andric 326*bdd1243dSDimitry Andric // Inserts a branch into the end of the specific MachineBasicBlock, returning 327*bdd1243dSDimitry Andric // the number of instructions inserted. 328*bdd1243dSDimitry Andric unsigned LoongArchInstrInfo::insertBranch( 329*bdd1243dSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, 330*bdd1243dSDimitry Andric ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { 331*bdd1243dSDimitry Andric if (BytesAdded) 332*bdd1243dSDimitry Andric *BytesAdded = 0; 333*bdd1243dSDimitry Andric 334*bdd1243dSDimitry Andric // Shouldn't be a fall through. 335*bdd1243dSDimitry Andric assert(TBB && "insertBranch must not be told to insert a fallthrough"); 336*bdd1243dSDimitry Andric assert(Cond.size() <= 3 && Cond.size() != 1 && 337*bdd1243dSDimitry Andric "LoongArch branch conditions have at most two components!"); 338*bdd1243dSDimitry Andric 339*bdd1243dSDimitry Andric // Unconditional branch. 340*bdd1243dSDimitry Andric if (Cond.empty()) { 341*bdd1243dSDimitry Andric MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(TBB); 342*bdd1243dSDimitry Andric if (BytesAdded) 343*bdd1243dSDimitry Andric *BytesAdded += getInstSizeInBytes(MI); 344*bdd1243dSDimitry Andric return 1; 345*bdd1243dSDimitry Andric } 346*bdd1243dSDimitry Andric 347*bdd1243dSDimitry Andric // Either a one or two-way conditional branch. 348*bdd1243dSDimitry Andric MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(Cond[0].getImm())); 349*bdd1243dSDimitry Andric for (unsigned i = 1; i < Cond.size(); ++i) 350*bdd1243dSDimitry Andric MIB.add(Cond[i]); 351*bdd1243dSDimitry Andric MIB.addMBB(TBB); 352*bdd1243dSDimitry Andric if (BytesAdded) 353*bdd1243dSDimitry Andric *BytesAdded += getInstSizeInBytes(*MIB); 354*bdd1243dSDimitry Andric 355*bdd1243dSDimitry Andric // One-way conditional branch. 356*bdd1243dSDimitry Andric if (!FBB) 357*bdd1243dSDimitry Andric return 1; 358*bdd1243dSDimitry Andric 359*bdd1243dSDimitry Andric // Two-way conditional branch. 360*bdd1243dSDimitry Andric MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(FBB); 361*bdd1243dSDimitry Andric if (BytesAdded) 362*bdd1243dSDimitry Andric *BytesAdded += getInstSizeInBytes(MI); 363*bdd1243dSDimitry Andric return 2; 364*bdd1243dSDimitry Andric } 365*bdd1243dSDimitry Andric 366*bdd1243dSDimitry Andric void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB, 367*bdd1243dSDimitry Andric MachineBasicBlock &DestBB, 368*bdd1243dSDimitry Andric MachineBasicBlock &RestoreBB, 369*bdd1243dSDimitry Andric const DebugLoc &DL, 370*bdd1243dSDimitry Andric int64_t BrOffset, 371*bdd1243dSDimitry Andric RegScavenger *RS) const { 372*bdd1243dSDimitry Andric assert(RS && "RegScavenger required for long branching"); 373*bdd1243dSDimitry Andric assert(MBB.empty() && 374*bdd1243dSDimitry Andric "new block should be inserted for expanding unconditional branch"); 375*bdd1243dSDimitry Andric assert(MBB.pred_size() == 1); 376*bdd1243dSDimitry Andric 377*bdd1243dSDimitry Andric MachineFunction *MF = MBB.getParent(); 378*bdd1243dSDimitry Andric MachineRegisterInfo &MRI = MF->getRegInfo(); 379*bdd1243dSDimitry Andric const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); 380*bdd1243dSDimitry Andric LoongArchMachineFunctionInfo *LAFI = 381*bdd1243dSDimitry Andric MF->getInfo<LoongArchMachineFunctionInfo>(); 382*bdd1243dSDimitry Andric 383*bdd1243dSDimitry Andric if (!isInt<32>(BrOffset)) 384*bdd1243dSDimitry Andric report_fatal_error( 385*bdd1243dSDimitry Andric "Branch offsets outside of the signed 32-bit range not supported"); 386*bdd1243dSDimitry Andric 387*bdd1243dSDimitry Andric Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass); 388*bdd1243dSDimitry Andric auto II = MBB.end(); 389*bdd1243dSDimitry Andric 390*bdd1243dSDimitry Andric MachineInstr &PCALAU12I = 391*bdd1243dSDimitry Andric *BuildMI(MBB, II, DL, get(LoongArch::PCALAU12I), ScratchReg) 392*bdd1243dSDimitry Andric .addMBB(&DestBB, LoongArchII::MO_PCREL_HI); 393*bdd1243dSDimitry Andric MachineInstr &ADDI = 394*bdd1243dSDimitry Andric *BuildMI(MBB, II, DL, 395*bdd1243dSDimitry Andric get(STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W), 396*bdd1243dSDimitry Andric ScratchReg) 397*bdd1243dSDimitry Andric .addReg(ScratchReg) 398*bdd1243dSDimitry Andric .addMBB(&DestBB, LoongArchII::MO_PCREL_LO); 399*bdd1243dSDimitry Andric BuildMI(MBB, II, DL, get(LoongArch::PseudoBRIND)) 400*bdd1243dSDimitry Andric .addReg(ScratchReg, RegState::Kill) 401*bdd1243dSDimitry Andric .addImm(0); 402*bdd1243dSDimitry Andric 403*bdd1243dSDimitry Andric RS->enterBasicBlockEnd(MBB); 404*bdd1243dSDimitry Andric Register Scav = RS->scavengeRegisterBackwards( 405*bdd1243dSDimitry Andric LoongArch::GPRRegClass, PCALAU12I.getIterator(), /*RestoreAfter=*/false, 406*bdd1243dSDimitry Andric /*SPAdj=*/0, /*AllowSpill=*/false); 407*bdd1243dSDimitry Andric if (Scav != LoongArch::NoRegister) 408*bdd1243dSDimitry Andric RS->setRegUsed(Scav); 409*bdd1243dSDimitry Andric else { 410*bdd1243dSDimitry Andric // When there is no scavenged register, it needs to specify a register. 411*bdd1243dSDimitry Andric // Specify t8 register because it won't be used too often. 412*bdd1243dSDimitry Andric Scav = LoongArch::R20; 413*bdd1243dSDimitry Andric int FrameIndex = LAFI->getBranchRelaxationSpillFrameIndex(); 414*bdd1243dSDimitry Andric if (FrameIndex == -1) 415*bdd1243dSDimitry Andric report_fatal_error("The function size is incorrectly estimated."); 416*bdd1243dSDimitry Andric storeRegToStackSlot(MBB, PCALAU12I, Scav, /*IsKill=*/true, FrameIndex, 417*bdd1243dSDimitry Andric &LoongArch::GPRRegClass, TRI, Register()); 418*bdd1243dSDimitry Andric TRI->eliminateFrameIndex(std::prev(PCALAU12I.getIterator()), 419*bdd1243dSDimitry Andric /*SpAdj=*/0, /*FIOperandNum=*/1); 420*bdd1243dSDimitry Andric PCALAU12I.getOperand(1).setMBB(&RestoreBB); 421*bdd1243dSDimitry Andric ADDI.getOperand(2).setMBB(&RestoreBB); 422*bdd1243dSDimitry Andric loadRegFromStackSlot(RestoreBB, RestoreBB.end(), Scav, FrameIndex, 423*bdd1243dSDimitry Andric &LoongArch::GPRRegClass, TRI, Register()); 424*bdd1243dSDimitry Andric TRI->eliminateFrameIndex(RestoreBB.back(), 425*bdd1243dSDimitry Andric /*SpAdj=*/0, /*FIOperandNum=*/1); 426*bdd1243dSDimitry Andric } 427*bdd1243dSDimitry Andric MRI.replaceRegWith(ScratchReg, Scav); 428*bdd1243dSDimitry Andric MRI.clearVirtRegs(); 429*bdd1243dSDimitry Andric } 430*bdd1243dSDimitry Andric 431*bdd1243dSDimitry Andric static unsigned getOppositeBranchOpc(unsigned Opc) { 432*bdd1243dSDimitry Andric switch (Opc) { 433*bdd1243dSDimitry Andric default: 434*bdd1243dSDimitry Andric llvm_unreachable("Unrecognized conditional branch"); 435*bdd1243dSDimitry Andric case LoongArch::BEQ: 436*bdd1243dSDimitry Andric return LoongArch::BNE; 437*bdd1243dSDimitry Andric case LoongArch::BNE: 438*bdd1243dSDimitry Andric return LoongArch::BEQ; 439*bdd1243dSDimitry Andric case LoongArch::BEQZ: 440*bdd1243dSDimitry Andric return LoongArch::BNEZ; 441*bdd1243dSDimitry Andric case LoongArch::BNEZ: 442*bdd1243dSDimitry Andric return LoongArch::BEQZ; 443*bdd1243dSDimitry Andric case LoongArch::BCEQZ: 444*bdd1243dSDimitry Andric return LoongArch::BCNEZ; 445*bdd1243dSDimitry Andric case LoongArch::BCNEZ: 446*bdd1243dSDimitry Andric return LoongArch::BCEQZ; 447*bdd1243dSDimitry Andric case LoongArch::BLT: 448*bdd1243dSDimitry Andric return LoongArch::BGE; 449*bdd1243dSDimitry Andric case LoongArch::BGE: 450*bdd1243dSDimitry Andric return LoongArch::BLT; 451*bdd1243dSDimitry Andric case LoongArch::BLTU: 452*bdd1243dSDimitry Andric return LoongArch::BGEU; 453*bdd1243dSDimitry Andric case LoongArch::BGEU: 454*bdd1243dSDimitry Andric return LoongArch::BLTU; 455*bdd1243dSDimitry Andric } 456*bdd1243dSDimitry Andric } 457*bdd1243dSDimitry Andric 458*bdd1243dSDimitry Andric bool LoongArchInstrInfo::reverseBranchCondition( 459*bdd1243dSDimitry Andric SmallVectorImpl<MachineOperand> &Cond) const { 460*bdd1243dSDimitry Andric assert((Cond.size() && Cond.size() <= 3) && "Invalid branch condition!"); 461*bdd1243dSDimitry Andric Cond[0].setImm(getOppositeBranchOpc(Cond[0].getImm())); 462*bdd1243dSDimitry Andric return false; 463*bdd1243dSDimitry Andric } 464*bdd1243dSDimitry Andric 465*bdd1243dSDimitry Andric std::pair<unsigned, unsigned> 466*bdd1243dSDimitry Andric LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const { 467*bdd1243dSDimitry Andric return std::make_pair(TF, 0u); 468*bdd1243dSDimitry Andric } 469*bdd1243dSDimitry Andric 470*bdd1243dSDimitry Andric ArrayRef<std::pair<unsigned, const char *>> 471*bdd1243dSDimitry Andric LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const { 472*bdd1243dSDimitry Andric using namespace LoongArchII; 473*bdd1243dSDimitry Andric // TODO: Add more target flags. 474*bdd1243dSDimitry Andric static const std::pair<unsigned, const char *> TargetFlags[] = { 475*bdd1243dSDimitry Andric {MO_CALL, "loongarch-call"}, 476*bdd1243dSDimitry Andric {MO_CALL_PLT, "loongarch-call-plt"}, 477*bdd1243dSDimitry Andric {MO_PCREL_HI, "loongarch-pcrel-hi"}, 478*bdd1243dSDimitry Andric {MO_PCREL_LO, "loongarch-pcrel-lo"}, 479*bdd1243dSDimitry Andric {MO_GOT_PC_HI, "loongarch-got-pc-hi"}, 480*bdd1243dSDimitry Andric {MO_GOT_PC_LO, "loongarch-got-pc-lo"}, 481*bdd1243dSDimitry Andric {MO_LE_HI, "loongarch-le-hi"}, 482*bdd1243dSDimitry Andric {MO_LE_LO, "loongarch-le-lo"}, 483*bdd1243dSDimitry Andric {MO_IE_PC_HI, "loongarch-ie-pc-hi"}, 484*bdd1243dSDimitry Andric {MO_IE_PC_LO, "loongarch-ie-pc-lo"}, 485*bdd1243dSDimitry Andric {MO_LD_PC_HI, "loongarch-ld-pc-hi"}, 486*bdd1243dSDimitry Andric {MO_GD_PC_HI, "loongarch-gd-pc-hi"}}; 487*bdd1243dSDimitry Andric return ArrayRef(TargetFlags); 488*bdd1243dSDimitry Andric } 489