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