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