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