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