1 //=- LoongArchInstrInfo.cpp - LoongArch Instruction Information -*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains the LoongArch implementation of the TargetInstrInfo class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "LoongArchInstrInfo.h"
14 #include "LoongArch.h"
15 #include "LoongArchMachineFunctionInfo.h"
16 #include "LoongArchRegisterInfo.h"
17 #include "MCTargetDesc/LoongArchMCTargetDesc.h"
18 #include "MCTargetDesc/LoongArchMatInt.h"
19 #include "llvm/CodeGen/RegisterScavenging.h"
20 #include "llvm/MC/MCInstBuilder.h"
21 
22 using namespace llvm;
23 
24 #define GET_INSTRINFO_CTOR_DTOR
25 #include "LoongArchGenInstrInfo.inc"
26 
27 LoongArchInstrInfo::LoongArchInstrInfo(LoongArchSubtarget &STI)
28     : LoongArchGenInstrInfo(LoongArch::ADJCALLSTACKDOWN,
29                             LoongArch::ADJCALLSTACKUP),
30       STI(STI) {}
31 
32 MCInst LoongArchInstrInfo::getNop() const {
33   return MCInstBuilder(LoongArch::ANDI)
34       .addReg(LoongArch::R0)
35       .addReg(LoongArch::R0)
36       .addImm(0);
37 }
38 
39 void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
40                                      MachineBasicBlock::iterator MBBI,
41                                      const DebugLoc &DL, MCRegister DstReg,
42                                      MCRegister SrcReg, bool KillSrc) const {
43   if (LoongArch::GPRRegClass.contains(DstReg, SrcReg)) {
44     BuildMI(MBB, MBBI, DL, get(LoongArch::OR), DstReg)
45         .addReg(SrcReg, getKillRegState(KillSrc))
46         .addReg(LoongArch::R0);
47     return;
48   }
49 
50   // GPR->CFR copy.
51   if (LoongArch::CFRRegClass.contains(DstReg) &&
52       LoongArch::GPRRegClass.contains(SrcReg)) {
53     BuildMI(MBB, MBBI, DL, get(LoongArch::MOVGR2CF), DstReg)
54         .addReg(SrcReg, getKillRegState(KillSrc));
55     return;
56   }
57   // CFR->GPR copy.
58   if (LoongArch::GPRRegClass.contains(DstReg) &&
59       LoongArch::CFRRegClass.contains(SrcReg)) {
60     BuildMI(MBB, MBBI, DL, get(LoongArch::MOVCF2GR), DstReg)
61         .addReg(SrcReg, getKillRegState(KillSrc));
62     return;
63   }
64 
65   // FPR->FPR copies.
66   unsigned Opc;
67   if (LoongArch::FPR32RegClass.contains(DstReg, SrcReg)) {
68     Opc = LoongArch::FMOV_S;
69   } else if (LoongArch::FPR64RegClass.contains(DstReg, SrcReg)) {
70     Opc = LoongArch::FMOV_D;
71   } else {
72     // TODO: support other copies.
73     llvm_unreachable("Impossible reg-to-reg copy");
74   }
75 
76   BuildMI(MBB, MBBI, DL, get(Opc), DstReg)
77       .addReg(SrcReg, getKillRegState(KillSrc));
78 }
79 
80 void LoongArchInstrInfo::storeRegToStackSlot(
81     MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register SrcReg,
82     bool IsKill, int FI, const TargetRegisterClass *RC,
83     const TargetRegisterInfo *TRI, Register VReg) const {
84   MachineFunction *MF = MBB.getParent();
85   MachineFrameInfo &MFI = MF->getFrameInfo();
86 
87   unsigned Opcode;
88   if (LoongArch::GPRRegClass.hasSubClassEq(RC))
89     Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32
90                  ? LoongArch::ST_W
91                  : LoongArch::ST_D;
92   else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))
93     Opcode = LoongArch::FST_S;
94   else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))
95     Opcode = LoongArch::FST_D;
96   else if (LoongArch::CFRRegClass.hasSubClassEq(RC))
97     Opcode = LoongArch::PseudoST_CFR;
98   else
99     llvm_unreachable("Can't store this register to stack slot");
100 
101   MachineMemOperand *MMO = MF->getMachineMemOperand(
102       MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOStore,
103       MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
104 
105   BuildMI(MBB, I, DebugLoc(), get(Opcode))
106       .addReg(SrcReg, getKillRegState(IsKill))
107       .addFrameIndex(FI)
108       .addImm(0)
109       .addMemOperand(MMO);
110 }
111 
112 void LoongArchInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
113                                               MachineBasicBlock::iterator I,
114                                               Register DstReg, int FI,
115                                               const TargetRegisterClass *RC,
116                                               const TargetRegisterInfo *TRI,
117                                               Register VReg) const {
118   MachineFunction *MF = MBB.getParent();
119   MachineFrameInfo &MFI = MF->getFrameInfo();
120 
121   unsigned Opcode;
122   if (LoongArch::GPRRegClass.hasSubClassEq(RC))
123     Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32
124                  ? LoongArch::LD_W
125                  : LoongArch::LD_D;
126   else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))
127     Opcode = LoongArch::FLD_S;
128   else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))
129     Opcode = LoongArch::FLD_D;
130   else if (LoongArch::CFRRegClass.hasSubClassEq(RC))
131     Opcode = LoongArch::PseudoLD_CFR;
132   else
133     llvm_unreachable("Can't load this register from stack slot");
134 
135   MachineMemOperand *MMO = MF->getMachineMemOperand(
136       MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad,
137       MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
138 
139   BuildMI(MBB, I, DebugLoc(), get(Opcode), DstReg)
140       .addFrameIndex(FI)
141       .addImm(0)
142       .addMemOperand(MMO);
143 }
144 
145 void LoongArchInstrInfo::movImm(MachineBasicBlock &MBB,
146                                 MachineBasicBlock::iterator MBBI,
147                                 const DebugLoc &DL, Register DstReg,
148                                 uint64_t Val, MachineInstr::MIFlag Flag) const {
149   Register SrcReg = LoongArch::R0;
150 
151   if (!STI.is64Bit() && !isInt<32>(Val))
152     report_fatal_error("Should only materialize 32-bit constants for LA32");
153 
154   auto Seq = LoongArchMatInt::generateInstSeq(Val);
155   assert(!Seq.empty());
156 
157   for (auto &Inst : Seq) {
158     switch (Inst.Opc) {
159     case LoongArch::LU12I_W:
160       BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)
161           .addImm(Inst.Imm)
162           .setMIFlag(Flag);
163       break;
164     case LoongArch::ADDI_W:
165     case LoongArch::ORI:
166     case LoongArch::LU32I_D: // "rj" is needed due to InstrInfo pattern
167     case LoongArch::LU52I_D:
168       BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)
169           .addReg(SrcReg, RegState::Kill)
170           .addImm(Inst.Imm)
171           .setMIFlag(Flag);
172       break;
173     default:
174       assert(false && "Unknown insn emitted by LoongArchMatInt");
175     }
176 
177     // Only the first instruction has $zero as its source.
178     SrcReg = DstReg;
179   }
180 }
181 
182 unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
183   unsigned Opcode = MI.getOpcode();
184 
185   if (Opcode == TargetOpcode::INLINEASM ||
186       Opcode == TargetOpcode::INLINEASM_BR) {
187     const MachineFunction *MF = MI.getParent()->getParent();
188     const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
189     return getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI);
190   }
191   return MI.getDesc().getSize();
192 }
193 
194 MachineBasicBlock *
195 LoongArchInstrInfo::getBranchDestBlock(const MachineInstr &MI) const {
196   assert(MI.getDesc().isBranch() && "Unexpected opcode!");
197   // The branch target is always the last operand.
198   return MI.getOperand(MI.getNumExplicitOperands() - 1).getMBB();
199 }
200 
201 static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target,
202                             SmallVectorImpl<MachineOperand> &Cond) {
203   // Block ends with fall-through condbranch.
204   assert(LastInst.getDesc().isConditionalBranch() &&
205          "Unknown conditional branch");
206   int NumOp = LastInst.getNumExplicitOperands();
207   Target = LastInst.getOperand(NumOp - 1).getMBB();
208 
209   Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode()));
210   for (int i = 0; i < NumOp - 1; i++)
211     Cond.push_back(LastInst.getOperand(i));
212 }
213 
214 bool LoongArchInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
215                                        MachineBasicBlock *&TBB,
216                                        MachineBasicBlock *&FBB,
217                                        SmallVectorImpl<MachineOperand> &Cond,
218                                        bool AllowModify) const {
219   TBB = FBB = nullptr;
220   Cond.clear();
221 
222   // If the block has no terminators, it just falls into the block after it.
223   MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
224   if (I == MBB.end() || !isUnpredicatedTerminator(*I))
225     return false;
226 
227   // Count the number of terminators and find the first unconditional or
228   // indirect branch.
229   MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end();
230   int NumTerminators = 0;
231   for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(*J);
232        J++) {
233     NumTerminators++;
234     if (J->getDesc().isUnconditionalBranch() ||
235         J->getDesc().isIndirectBranch()) {
236       FirstUncondOrIndirectBr = J.getReverse();
237     }
238   }
239 
240   // If AllowModify is true, we can erase any terminators after
241   // FirstUncondOrIndirectBR.
242   if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) {
243     while (std::next(FirstUncondOrIndirectBr) != MBB.end()) {
244       std::next(FirstUncondOrIndirectBr)->eraseFromParent();
245       NumTerminators--;
246     }
247     I = FirstUncondOrIndirectBr;
248   }
249 
250   // Handle a single unconditional branch.
251   if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) {
252     TBB = getBranchDestBlock(*I);
253     return false;
254   }
255 
256   // Handle a single conditional branch.
257   if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) {
258     parseCondBranch(*I, TBB, Cond);
259     return false;
260   }
261 
262   // Handle a conditional branch followed by an unconditional branch.
263   if (NumTerminators == 2 && std::prev(I)->getDesc().isConditionalBranch() &&
264       I->getDesc().isUnconditionalBranch()) {
265     parseCondBranch(*std::prev(I), TBB, Cond);
266     FBB = getBranchDestBlock(*I);
267     return false;
268   }
269 
270   // Otherwise, we can't handle this.
271   return true;
272 }
273 
274 bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
275                                                int64_t BrOffset) const {
276   switch (BranchOp) {
277   default:
278     llvm_unreachable("Unknown branch instruction!");
279   case LoongArch::BEQ:
280   case LoongArch::BNE:
281   case LoongArch::BLT:
282   case LoongArch::BGE:
283   case LoongArch::BLTU:
284   case LoongArch::BGEU:
285     return isInt<18>(BrOffset);
286   case LoongArch::BEQZ:
287   case LoongArch::BNEZ:
288   case LoongArch::BCEQZ:
289   case LoongArch::BCNEZ:
290     return isInt<23>(BrOffset);
291   case LoongArch::B:
292   case LoongArch::PseudoBR:
293     return isInt<28>(BrOffset);
294   }
295 }
296 
297 unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB,
298                                           int *BytesRemoved) const {
299   if (BytesRemoved)
300     *BytesRemoved = 0;
301   MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
302   if (I == MBB.end())
303     return 0;
304 
305   if (!I->getDesc().isBranch())
306     return 0;
307 
308   // Remove the branch.
309   if (BytesRemoved)
310     *BytesRemoved += getInstSizeInBytes(*I);
311   I->eraseFromParent();
312 
313   I = MBB.end();
314 
315   if (I == MBB.begin())
316     return 1;
317   --I;
318   if (!I->getDesc().isConditionalBranch())
319     return 1;
320 
321   // Remove the branch.
322   if (BytesRemoved)
323     *BytesRemoved += getInstSizeInBytes(*I);
324   I->eraseFromParent();
325   return 2;
326 }
327 
328 // Inserts a branch into the end of the specific MachineBasicBlock, returning
329 // the number of instructions inserted.
330 unsigned LoongArchInstrInfo::insertBranch(
331     MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
332     ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
333   if (BytesAdded)
334     *BytesAdded = 0;
335 
336   // Shouldn't be a fall through.
337   assert(TBB && "insertBranch must not be told to insert a fallthrough");
338   assert(Cond.size() <= 3 && Cond.size() != 1 &&
339          "LoongArch branch conditions have at most two components!");
340 
341   // Unconditional branch.
342   if (Cond.empty()) {
343     MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(TBB);
344     if (BytesAdded)
345       *BytesAdded += getInstSizeInBytes(MI);
346     return 1;
347   }
348 
349   // Either a one or two-way conditional branch.
350   MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(Cond[0].getImm()));
351   for (unsigned i = 1; i < Cond.size(); ++i)
352     MIB.add(Cond[i]);
353   MIB.addMBB(TBB);
354   if (BytesAdded)
355     *BytesAdded += getInstSizeInBytes(*MIB);
356 
357   // One-way conditional branch.
358   if (!FBB)
359     return 1;
360 
361   // Two-way conditional branch.
362   MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(FBB);
363   if (BytesAdded)
364     *BytesAdded += getInstSizeInBytes(MI);
365   return 2;
366 }
367 
368 void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,
369                                               MachineBasicBlock &DestBB,
370                                               MachineBasicBlock &RestoreBB,
371                                               const DebugLoc &DL,
372                                               int64_t BrOffset,
373                                               RegScavenger *RS) const {
374   assert(RS && "RegScavenger required for long branching");
375   assert(MBB.empty() &&
376          "new block should be inserted for expanding unconditional branch");
377   assert(MBB.pred_size() == 1);
378 
379   MachineFunction *MF = MBB.getParent();
380   MachineRegisterInfo &MRI = MF->getRegInfo();
381   const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
382   LoongArchMachineFunctionInfo *LAFI =
383       MF->getInfo<LoongArchMachineFunctionInfo>();
384 
385   if (!isInt<32>(BrOffset))
386     report_fatal_error(
387         "Branch offsets outside of the signed 32-bit range not supported");
388 
389   Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
390   auto II = MBB.end();
391 
392   MachineInstr &PCALAU12I =
393       *BuildMI(MBB, II, DL, get(LoongArch::PCALAU12I), ScratchReg)
394            .addMBB(&DestBB, LoongArchII::MO_PCREL_HI);
395   MachineInstr &ADDI =
396       *BuildMI(MBB, II, DL,
397                get(STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W),
398                ScratchReg)
399            .addReg(ScratchReg)
400            .addMBB(&DestBB, LoongArchII::MO_PCREL_LO);
401   BuildMI(MBB, II, DL, get(LoongArch::PseudoBRIND))
402       .addReg(ScratchReg, RegState::Kill)
403       .addImm(0);
404 
405   RS->enterBasicBlockEnd(MBB);
406   Register Scav = RS->scavengeRegisterBackwards(
407       LoongArch::GPRRegClass, PCALAU12I.getIterator(), /*RestoreAfter=*/false,
408       /*SPAdj=*/0, /*AllowSpill=*/false);
409   if (Scav != LoongArch::NoRegister)
410     RS->setRegUsed(Scav);
411   else {
412     // When there is no scavenged register, it needs to specify a register.
413     // Specify t8 register because it won't be used too often.
414     Scav = LoongArch::R20;
415     int FrameIndex = LAFI->getBranchRelaxationSpillFrameIndex();
416     if (FrameIndex == -1)
417       report_fatal_error("The function size is incorrectly estimated.");
418     storeRegToStackSlot(MBB, PCALAU12I, Scav, /*IsKill=*/true, FrameIndex,
419                         &LoongArch::GPRRegClass, TRI, Register());
420     TRI->eliminateFrameIndex(std::prev(PCALAU12I.getIterator()),
421                              /*SpAdj=*/0, /*FIOperandNum=*/1);
422     PCALAU12I.getOperand(1).setMBB(&RestoreBB);
423     ADDI.getOperand(2).setMBB(&RestoreBB);
424     loadRegFromStackSlot(RestoreBB, RestoreBB.end(), Scav, FrameIndex,
425                          &LoongArch::GPRRegClass, TRI, Register());
426     TRI->eliminateFrameIndex(RestoreBB.back(),
427                              /*SpAdj=*/0, /*FIOperandNum=*/1);
428   }
429   MRI.replaceRegWith(ScratchReg, Scav);
430   MRI.clearVirtRegs();
431 }
432 
433 static unsigned getOppositeBranchOpc(unsigned Opc) {
434   switch (Opc) {
435   default:
436     llvm_unreachable("Unrecognized conditional branch");
437   case LoongArch::BEQ:
438     return LoongArch::BNE;
439   case LoongArch::BNE:
440     return LoongArch::BEQ;
441   case LoongArch::BEQZ:
442     return LoongArch::BNEZ;
443   case LoongArch::BNEZ:
444     return LoongArch::BEQZ;
445   case LoongArch::BCEQZ:
446     return LoongArch::BCNEZ;
447   case LoongArch::BCNEZ:
448     return LoongArch::BCEQZ;
449   case LoongArch::BLT:
450     return LoongArch::BGE;
451   case LoongArch::BGE:
452     return LoongArch::BLT;
453   case LoongArch::BLTU:
454     return LoongArch::BGEU;
455   case LoongArch::BGEU:
456     return LoongArch::BLTU;
457   }
458 }
459 
460 bool LoongArchInstrInfo::reverseBranchCondition(
461     SmallVectorImpl<MachineOperand> &Cond) const {
462   assert((Cond.size() && Cond.size() <= 3) && "Invalid branch condition!");
463   Cond[0].setImm(getOppositeBranchOpc(Cond[0].getImm()));
464   return false;
465 }
466 
467 std::pair<unsigned, unsigned>
468 LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
469   return std::make_pair(TF, 0u);
470 }
471 
472 ArrayRef<std::pair<unsigned, const char *>>
473 LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
474   using namespace LoongArchII;
475   // TODO: Add more target flags.
476   static const std::pair<unsigned, const char *> TargetFlags[] = {
477       {MO_CALL, "loongarch-call"},
478       {MO_CALL_PLT, "loongarch-call-plt"},
479       {MO_PCREL_HI, "loongarch-pcrel-hi"},
480       {MO_PCREL_LO, "loongarch-pcrel-lo"},
481       {MO_PCREL64_LO, "loongarch-pcrel64-lo"},
482       {MO_PCREL64_HI, "loongarch-pcrel64-hi"},
483       {MO_GOT_PC_HI, "loongarch-got-pc-hi"},
484       {MO_GOT_PC_LO, "loongarch-got-pc-lo"},
485       {MO_GOT_PC64_LO, "loongarch-got-pc64-lo"},
486       {MO_GOT_PC64_HI, "loongarch-got-pc64-hi"},
487       {MO_LE_HI, "loongarch-le-hi"},
488       {MO_LE_LO, "loongarch-le-lo"},
489       {MO_LE64_LO, "loongarch-le64-lo"},
490       {MO_LE64_HI, "loongarch-le64-hi"},
491       {MO_IE_PC_HI, "loongarch-ie-pc-hi"},
492       {MO_IE_PC_LO, "loongarch-ie-pc-lo"},
493       {MO_IE_PC64_LO, "loongarch-ie-pc64-lo"},
494       {MO_IE_PC64_HI, "loongarch-ie-pc64-hi"},
495       {MO_LD_PC_HI, "loongarch-ld-pc-hi"},
496       {MO_GD_PC_HI, "loongarch-gd-pc-hi"}};
497   return ArrayRef(TargetFlags);
498 }
499