1 //===-- LoongArchExpandPseudoInsts.cpp - Expand pseudo instructions -------===//
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 a pass that expands pseudo instructions into target
10 // instructions.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "LoongArch.h"
15 #include "LoongArchInstrInfo.h"
16 #include "LoongArchTargetMachine.h"
17 #include "MCTargetDesc/LoongArchBaseInfo.h"
18 #include "MCTargetDesc/LoongArchMCTargetDesc.h"
19 #include "llvm/CodeGen/LivePhysRegs.h"
20 #include "llvm/CodeGen/MachineFunctionPass.h"
21 #include "llvm/CodeGen/MachineInstrBuilder.h"
22 #include "llvm/CodeGen/MachineOperand.h"
23 #include "llvm/CodeGen/Register.h"
24 #include "llvm/MC/MCContext.h"
25 #include "llvm/Support/CodeGen.h"
26 #include "llvm/Support/ErrorHandling.h"
27 
28 using namespace llvm;
29 
30 #define LOONGARCH_PRERA_EXPAND_PSEUDO_NAME                                     \
31   "LoongArch Pre-RA pseudo instruction expansion pass"
32 #define LOONGARCH_EXPAND_PSEUDO_NAME                                           \
33   "LoongArch pseudo instruction expansion pass"
34 
35 namespace {
36 
37 class LoongArchPreRAExpandPseudo : public MachineFunctionPass {
38 public:
39   const LoongArchInstrInfo *TII;
40   static char ID;
41 
LoongArchPreRAExpandPseudo()42   LoongArchPreRAExpandPseudo() : MachineFunctionPass(ID) {
43     initializeLoongArchPreRAExpandPseudoPass(*PassRegistry::getPassRegistry());
44   }
45 
46   bool runOnMachineFunction(MachineFunction &MF) override;
47 
getAnalysisUsage(AnalysisUsage & AU) const48   void getAnalysisUsage(AnalysisUsage &AU) const override {
49     AU.setPreservesCFG();
50     MachineFunctionPass::getAnalysisUsage(AU);
51   }
getPassName() const52   StringRef getPassName() const override {
53     return LOONGARCH_PRERA_EXPAND_PSEUDO_NAME;
54   }
55 
56 private:
57   bool expandMBB(MachineBasicBlock &MBB);
58   bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
59                 MachineBasicBlock::iterator &NextMBBI);
60   bool expandPcalau12iInstPair(MachineBasicBlock &MBB,
61                                MachineBasicBlock::iterator MBBI,
62                                MachineBasicBlock::iterator &NextMBBI,
63                                unsigned FlagsHi, unsigned SecondOpcode,
64                                unsigned FlagsLo);
65   bool expandLoadAddressPcrel(MachineBasicBlock &MBB,
66                               MachineBasicBlock::iterator MBBI,
67                               MachineBasicBlock::iterator &NextMBBI);
68   bool expandLoadAddressGot(MachineBasicBlock &MBB,
69                             MachineBasicBlock::iterator MBBI,
70                             MachineBasicBlock::iterator &NextMBBI);
71   bool expandLoadAddressTLSLE(MachineBasicBlock &MBB,
72                               MachineBasicBlock::iterator MBBI,
73                               MachineBasicBlock::iterator &NextMBBI);
74   bool expandLoadAddressTLSIE(MachineBasicBlock &MBB,
75                               MachineBasicBlock::iterator MBBI,
76                               MachineBasicBlock::iterator &NextMBBI);
77   bool expandLoadAddressTLSLD(MachineBasicBlock &MBB,
78                               MachineBasicBlock::iterator MBBI,
79                               MachineBasicBlock::iterator &NextMBBI);
80   bool expandLoadAddressTLSGD(MachineBasicBlock &MBB,
81                               MachineBasicBlock::iterator MBBI,
82                               MachineBasicBlock::iterator &NextMBBI);
83 };
84 
85 char LoongArchPreRAExpandPseudo::ID = 0;
86 
runOnMachineFunction(MachineFunction & MF)87 bool LoongArchPreRAExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
88   TII =
89       static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo());
90   bool Modified = false;
91   for (auto &MBB : MF)
92     Modified |= expandMBB(MBB);
93   return Modified;
94 }
95 
expandMBB(MachineBasicBlock & MBB)96 bool LoongArchPreRAExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
97   bool Modified = false;
98 
99   MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
100   while (MBBI != E) {
101     MachineBasicBlock::iterator NMBBI = std::next(MBBI);
102     Modified |= expandMI(MBB, MBBI, NMBBI);
103     MBBI = NMBBI;
104   }
105 
106   return Modified;
107 }
108 
expandMI(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)109 bool LoongArchPreRAExpandPseudo::expandMI(
110     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
111     MachineBasicBlock::iterator &NextMBBI) {
112   switch (MBBI->getOpcode()) {
113   case LoongArch::PseudoLA_PCREL:
114     return expandLoadAddressPcrel(MBB, MBBI, NextMBBI);
115   case LoongArch::PseudoLA_GOT:
116     return expandLoadAddressGot(MBB, MBBI, NextMBBI);
117   case LoongArch::PseudoLA_TLS_LE:
118     return expandLoadAddressTLSLE(MBB, MBBI, NextMBBI);
119   case LoongArch::PseudoLA_TLS_IE:
120     return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI);
121   case LoongArch::PseudoLA_TLS_LD:
122     return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI);
123   case LoongArch::PseudoLA_TLS_GD:
124     return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI);
125   }
126   return false;
127 }
128 
expandPcalau12iInstPair(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI,unsigned FlagsHi,unsigned SecondOpcode,unsigned FlagsLo)129 bool LoongArchPreRAExpandPseudo::expandPcalau12iInstPair(
130     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
131     MachineBasicBlock::iterator &NextMBBI, unsigned FlagsHi,
132     unsigned SecondOpcode, unsigned FlagsLo) {
133   MachineFunction *MF = MBB.getParent();
134   MachineInstr &MI = *MBBI;
135   DebugLoc DL = MI.getDebugLoc();
136 
137   Register DestReg = MI.getOperand(0).getReg();
138   Register ScratchReg =
139       MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
140   MachineOperand &Symbol = MI.getOperand(1);
141 
142   BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg)
143       .addDisp(Symbol, 0, FlagsHi);
144 
145   MachineInstr *SecondMI =
146       BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg)
147           .addReg(ScratchReg)
148           .addDisp(Symbol, 0, FlagsLo);
149 
150   if (MI.hasOneMemOperand())
151     SecondMI->addMemOperand(*MF, *MI.memoperands_begin());
152 
153   MI.eraseFromParent();
154   return true;
155 }
156 
expandLoadAddressPcrel(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)157 bool LoongArchPreRAExpandPseudo::expandLoadAddressPcrel(
158     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
159     MachineBasicBlock::iterator &NextMBBI) {
160   // Code Sequence:
161   // pcalau12i $rd, %pc_hi20(sym)
162   // addi.w/d $rd, $rd, %pc_lo12(sym)
163   MachineFunction *MF = MBB.getParent();
164   const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
165   unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
166   return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_PCREL_HI,
167                                  SecondOpcode, LoongArchII::MO_PCREL_LO);
168 }
169 
expandLoadAddressGot(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)170 bool LoongArchPreRAExpandPseudo::expandLoadAddressGot(
171     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
172     MachineBasicBlock::iterator &NextMBBI) {
173   // Code Sequence:
174   // pcalau12i $rd, %got_pc_hi20(sym)
175   // ld.w/d $rd, $rd, %got_pc_lo12(sym)
176   MachineFunction *MF = MBB.getParent();
177   const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
178   unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
179   return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GOT_PC_HI,
180                                  SecondOpcode, LoongArchII::MO_GOT_PC_LO);
181 }
182 
expandLoadAddressTLSLE(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)183 bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLE(
184     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
185     MachineBasicBlock::iterator &NextMBBI) {
186   // Code Sequence:
187   // lu12i.w $rd, %le_hi20(sym)
188   // ori $rd, $rd, %le_lo12(sym)
189   //
190   // And additionally if generating code using the large code model:
191   //
192   // lu32i.d $rd, %le64_lo20(sym)
193   // lu52i.d $rd, $rd, %le64_hi12(sym)
194   MachineFunction *MF = MBB.getParent();
195   MachineInstr &MI = *MBBI;
196   DebugLoc DL = MI.getDebugLoc();
197 
198   bool Large = MF->getTarget().getCodeModel() == CodeModel::Large;
199   Register DestReg = MI.getOperand(0).getReg();
200   Register Parts01 =
201       Large ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)
202             : DestReg;
203   Register Part1 =
204       MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
205   MachineOperand &Symbol = MI.getOperand(1);
206 
207   BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W), Part1)
208       .addDisp(Symbol, 0, LoongArchII::MO_LE_HI);
209 
210   BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ORI), Parts01)
211       .addReg(Part1, RegState::Kill)
212       .addDisp(Symbol, 0, LoongArchII::MO_LE_LO);
213 
214   if (Large) {
215     Register Parts012 =
216         MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
217 
218     BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), Parts012)
219         // "rj" is needed due to InstrInfo pattern requirement.
220         .addReg(Parts01, RegState::Kill)
221         .addDisp(Symbol, 0, LoongArchII::MO_LE64_LO);
222     BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), DestReg)
223         .addReg(Parts012, RegState::Kill)
224         .addDisp(Symbol, 0, LoongArchII::MO_LE64_HI);
225   }
226 
227   MI.eraseFromParent();
228   return true;
229 }
230 
expandLoadAddressTLSIE(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)231 bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSIE(
232     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
233     MachineBasicBlock::iterator &NextMBBI) {
234   // Code Sequence:
235   // pcalau12i $rd, %ie_pc_hi20(sym)
236   // ld.w/d $rd, $rd, %ie_pc_lo12(sym)
237   MachineFunction *MF = MBB.getParent();
238   const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
239   unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
240   return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_IE_PC_HI,
241                                  SecondOpcode, LoongArchII::MO_IE_PC_LO);
242 }
243 
expandLoadAddressTLSLD(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)244 bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLD(
245     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
246     MachineBasicBlock::iterator &NextMBBI) {
247   // Code Sequence:
248   // pcalau12i $rd, %ld_pc_hi20(sym)
249   // addi.w/d $rd, $rd, %got_pc_lo12(sym)
250   MachineFunction *MF = MBB.getParent();
251   const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
252   unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
253   return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_LD_PC_HI,
254                                  SecondOpcode, LoongArchII::MO_GOT_PC_LO);
255 }
256 
expandLoadAddressTLSGD(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)257 bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSGD(
258     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
259     MachineBasicBlock::iterator &NextMBBI) {
260   // Code Sequence:
261   // pcalau12i $rd, %gd_pc_hi20(sym)
262   // addi.w/d $rd, $rd, %got_pc_lo12(sym)
263   MachineFunction *MF = MBB.getParent();
264   const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
265   unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
266   return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GD_PC_HI,
267                                  SecondOpcode, LoongArchII::MO_GOT_PC_LO);
268 }
269 
270 class LoongArchExpandPseudo : public MachineFunctionPass {
271 public:
272   const LoongArchInstrInfo *TII;
273   static char ID;
274 
LoongArchExpandPseudo()275   LoongArchExpandPseudo() : MachineFunctionPass(ID) {
276     initializeLoongArchExpandPseudoPass(*PassRegistry::getPassRegistry());
277   }
278 
279   bool runOnMachineFunction(MachineFunction &MF) override;
280 
getPassName() const281   StringRef getPassName() const override {
282     return LOONGARCH_EXPAND_PSEUDO_NAME;
283   }
284 
285 private:
286   bool expandMBB(MachineBasicBlock &MBB);
287   bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
288                 MachineBasicBlock::iterator &NextMBBI);
289   bool expandCopyCFR(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
290                      MachineBasicBlock::iterator &NextMBBI);
291   bool expandLargeAddressLoad(MachineBasicBlock &MBB,
292                               MachineBasicBlock::iterator MBBI,
293                               MachineBasicBlock::iterator &NextMBBI,
294                               unsigned LastOpcode, unsigned IdentifyingMO);
295   bool expandLargeAddressLoad(MachineBasicBlock &MBB,
296                               MachineBasicBlock::iterator MBBI,
297                               MachineBasicBlock::iterator &NextMBBI,
298                               unsigned LastOpcode, unsigned IdentifyingMO,
299                               const MachineOperand &Symbol, Register DestReg,
300                               bool EraseFromParent);
301   bool expandLoadAddressPcrelLarge(MachineBasicBlock &MBB,
302                                    MachineBasicBlock::iterator MBBI,
303                                    MachineBasicBlock::iterator &NextMBBI);
304   bool expandLoadAddressGotLarge(MachineBasicBlock &MBB,
305                                  MachineBasicBlock::iterator MBBI,
306                                  MachineBasicBlock::iterator &NextMBBI);
307   bool expandLoadAddressTLSIELarge(MachineBasicBlock &MBB,
308                                    MachineBasicBlock::iterator MBBI,
309                                    MachineBasicBlock::iterator &NextMBBI);
310   bool expandLoadAddressTLSLDLarge(MachineBasicBlock &MBB,
311                                    MachineBasicBlock::iterator MBBI,
312                                    MachineBasicBlock::iterator &NextMBBI);
313   bool expandLoadAddressTLSGDLarge(MachineBasicBlock &MBB,
314                                    MachineBasicBlock::iterator MBBI,
315                                    MachineBasicBlock::iterator &NextMBBI);
316   bool expandFunctionCALL(MachineBasicBlock &MBB,
317                           MachineBasicBlock::iterator MBBI,
318                           MachineBasicBlock::iterator &NextMBBI,
319                           bool IsTailCall);
320 };
321 
322 char LoongArchExpandPseudo::ID = 0;
323 
runOnMachineFunction(MachineFunction & MF)324 bool LoongArchExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
325   TII =
326       static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo());
327 
328   bool Modified = false;
329   for (auto &MBB : MF)
330     Modified |= expandMBB(MBB);
331 
332   return Modified;
333 }
334 
expandMBB(MachineBasicBlock & MBB)335 bool LoongArchExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
336   bool Modified = false;
337 
338   MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
339   while (MBBI != E) {
340     MachineBasicBlock::iterator NMBBI = std::next(MBBI);
341     Modified |= expandMI(MBB, MBBI, NMBBI);
342     MBBI = NMBBI;
343   }
344 
345   return Modified;
346 }
347 
expandMI(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)348 bool LoongArchExpandPseudo::expandMI(MachineBasicBlock &MBB,
349                                      MachineBasicBlock::iterator MBBI,
350                                      MachineBasicBlock::iterator &NextMBBI) {
351   switch (MBBI->getOpcode()) {
352   case LoongArch::PseudoCopyCFR:
353     return expandCopyCFR(MBB, MBBI, NextMBBI);
354   case LoongArch::PseudoLA_PCREL_LARGE:
355     return expandLoadAddressPcrelLarge(MBB, MBBI, NextMBBI);
356   case LoongArch::PseudoLA_GOT_LARGE:
357     return expandLoadAddressGotLarge(MBB, MBBI, NextMBBI);
358   case LoongArch::PseudoLA_TLS_IE_LARGE:
359     return expandLoadAddressTLSIELarge(MBB, MBBI, NextMBBI);
360   case LoongArch::PseudoLA_TLS_LD_LARGE:
361     return expandLoadAddressTLSLDLarge(MBB, MBBI, NextMBBI);
362   case LoongArch::PseudoLA_TLS_GD_LARGE:
363     return expandLoadAddressTLSGDLarge(MBB, MBBI, NextMBBI);
364   case LoongArch::PseudoCALL:
365   case LoongArch::PseudoCALL_MEDIUM:
366   case LoongArch::PseudoCALL_LARGE:
367     return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
368   case LoongArch::PseudoTAIL:
369   case LoongArch::PseudoTAIL_MEDIUM:
370   case LoongArch::PseudoTAIL_LARGE:
371     return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
372   }
373 
374   return false;
375 }
376 
expandCopyCFR(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)377 bool LoongArchExpandPseudo::expandCopyCFR(
378     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
379     MachineBasicBlock::iterator &NextMBBI) {
380   MachineFunction *MF = MBB.getParent();
381   MachineInstr &MI = *MBBI;
382   DebugLoc DL = MI.getDebugLoc();
383 
384   // Expand:
385   // MBB:
386   //    fcmp.caf.s  $dst, $fa0, $fa0 # set $dst 0(false)
387   //    bceqz $src, SinkBB
388   // FalseBB:
389   //    fcmp.cueq.s $dst, $fa0, $fa0 # set $dst 1(true)
390   // SinkBB:
391   //    fallthrough
392 
393   const BasicBlock *LLVM_BB = MBB.getBasicBlock();
394   auto *FalseBB = MF->CreateMachineBasicBlock(LLVM_BB);
395   auto *SinkBB = MF->CreateMachineBasicBlock(LLVM_BB);
396 
397   MF->insert(++MBB.getIterator(), FalseBB);
398   MF->insert(++FalseBB->getIterator(), SinkBB);
399 
400   Register DestReg = MI.getOperand(0).getReg();
401   Register SrcReg = MI.getOperand(1).getReg();
402   // DestReg = 0
403   BuildMI(MBB, MBBI, DL, TII->get(LoongArch::SET_CFR_FALSE), DestReg);
404   // Insert branch instruction.
405   BuildMI(MBB, MBBI, DL, TII->get(LoongArch::BCEQZ))
406       .addReg(SrcReg)
407       .addMBB(SinkBB);
408   // DestReg = 1
409   BuildMI(FalseBB, DL, TII->get(LoongArch::SET_CFR_TRUE), DestReg);
410 
411   FalseBB->addSuccessor(SinkBB);
412 
413   SinkBB->splice(SinkBB->end(), &MBB, MI, MBB.end());
414   SinkBB->transferSuccessors(&MBB);
415 
416   MBB.addSuccessor(FalseBB);
417   MBB.addSuccessor(SinkBB);
418 
419   NextMBBI = MBB.end();
420   MI.eraseFromParent();
421 
422   // Make sure live-ins are correctly attached to this new basic block.
423   LivePhysRegs LiveRegs;
424   computeAndAddLiveIns(LiveRegs, *FalseBB);
425   computeAndAddLiveIns(LiveRegs, *SinkBB);
426 
427   return true;
428 }
429 
expandLargeAddressLoad(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI,unsigned LastOpcode,unsigned IdentifyingMO)430 bool LoongArchExpandPseudo::expandLargeAddressLoad(
431     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
432     MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode,
433     unsigned IdentifyingMO) {
434   MachineInstr &MI = *MBBI;
435   return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode, IdentifyingMO,
436                                 MI.getOperand(2), MI.getOperand(0).getReg(),
437                                 true);
438 }
439 
expandLargeAddressLoad(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI,unsigned LastOpcode,unsigned IdentifyingMO,const MachineOperand & Symbol,Register DestReg,bool EraseFromParent)440 bool LoongArchExpandPseudo::expandLargeAddressLoad(
441     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
442     MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode,
443     unsigned IdentifyingMO, const MachineOperand &Symbol, Register DestReg,
444     bool EraseFromParent) {
445   // Code Sequence:
446   //
447   // Part1: pcalau12i  $dst, %MO1(sym)
448   // Part0: addi.d     $t8, $zero, %MO0(sym)
449   // Part2: lu32i.d    $t8, %MO2(sym)
450   // Part3: lu52i.d    $t8, $t8, %MO3(sym)
451   // Fin:   LastOpcode $dst, $t8, $dst
452 
453   unsigned MO0, MO1, MO2, MO3;
454   switch (IdentifyingMO) {
455   default:
456     llvm_unreachable("unsupported identifying MO");
457   case LoongArchII::MO_PCREL_LO:
458     MO0 = IdentifyingMO;
459     MO1 = LoongArchII::MO_PCREL_HI;
460     MO2 = LoongArchII::MO_PCREL64_LO;
461     MO3 = LoongArchII::MO_PCREL64_HI;
462     break;
463   case LoongArchII::MO_GOT_PC_HI:
464   case LoongArchII::MO_LD_PC_HI:
465   case LoongArchII::MO_GD_PC_HI:
466     // These cases relocate just like the GOT case, except for Part1.
467     MO0 = LoongArchII::MO_GOT_PC_LO;
468     MO1 = IdentifyingMO;
469     MO2 = LoongArchII::MO_GOT_PC64_LO;
470     MO3 = LoongArchII::MO_GOT_PC64_HI;
471     break;
472   case LoongArchII::MO_IE_PC_LO:
473     MO0 = IdentifyingMO;
474     MO1 = LoongArchII::MO_IE_PC_HI;
475     MO2 = LoongArchII::MO_IE_PC64_LO;
476     MO3 = LoongArchII::MO_IE_PC64_HI;
477     break;
478   }
479 
480   MachineInstr &MI = *MBBI;
481   DebugLoc DL = MI.getDebugLoc();
482   Register ScratchReg = LoongArch::R20; // $t8
483 
484   assert(MBB.getParent()->getSubtarget<LoongArchSubtarget>().is64Bit() &&
485          "Large code model requires LA64");
486 
487   auto Part1 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), DestReg);
488   auto Part0 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADDI_D), ScratchReg)
489                    .addReg(LoongArch::R0);
490   auto Part2 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), ScratchReg)
491                    // "rj" is needed due to InstrInfo pattern requirement.
492                    .addReg(ScratchReg);
493   auto Part3 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), ScratchReg)
494                    .addReg(ScratchReg);
495   BuildMI(MBB, MBBI, DL, TII->get(LastOpcode), DestReg)
496       .addReg(ScratchReg)
497       .addReg(DestReg);
498 
499   if (Symbol.getType() == MachineOperand::MO_ExternalSymbol) {
500     const char *SymName = Symbol.getSymbolName();
501     Part0.addExternalSymbol(SymName, MO0);
502     Part1.addExternalSymbol(SymName, MO1);
503     Part2.addExternalSymbol(SymName, MO2);
504     Part3.addExternalSymbol(SymName, MO3);
505   } else {
506     Part0.addDisp(Symbol, 0, MO0);
507     Part1.addDisp(Symbol, 0, MO1);
508     Part2.addDisp(Symbol, 0, MO2);
509     Part3.addDisp(Symbol, 0, MO3);
510   }
511 
512   if (EraseFromParent)
513     MI.eraseFromParent();
514 
515   return true;
516 }
517 
expandLoadAddressPcrelLarge(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)518 bool LoongArchExpandPseudo::expandLoadAddressPcrelLarge(
519     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
520     MachineBasicBlock::iterator &NextMBBI) {
521   // Emit the 5-insn large address load sequence with the `%pc` family of
522   // relocs.
523   return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,
524                                 LoongArchII::MO_PCREL_LO);
525 }
526 
expandLoadAddressGotLarge(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)527 bool LoongArchExpandPseudo::expandLoadAddressGotLarge(
528     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
529     MachineBasicBlock::iterator &NextMBBI) {
530   // Emit the 5-insn large address load sequence with the `%got_pc` family
531   // of relocs, loading the result from GOT with `ldx.d` in the end.
532   return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::LDX_D,
533                                 LoongArchII::MO_GOT_PC_HI);
534 }
535 
expandLoadAddressTLSIELarge(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)536 bool LoongArchExpandPseudo::expandLoadAddressTLSIELarge(
537     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
538     MachineBasicBlock::iterator &NextMBBI) {
539   // Emit the 5-insn large address load sequence with the `%ie_pc` family
540   // of relocs, loading the result with `ldx.d` in the end.
541   return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::LDX_D,
542                                 LoongArchII::MO_IE_PC_LO);
543 }
544 
expandLoadAddressTLSLDLarge(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)545 bool LoongArchExpandPseudo::expandLoadAddressTLSLDLarge(
546     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
547     MachineBasicBlock::iterator &NextMBBI) {
548   // Emit the 5-insn large address load sequence with the `%got_pc` family
549   // of relocs, with the `pcalau12i` insn relocated with `%ld_pc_hi20`.
550   return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,
551                                 LoongArchII::MO_LD_PC_HI);
552 }
553 
expandLoadAddressTLSGDLarge(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)554 bool LoongArchExpandPseudo::expandLoadAddressTLSGDLarge(
555     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
556     MachineBasicBlock::iterator &NextMBBI) {
557   // Emit the 5-insn large address load sequence with the `%got_pc` family
558   // of relocs, with the `pcalau12i` insn relocated with `%gd_pc_hi20`.
559   return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,
560                                 LoongArchII::MO_GD_PC_HI);
561 }
562 
expandFunctionCALL(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI,bool IsTailCall)563 bool LoongArchExpandPseudo::expandFunctionCALL(
564     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
565     MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {
566   MachineFunction *MF = MBB.getParent();
567   MachineInstr &MI = *MBBI;
568   DebugLoc DL = MI.getDebugLoc();
569   const MachineOperand &Func = MI.getOperand(0);
570   MachineInstrBuilder CALL;
571   unsigned Opcode;
572 
573   switch (MF->getTarget().getCodeModel()) {
574   default:
575     report_fatal_error("Unsupported code model");
576     break;
577   case CodeModel::Small: {
578     // CALL:
579     // bl func
580     // TAIL:
581     // b func
582     Opcode = IsTailCall ? LoongArch::PseudoB_TAIL : LoongArch::BL;
583     CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).add(Func);
584     break;
585   }
586   case CodeModel::Medium: {
587     // CALL:
588     // pcaddu18i  $ra, %call36(func)
589     // jirl       $ra, $ra, 0
590     // TAIL:
591     // pcaddu18i  $t8, %call36(func)
592     // jr         $t8
593     Opcode =
594         IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
595     Register ScratchReg = IsTailCall ? LoongArch::R20 : LoongArch::R1;
596     MachineInstrBuilder MIB =
597         BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCADDU18I), ScratchReg);
598 
599     CALL =
600         BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(ScratchReg).addImm(0);
601 
602     if (Func.isSymbol())
603       MIB.addExternalSymbol(Func.getSymbolName(), LoongArchII::MO_CALL36);
604     else
605       MIB.addDisp(Func, 0, LoongArchII::MO_CALL36);
606     break;
607   }
608   case CodeModel::Large: {
609     // Emit the 5-insn large address load sequence, either directly or
610     // indirectly in case of going through the GOT, then JIRL_TAIL or
611     // JIRL_CALL to $addr.
612     Opcode =
613         IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
614     Register AddrReg = IsTailCall ? LoongArch::R19 : LoongArch::R1;
615 
616     bool UseGOT = Func.isGlobal() && !Func.getGlobal()->isDSOLocal();
617     unsigned MO = UseGOT ? LoongArchII::MO_GOT_PC_HI : LoongArchII::MO_PCREL_LO;
618     unsigned LAOpcode = UseGOT ? LoongArch::LDX_D : LoongArch::ADD_D;
619     expandLargeAddressLoad(MBB, MBBI, NextMBBI, LAOpcode, MO, Func, AddrReg,
620                            false);
621     CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(AddrReg).addImm(0);
622     break;
623   }
624   }
625 
626   // Transfer implicit operands.
627   CALL.copyImplicitOps(MI);
628 
629   // Transfer MI flags.
630   CALL.setMIFlags(MI.getFlags());
631 
632   MI.eraseFromParent();
633   return true;
634 }
635 
636 } // end namespace
637 
638 INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "loongarch-prera-expand-pseudo",
639                 LOONGARCH_PRERA_EXPAND_PSEUDO_NAME, false, false)
640 
641 INITIALIZE_PASS(LoongArchExpandPseudo, "loongarch-expand-pseudo",
642                 LOONGARCH_EXPAND_PSEUDO_NAME, false, false)
643 
644 namespace llvm {
645 
createLoongArchPreRAExpandPseudoPass()646 FunctionPass *createLoongArchPreRAExpandPseudoPass() {
647   return new LoongArchPreRAExpandPseudo();
648 }
createLoongArchExpandPseudoPass()649 FunctionPass *createLoongArchExpandPseudoPass() {
650   return new LoongArchExpandPseudo();
651 }
652 
653 } // end namespace llvm
654