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