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
LoongArchInstrInfo(LoongArchSubtarget & STI)2781ad6265SDimitry Andric LoongArchInstrInfo::LoongArchInstrInfo(LoongArchSubtarget &STI)
28753f127fSDimitry Andric : LoongArchGenInstrInfo(LoongArch::ADJCALLSTACKDOWN,
29bdd1243dSDimitry Andric LoongArch::ADJCALLSTACKUP),
30bdd1243dSDimitry Andric STI(STI) {}
3181ad6265SDimitry Andric
getNop() const3206c3fb27SDimitry 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
copyPhysReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,const DebugLoc & DL,MCRegister DstReg,MCRegister SrcReg,bool KillSrc) const3981ad6265SDimitry 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
storeRegToStackSlot(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,Register SrcReg,bool IsKill,int FI,const TargetRegisterClass * RC,const TargetRegisterInfo * TRI,Register VReg) const110753f127fSDimitry 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
loadRegFromStackSlot(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,Register DstReg,int FI,const TargetRegisterClass * RC,const TargetRegisterInfo * TRI,Register VReg) const146bdd1243dSDimitry 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
movImm(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,const DebugLoc & DL,Register DstReg,uint64_t Val,MachineInstr::MIFlag Flag) const183bdd1243dSDimitry 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
getInstSizeInBytes(const MachineInstr & MI) const220bdd1243dSDimitry 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
isAsCheapAsAMove(const MachineInstr & MI) const232*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 *
getBranchDestBlock(const MachineInstr & MI) const248bdd1243dSDimitry 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
parseCondBranch(MachineInstr & LastInst,MachineBasicBlock * & Target,SmallVectorImpl<MachineOperand> & Cond)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
analyzeBranch(MachineBasicBlock & MBB,MachineBasicBlock * & TBB,MachineBasicBlock * & FBB,SmallVectorImpl<MachineOperand> & Cond,bool AllowModify) const267bdd1243dSDimitry 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
isBranchOffsetInRange(unsigned BranchOp,int64_t BrOffset) const327bdd1243dSDimitry 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
removeBranch(MachineBasicBlock & MBB,int * BytesRemoved) const350bdd1243dSDimitry 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.
insertBranch(MachineBasicBlock & MBB,MachineBasicBlock * TBB,MachineBasicBlock * FBB,ArrayRef<MachineOperand> Cond,const DebugLoc & DL,int * BytesAdded) const383bdd1243dSDimitry 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
insertIndirectBranch(MachineBasicBlock & MBB,MachineBasicBlock & DestBB,MachineBasicBlock & RestoreBB,const DebugLoc & DL,int64_t BrOffset,RegScavenger * RS) const421bdd1243dSDimitry 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
getOppositeBranchOpc(unsigned Opc)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
reverseBranchCondition(SmallVectorImpl<MachineOperand> & Cond) const513bdd1243dSDimitry 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>
decomposeMachineOperandsTargetFlags(unsigned TF) const521bdd1243dSDimitry 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 *>>
getSerializableDirectMachineOperandTargetFlags() const526bdd1243dSDimitry 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.
isSEXT_W(const MachineInstr & MI)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