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