xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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