xref: /freebsd/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp (revision 5f4c09dd85bff675e0ca63c55ea3c517e0fddfcc)
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/MC/MCContext.h"
23 #include "llvm/Support/CodeGen.h"
24 
25 using namespace llvm;
26 
27 #define LOONGARCH_PRERA_EXPAND_PSEUDO_NAME                                     \
28   "LoongArch Pre-RA pseudo instruction expansion pass"
29 
30 namespace {
31 
32 class LoongArchPreRAExpandPseudo : public MachineFunctionPass {
33 public:
34   const LoongArchInstrInfo *TII;
35   static char ID;
36 
37   LoongArchPreRAExpandPseudo() : MachineFunctionPass(ID) {
38     initializeLoongArchPreRAExpandPseudoPass(*PassRegistry::getPassRegistry());
39   }
40 
41   bool runOnMachineFunction(MachineFunction &MF) override;
42 
43   void getAnalysisUsage(AnalysisUsage &AU) const override {
44     AU.setPreservesCFG();
45     MachineFunctionPass::getAnalysisUsage(AU);
46   }
47   StringRef getPassName() const override {
48     return LOONGARCH_PRERA_EXPAND_PSEUDO_NAME;
49   }
50 
51 private:
52   bool expandMBB(MachineBasicBlock &MBB);
53   bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
54                 MachineBasicBlock::iterator &NextMBBI);
55   bool expandPcalau12iInstPair(MachineBasicBlock &MBB,
56                                MachineBasicBlock::iterator MBBI,
57                                MachineBasicBlock::iterator &NextMBBI,
58                                unsigned FlagsHi, unsigned SecondOpcode,
59                                unsigned FlagsLo);
60   bool expandLoadAddressPcrel(MachineBasicBlock &MBB,
61                               MachineBasicBlock::iterator MBBI,
62                               MachineBasicBlock::iterator &NextMBBI);
63   bool expandLoadAddressGot(MachineBasicBlock &MBB,
64                             MachineBasicBlock::iterator MBBI,
65                             MachineBasicBlock::iterator &NextMBBI);
66   bool expandLoadAddressTLSLE(MachineBasicBlock &MBB,
67                               MachineBasicBlock::iterator MBBI,
68                               MachineBasicBlock::iterator &NextMBBI);
69   bool expandLoadAddressTLSIE(MachineBasicBlock &MBB,
70                               MachineBasicBlock::iterator MBBI,
71                               MachineBasicBlock::iterator &NextMBBI);
72   bool expandLoadAddressTLSLD(MachineBasicBlock &MBB,
73                               MachineBasicBlock::iterator MBBI,
74                               MachineBasicBlock::iterator &NextMBBI);
75   bool expandLoadAddressTLSGD(MachineBasicBlock &MBB,
76                               MachineBasicBlock::iterator MBBI,
77                               MachineBasicBlock::iterator &NextMBBI);
78   bool expandFunctionCALL(MachineBasicBlock &MBB,
79                           MachineBasicBlock::iterator MBBI,
80                           MachineBasicBlock::iterator &NextMBBI,
81                           bool IsTailCall);
82 };
83 
84 char LoongArchPreRAExpandPseudo::ID = 0;
85 
86 bool LoongArchPreRAExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
87   TII =
88       static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo());
89   bool Modified = false;
90   for (auto &MBB : MF)
91     Modified |= expandMBB(MBB);
92   return Modified;
93 }
94 
95 bool LoongArchPreRAExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
96   bool Modified = false;
97 
98   MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
99   while (MBBI != E) {
100     MachineBasicBlock::iterator NMBBI = std::next(MBBI);
101     Modified |= expandMI(MBB, MBBI, NMBBI);
102     MBBI = NMBBI;
103   }
104 
105   return Modified;
106 }
107 
108 bool LoongArchPreRAExpandPseudo::expandMI(
109     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
110     MachineBasicBlock::iterator &NextMBBI) {
111   switch (MBBI->getOpcode()) {
112   case LoongArch::PseudoLA_PCREL:
113     return expandLoadAddressPcrel(MBB, MBBI, NextMBBI);
114   case LoongArch::PseudoLA_GOT:
115     return expandLoadAddressGot(MBB, MBBI, NextMBBI);
116   case LoongArch::PseudoLA_TLS_LE:
117     return expandLoadAddressTLSLE(MBB, MBBI, NextMBBI);
118   case LoongArch::PseudoLA_TLS_IE:
119     return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI);
120   case LoongArch::PseudoLA_TLS_LD:
121     return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI);
122   case LoongArch::PseudoLA_TLS_GD:
123     return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI);
124   case LoongArch::PseudoCALL:
125     return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
126   case LoongArch::PseudoTAIL:
127     return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
128   }
129   return false;
130 }
131 
132 bool LoongArchPreRAExpandPseudo::expandPcalau12iInstPair(
133     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
134     MachineBasicBlock::iterator &NextMBBI, unsigned FlagsHi,
135     unsigned SecondOpcode, unsigned FlagsLo) {
136   MachineFunction *MF = MBB.getParent();
137   MachineInstr &MI = *MBBI;
138   DebugLoc DL = MI.getDebugLoc();
139 
140   Register DestReg = MI.getOperand(0).getReg();
141   Register ScratchReg =
142       MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
143   MachineOperand &Symbol = MI.getOperand(1);
144 
145   BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg)
146       .addDisp(Symbol, 0, FlagsHi);
147 
148   MachineInstr *SecondMI =
149       BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg)
150           .addReg(ScratchReg)
151           .addDisp(Symbol, 0, FlagsLo);
152 
153   if (MI.hasOneMemOperand())
154     SecondMI->addMemOperand(*MF, *MI.memoperands_begin());
155 
156   MI.eraseFromParent();
157   return true;
158 }
159 
160 bool LoongArchPreRAExpandPseudo::expandLoadAddressPcrel(
161     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
162     MachineBasicBlock::iterator &NextMBBI) {
163   // Code Sequence:
164   // pcalau12i $rd, %pc_hi20(sym)
165   // addi.w/d $rd, $rd, %pc_lo12(sym)
166   MachineFunction *MF = MBB.getParent();
167   const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
168   unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
169   return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_PCREL_HI,
170                                  SecondOpcode, LoongArchII::MO_PCREL_LO);
171 }
172 
173 bool LoongArchPreRAExpandPseudo::expandLoadAddressGot(
174     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
175     MachineBasicBlock::iterator &NextMBBI) {
176   // Code Sequence:
177   // pcalau12i $rd, %got_pc_hi20(sym)
178   // ld.w/d $rd, $rd, %got_pc_lo12(sym)
179   MachineFunction *MF = MBB.getParent();
180   const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
181   unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
182   return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GOT_PC_HI,
183                                  SecondOpcode, LoongArchII::MO_GOT_PC_LO);
184 }
185 
186 bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLE(
187     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
188     MachineBasicBlock::iterator &NextMBBI) {
189   // Code Sequence:
190   // lu12i.w $rd, %le_hi20(sym)
191   // ori $rd, $rd, %le_lo12(sym)
192   MachineFunction *MF = MBB.getParent();
193   MachineInstr &MI = *MBBI;
194   DebugLoc DL = MI.getDebugLoc();
195 
196   Register DestReg = MI.getOperand(0).getReg();
197   Register ScratchReg =
198       MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
199   MachineOperand &Symbol = MI.getOperand(1);
200 
201   BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W), ScratchReg)
202       .addDisp(Symbol, 0, LoongArchII::MO_LE_HI);
203 
204   BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ORI), DestReg)
205       .addReg(ScratchReg)
206       .addDisp(Symbol, 0, LoongArchII::MO_LE_LO);
207 
208   MI.eraseFromParent();
209   return true;
210 }
211 
212 bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSIE(
213     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
214     MachineBasicBlock::iterator &NextMBBI) {
215   // Code Sequence:
216   // pcalau12i $rd, %ie_pc_hi20(sym)
217   // ld.w/d $rd, $rd, %ie_pc_lo12(sym)
218   MachineFunction *MF = MBB.getParent();
219   const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
220   unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
221   return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_IE_PC_HI,
222                                  SecondOpcode, LoongArchII::MO_IE_PC_LO);
223 }
224 
225 bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLD(
226     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
227     MachineBasicBlock::iterator &NextMBBI) {
228   // Code Sequence:
229   // pcalau12i $rd, %ld_pc_hi20(sym)
230   // addi.w/d $rd, $rd, %got_pc_lo12(sym)
231   MachineFunction *MF = MBB.getParent();
232   const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
233   unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
234   return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_LD_PC_HI,
235                                  SecondOpcode, LoongArchII::MO_GOT_PC_LO);
236 }
237 
238 bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSGD(
239     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
240     MachineBasicBlock::iterator &NextMBBI) {
241   // Code Sequence:
242   // pcalau12i $rd, %gd_pc_hi20(sym)
243   // addi.w/d $rd, $rd, %got_pc_lo12(sym)
244   MachineFunction *MF = MBB.getParent();
245   const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
246   unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
247   return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GD_PC_HI,
248                                  SecondOpcode, LoongArchII::MO_GOT_PC_LO);
249 }
250 
251 bool LoongArchPreRAExpandPseudo::expandFunctionCALL(
252     MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
253     MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {
254   MachineFunction *MF = MBB.getParent();
255   MachineInstr &MI = *MBBI;
256   DebugLoc DL = MI.getDebugLoc();
257   const MachineOperand &Func = MI.getOperand(0);
258   MachineInstrBuilder CALL;
259   unsigned Opcode;
260 
261   switch (MF->getTarget().getCodeModel()) {
262   default:
263     report_fatal_error("Unsupported code model");
264     break;
265   case CodeModel::Small: {
266     // CALL:
267     // bl func
268     // TAIL:
269     // b func
270     Opcode = IsTailCall ? LoongArch::PseudoB_TAIL : LoongArch::BL;
271     CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).add(Func);
272     break;
273   }
274   case CodeModel::Medium: {
275     // CALL:
276     // pcalau12i  $ra, %pc_hi20(func)
277     // jirl       $ra, $ra, %pc_lo12(func)
278     // TAIL:
279     // pcalau12i  $scratch, %pc_hi20(func)
280     // jirl       $r0, $scratch, %pc_lo12(func)
281     Opcode =
282         IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
283     Register ScratchReg =
284         IsTailCall
285             ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)
286             : LoongArch::R1;
287     MachineInstrBuilder MIB =
288         BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg);
289     CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(ScratchReg);
290     if (Func.isSymbol()) {
291       const char *FnName = Func.getSymbolName();
292       MIB.addExternalSymbol(FnName, LoongArchII::MO_PCREL_HI);
293       CALL.addExternalSymbol(FnName, LoongArchII::MO_PCREL_LO);
294       break;
295     }
296     assert(Func.isGlobal() && "Expected a GlobalValue at this time");
297     const GlobalValue *GV = Func.getGlobal();
298     MIB.addGlobalAddress(GV, 0, LoongArchII::MO_PCREL_HI);
299     CALL.addGlobalAddress(GV, 0, LoongArchII::MO_PCREL_LO);
300     break;
301   }
302   }
303 
304   // Transfer implicit operands.
305   CALL.copyImplicitOps(MI);
306 
307   // Transfer MI flags.
308   CALL.setMIFlags(MI.getFlags());
309 
310   MI.eraseFromParent();
311   return true;
312 }
313 
314 } // end namespace
315 
316 INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "loongarch-prera-expand-pseudo",
317                 LOONGARCH_PRERA_EXPAND_PSEUDO_NAME, false, false)
318 
319 namespace llvm {
320 
321 FunctionPass *createLoongArchPreRAExpandPseudoPass() {
322   return new LoongArchPreRAExpandPseudo();
323 }
324 
325 } // end namespace llvm
326