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,
671db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI);
68bdd1243dSDimitry Andric bool expandLoadAddressGot(MachineBasicBlock &MBB,
69bdd1243dSDimitry Andric MachineBasicBlock::iterator MBBI,
701db9f3b2SDimitry 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,
761db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI);
77bdd1243dSDimitry Andric bool expandLoadAddressTLSLD(MachineBasicBlock &MBB,
78bdd1243dSDimitry Andric MachineBasicBlock::iterator MBBI,
791db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI);
80bdd1243dSDimitry Andric bool expandLoadAddressTLSGD(MachineBasicBlock &MBB,
81bdd1243dSDimitry Andric MachineBasicBlock::iterator MBBI,
821db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI);
830fca6ea1SDimitry Andric bool expandLoadAddressTLSDesc(MachineBasicBlock &MBB,
840fca6ea1SDimitry Andric MachineBasicBlock::iterator MBBI,
850fca6ea1SDimitry Andric MachineBasicBlock::iterator &NextMBBI);
86bdd1243dSDimitry Andric };
87bdd1243dSDimitry Andric
88bdd1243dSDimitry Andric char LoongArchPreRAExpandPseudo::ID = 0;
89bdd1243dSDimitry Andric
runOnMachineFunction(MachineFunction & MF)90bdd1243dSDimitry Andric bool LoongArchPreRAExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
91bdd1243dSDimitry Andric TII =
92bdd1243dSDimitry Andric static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo());
93bdd1243dSDimitry Andric bool Modified = false;
94bdd1243dSDimitry Andric for (auto &MBB : MF)
95bdd1243dSDimitry Andric Modified |= expandMBB(MBB);
96bdd1243dSDimitry Andric return Modified;
97bdd1243dSDimitry Andric }
98bdd1243dSDimitry Andric
expandMBB(MachineBasicBlock & MBB)99bdd1243dSDimitry Andric bool LoongArchPreRAExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
100bdd1243dSDimitry Andric bool Modified = false;
101bdd1243dSDimitry Andric
102bdd1243dSDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
103bdd1243dSDimitry Andric while (MBBI != E) {
104bdd1243dSDimitry Andric MachineBasicBlock::iterator NMBBI = std::next(MBBI);
105bdd1243dSDimitry Andric Modified |= expandMI(MBB, MBBI, NMBBI);
106bdd1243dSDimitry Andric MBBI = NMBBI;
107bdd1243dSDimitry Andric }
108bdd1243dSDimitry Andric
109bdd1243dSDimitry Andric return Modified;
110bdd1243dSDimitry Andric }
111bdd1243dSDimitry Andric
expandMI(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)112bdd1243dSDimitry Andric bool LoongArchPreRAExpandPseudo::expandMI(
113bdd1243dSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
114bdd1243dSDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
115bdd1243dSDimitry Andric switch (MBBI->getOpcode()) {
116bdd1243dSDimitry Andric case LoongArch::PseudoLA_PCREL:
117bdd1243dSDimitry Andric return expandLoadAddressPcrel(MBB, MBBI, NextMBBI);
118bdd1243dSDimitry Andric case LoongArch::PseudoLA_GOT:
119bdd1243dSDimitry Andric return expandLoadAddressGot(MBB, MBBI, NextMBBI);
120bdd1243dSDimitry Andric case LoongArch::PseudoLA_TLS_LE:
121bdd1243dSDimitry Andric return expandLoadAddressTLSLE(MBB, MBBI, NextMBBI);
122bdd1243dSDimitry Andric case LoongArch::PseudoLA_TLS_IE:
123bdd1243dSDimitry Andric return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI);
124bdd1243dSDimitry Andric case LoongArch::PseudoLA_TLS_LD:
125bdd1243dSDimitry Andric return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI);
126bdd1243dSDimitry Andric case LoongArch::PseudoLA_TLS_GD:
127bdd1243dSDimitry Andric return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI);
1280fca6ea1SDimitry Andric case LoongArch::PseudoLA_TLS_DESC_PC:
1290fca6ea1SDimitry Andric return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI);
130bdd1243dSDimitry Andric }
131bdd1243dSDimitry Andric return false;
132bdd1243dSDimitry Andric }
133bdd1243dSDimitry Andric
expandPcalau12iInstPair(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI,unsigned FlagsHi,unsigned SecondOpcode,unsigned FlagsLo)134bdd1243dSDimitry Andric bool LoongArchPreRAExpandPseudo::expandPcalau12iInstPair(
135bdd1243dSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
136bdd1243dSDimitry Andric MachineBasicBlock::iterator &NextMBBI, unsigned FlagsHi,
137bdd1243dSDimitry Andric unsigned SecondOpcode, unsigned FlagsLo) {
138bdd1243dSDimitry Andric MachineFunction *MF = MBB.getParent();
139bdd1243dSDimitry Andric MachineInstr &MI = *MBBI;
140bdd1243dSDimitry Andric DebugLoc DL = MI.getDebugLoc();
141bdd1243dSDimitry Andric
142bdd1243dSDimitry Andric Register DestReg = MI.getOperand(0).getReg();
143bdd1243dSDimitry Andric Register ScratchReg =
144bdd1243dSDimitry Andric MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
145bdd1243dSDimitry Andric MachineOperand &Symbol = MI.getOperand(1);
146bdd1243dSDimitry Andric
147bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg)
148bdd1243dSDimitry Andric .addDisp(Symbol, 0, FlagsHi);
149bdd1243dSDimitry Andric
150bdd1243dSDimitry Andric MachineInstr *SecondMI =
151bdd1243dSDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg)
152bdd1243dSDimitry Andric .addReg(ScratchReg)
153bdd1243dSDimitry Andric .addDisp(Symbol, 0, FlagsLo);
154bdd1243dSDimitry Andric
155bdd1243dSDimitry Andric if (MI.hasOneMemOperand())
156bdd1243dSDimitry Andric SecondMI->addMemOperand(*MF, *MI.memoperands_begin());
157bdd1243dSDimitry Andric
158bdd1243dSDimitry Andric MI.eraseFromParent();
159bdd1243dSDimitry Andric return true;
160bdd1243dSDimitry Andric }
161bdd1243dSDimitry Andric
expandLoadAddressPcrel(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)162bdd1243dSDimitry Andric bool LoongArchPreRAExpandPseudo::expandLoadAddressPcrel(
163bdd1243dSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
1641db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
165bdd1243dSDimitry Andric // Code Sequence:
166bdd1243dSDimitry Andric // pcalau12i $rd, %pc_hi20(sym)
167bdd1243dSDimitry Andric // addi.w/d $rd, $rd, %pc_lo12(sym)
168bdd1243dSDimitry Andric MachineFunction *MF = MBB.getParent();
169bdd1243dSDimitry Andric const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
170bdd1243dSDimitry Andric unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
171bdd1243dSDimitry Andric return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_PCREL_HI,
172bdd1243dSDimitry Andric SecondOpcode, LoongArchII::MO_PCREL_LO);
173bdd1243dSDimitry Andric }
174bdd1243dSDimitry Andric
expandLoadAddressGot(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)175bdd1243dSDimitry Andric bool LoongArchPreRAExpandPseudo::expandLoadAddressGot(
176bdd1243dSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
1771db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
178bdd1243dSDimitry Andric // Code Sequence:
179bdd1243dSDimitry Andric // pcalau12i $rd, %got_pc_hi20(sym)
180bdd1243dSDimitry Andric // ld.w/d $rd, $rd, %got_pc_lo12(sym)
181bdd1243dSDimitry Andric MachineFunction *MF = MBB.getParent();
182bdd1243dSDimitry Andric const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
183bdd1243dSDimitry Andric unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
184bdd1243dSDimitry Andric return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GOT_PC_HI,
185bdd1243dSDimitry Andric SecondOpcode, LoongArchII::MO_GOT_PC_LO);
186bdd1243dSDimitry Andric }
187bdd1243dSDimitry Andric
expandLoadAddressTLSLE(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)188bdd1243dSDimitry Andric bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLE(
189bdd1243dSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
190bdd1243dSDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
191bdd1243dSDimitry Andric // Code Sequence:
192bdd1243dSDimitry Andric // lu12i.w $rd, %le_hi20(sym)
193bdd1243dSDimitry Andric // ori $rd, $rd, %le_lo12(sym)
19406c3fb27SDimitry Andric //
19506c3fb27SDimitry Andric // And additionally if generating code using the large code model:
19606c3fb27SDimitry Andric //
19706c3fb27SDimitry Andric // lu32i.d $rd, %le64_lo20(sym)
19806c3fb27SDimitry Andric // lu52i.d $rd, $rd, %le64_hi12(sym)
199bdd1243dSDimitry Andric MachineFunction *MF = MBB.getParent();
200bdd1243dSDimitry Andric MachineInstr &MI = *MBBI;
201bdd1243dSDimitry Andric DebugLoc DL = MI.getDebugLoc();
202bdd1243dSDimitry Andric
20306c3fb27SDimitry Andric bool Large = MF->getTarget().getCodeModel() == CodeModel::Large;
204bdd1243dSDimitry Andric Register DestReg = MI.getOperand(0).getReg();
20506c3fb27SDimitry Andric Register Parts01 =
20606c3fb27SDimitry Andric Large ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)
20706c3fb27SDimitry Andric : DestReg;
20806c3fb27SDimitry Andric Register Part1 =
209bdd1243dSDimitry Andric MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
210bdd1243dSDimitry Andric MachineOperand &Symbol = MI.getOperand(1);
211bdd1243dSDimitry Andric
21206c3fb27SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W), Part1)
213bdd1243dSDimitry Andric .addDisp(Symbol, 0, LoongArchII::MO_LE_HI);
214bdd1243dSDimitry Andric
21506c3fb27SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ORI), Parts01)
21606c3fb27SDimitry Andric .addReg(Part1, RegState::Kill)
217bdd1243dSDimitry Andric .addDisp(Symbol, 0, LoongArchII::MO_LE_LO);
218bdd1243dSDimitry Andric
21906c3fb27SDimitry Andric if (Large) {
22006c3fb27SDimitry Andric Register Parts012 =
22106c3fb27SDimitry Andric MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
22206c3fb27SDimitry Andric
22306c3fb27SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), Parts012)
22406c3fb27SDimitry Andric // "rj" is needed due to InstrInfo pattern requirement.
22506c3fb27SDimitry Andric .addReg(Parts01, RegState::Kill)
22606c3fb27SDimitry Andric .addDisp(Symbol, 0, LoongArchII::MO_LE64_LO);
22706c3fb27SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), DestReg)
22806c3fb27SDimitry Andric .addReg(Parts012, RegState::Kill)
22906c3fb27SDimitry Andric .addDisp(Symbol, 0, LoongArchII::MO_LE64_HI);
23006c3fb27SDimitry Andric }
23106c3fb27SDimitry Andric
232bdd1243dSDimitry Andric MI.eraseFromParent();
233bdd1243dSDimitry Andric return true;
234bdd1243dSDimitry Andric }
235bdd1243dSDimitry Andric
expandLoadAddressTLSIE(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)236bdd1243dSDimitry Andric bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSIE(
237bdd1243dSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
2381db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
239bdd1243dSDimitry Andric // Code Sequence:
240bdd1243dSDimitry Andric // pcalau12i $rd, %ie_pc_hi20(sym)
241bdd1243dSDimitry Andric // ld.w/d $rd, $rd, %ie_pc_lo12(sym)
242bdd1243dSDimitry Andric MachineFunction *MF = MBB.getParent();
243bdd1243dSDimitry Andric const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
244bdd1243dSDimitry Andric unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
245bdd1243dSDimitry Andric return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_IE_PC_HI,
246bdd1243dSDimitry Andric SecondOpcode, LoongArchII::MO_IE_PC_LO);
247bdd1243dSDimitry Andric }
248bdd1243dSDimitry Andric
expandLoadAddressTLSLD(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)249bdd1243dSDimitry Andric bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLD(
250bdd1243dSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
2511db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
252bdd1243dSDimitry Andric // Code Sequence:
253bdd1243dSDimitry Andric // pcalau12i $rd, %ld_pc_hi20(sym)
254bdd1243dSDimitry Andric // addi.w/d $rd, $rd, %got_pc_lo12(sym)
255bdd1243dSDimitry Andric MachineFunction *MF = MBB.getParent();
256bdd1243dSDimitry Andric const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
257bdd1243dSDimitry Andric unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
258bdd1243dSDimitry Andric return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_LD_PC_HI,
259bdd1243dSDimitry Andric SecondOpcode, LoongArchII::MO_GOT_PC_LO);
260bdd1243dSDimitry Andric }
261bdd1243dSDimitry Andric
expandLoadAddressTLSGD(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)262bdd1243dSDimitry Andric bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSGD(
263bdd1243dSDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
2641db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
265bdd1243dSDimitry Andric // Code Sequence:
266bdd1243dSDimitry Andric // pcalau12i $rd, %gd_pc_hi20(sym)
267bdd1243dSDimitry Andric // addi.w/d $rd, $rd, %got_pc_lo12(sym)
268bdd1243dSDimitry Andric MachineFunction *MF = MBB.getParent();
269bdd1243dSDimitry Andric const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
270bdd1243dSDimitry Andric unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
271bdd1243dSDimitry Andric return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GD_PC_HI,
272bdd1243dSDimitry Andric SecondOpcode, LoongArchII::MO_GOT_PC_LO);
273bdd1243dSDimitry Andric }
274bdd1243dSDimitry Andric
expandLoadAddressTLSDesc(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)2750fca6ea1SDimitry Andric bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc(
2760fca6ea1SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
2770fca6ea1SDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
2780fca6ea1SDimitry Andric // Code Sequence:
2790fca6ea1SDimitry Andric // pcalau12i $a0, %desc_pc_hi20(sym)
2800fca6ea1SDimitry Andric // addi.w/d $a0, $a0, %desc_pc_lo12(sym)
2810fca6ea1SDimitry Andric // ld.w/d $ra, $a0, %desc_ld(sym)
2820fca6ea1SDimitry Andric // jirl $ra, $ra, %desc_ld(sym)
2830fca6ea1SDimitry Andric // add.d $dst, $a0, $tp
2840fca6ea1SDimitry Andric MachineFunction *MF = MBB.getParent();
2850fca6ea1SDimitry Andric MachineInstr &MI = *MBBI;
2860fca6ea1SDimitry Andric DebugLoc DL = MI.getDebugLoc();
2870fca6ea1SDimitry Andric
2880fca6ea1SDimitry Andric const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
2890fca6ea1SDimitry Andric unsigned ADD = STI.is64Bit() ? LoongArch::ADD_D : LoongArch::ADD_W;
2900fca6ea1SDimitry Andric unsigned ADDI = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
2910fca6ea1SDimitry Andric unsigned LD = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
2920fca6ea1SDimitry Andric
2930fca6ea1SDimitry Andric Register DestReg = MI.getOperand(0).getReg();
2940fca6ea1SDimitry Andric Register ScratchReg =
2950fca6ea1SDimitry Andric MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
2960fca6ea1SDimitry Andric MachineOperand &Symbol = MI.getOperand(1);
2970fca6ea1SDimitry Andric
2980fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg)
2990fca6ea1SDimitry Andric .addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_HI);
3000fca6ea1SDimitry Andric
3010fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(ADDI), LoongArch::R4)
3020fca6ea1SDimitry Andric .addReg(ScratchReg)
3030fca6ea1SDimitry Andric .addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_LO);
3040fca6ea1SDimitry Andric
3050fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LD), LoongArch::R1)
3060fca6ea1SDimitry Andric .addReg(LoongArch::R4)
3070fca6ea1SDimitry Andric .addDisp(Symbol, 0, LoongArchII::MO_DESC_LD);
3080fca6ea1SDimitry Andric
3090fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PseudoDESC_CALL), LoongArch::R1)
3100fca6ea1SDimitry Andric .addReg(LoongArch::R1)
3110fca6ea1SDimitry Andric .addDisp(Symbol, 0, LoongArchII::MO_DESC_CALL);
3120fca6ea1SDimitry Andric
3130fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(ADD), DestReg)
3140fca6ea1SDimitry Andric .addReg(LoongArch::R4)
3150fca6ea1SDimitry Andric .addReg(LoongArch::R2);
3160fca6ea1SDimitry Andric
3170fca6ea1SDimitry Andric MI.eraseFromParent();
3180fca6ea1SDimitry Andric return true;
3190fca6ea1SDimitry Andric }
3200fca6ea1SDimitry Andric
321b121cb00SDimitry Andric class LoongArchExpandPseudo : public MachineFunctionPass {
322b121cb00SDimitry Andric public:
323b121cb00SDimitry Andric const LoongArchInstrInfo *TII;
324b121cb00SDimitry Andric static char ID;
325b121cb00SDimitry Andric
LoongArchExpandPseudo()326b121cb00SDimitry Andric LoongArchExpandPseudo() : MachineFunctionPass(ID) {
327b121cb00SDimitry Andric initializeLoongArchExpandPseudoPass(*PassRegistry::getPassRegistry());
328b121cb00SDimitry Andric }
329b121cb00SDimitry Andric
330b121cb00SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override;
331b121cb00SDimitry Andric
getPassName() const332b121cb00SDimitry Andric StringRef getPassName() const override {
333b121cb00SDimitry Andric return LOONGARCH_EXPAND_PSEUDO_NAME;
334b121cb00SDimitry Andric }
335b121cb00SDimitry Andric
336b121cb00SDimitry Andric private:
337b121cb00SDimitry Andric bool expandMBB(MachineBasicBlock &MBB);
338b121cb00SDimitry Andric bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
339b121cb00SDimitry Andric MachineBasicBlock::iterator &NextMBBI);
340b121cb00SDimitry Andric bool expandCopyCFR(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
341b121cb00SDimitry Andric MachineBasicBlock::iterator &NextMBBI);
3421db9f3b2SDimitry Andric bool expandLargeAddressLoad(MachineBasicBlock &MBB,
3431db9f3b2SDimitry Andric MachineBasicBlock::iterator MBBI,
3441db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI,
3451db9f3b2SDimitry Andric unsigned LastOpcode, unsigned IdentifyingMO);
3461db9f3b2SDimitry Andric bool expandLargeAddressLoad(MachineBasicBlock &MBB,
3471db9f3b2SDimitry Andric MachineBasicBlock::iterator MBBI,
3481db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI,
3491db9f3b2SDimitry Andric unsigned LastOpcode, unsigned IdentifyingMO,
3501db9f3b2SDimitry Andric const MachineOperand &Symbol, Register DestReg,
3511db9f3b2SDimitry Andric bool EraseFromParent);
3521db9f3b2SDimitry Andric bool expandLoadAddressPcrelLarge(MachineBasicBlock &MBB,
3531db9f3b2SDimitry Andric MachineBasicBlock::iterator MBBI,
3541db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI);
3551db9f3b2SDimitry Andric bool expandLoadAddressGotLarge(MachineBasicBlock &MBB,
3561db9f3b2SDimitry Andric MachineBasicBlock::iterator MBBI,
3571db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI);
3581db9f3b2SDimitry Andric bool expandLoadAddressTLSIELarge(MachineBasicBlock &MBB,
3591db9f3b2SDimitry Andric MachineBasicBlock::iterator MBBI,
3601db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI);
3611db9f3b2SDimitry Andric bool expandLoadAddressTLSLDLarge(MachineBasicBlock &MBB,
3621db9f3b2SDimitry Andric MachineBasicBlock::iterator MBBI,
3631db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI);
3641db9f3b2SDimitry Andric bool expandLoadAddressTLSGDLarge(MachineBasicBlock &MBB,
3651db9f3b2SDimitry Andric MachineBasicBlock::iterator MBBI,
3661db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI);
3670fca6ea1SDimitry Andric bool expandLoadAddressTLSDescPcLarge(MachineBasicBlock &MBB,
3680fca6ea1SDimitry Andric MachineBasicBlock::iterator MBBI,
3690fca6ea1SDimitry Andric MachineBasicBlock::iterator &NextMBBI);
3701db9f3b2SDimitry Andric bool expandFunctionCALL(MachineBasicBlock &MBB,
3711db9f3b2SDimitry Andric MachineBasicBlock::iterator MBBI,
3721db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI,
3731db9f3b2SDimitry Andric bool IsTailCall);
374b121cb00SDimitry Andric };
375b121cb00SDimitry Andric
376b121cb00SDimitry Andric char LoongArchExpandPseudo::ID = 0;
377b121cb00SDimitry Andric
runOnMachineFunction(MachineFunction & MF)378b121cb00SDimitry Andric bool LoongArchExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
379b121cb00SDimitry Andric TII =
380b121cb00SDimitry Andric static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo());
381b121cb00SDimitry Andric
382b121cb00SDimitry Andric bool Modified = false;
383b121cb00SDimitry Andric for (auto &MBB : MF)
384b121cb00SDimitry Andric Modified |= expandMBB(MBB);
385b121cb00SDimitry Andric
386b121cb00SDimitry Andric return Modified;
387b121cb00SDimitry Andric }
388b121cb00SDimitry Andric
expandMBB(MachineBasicBlock & MBB)389b121cb00SDimitry Andric bool LoongArchExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
390b121cb00SDimitry Andric bool Modified = false;
391b121cb00SDimitry Andric
392b121cb00SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
393b121cb00SDimitry Andric while (MBBI != E) {
394b121cb00SDimitry Andric MachineBasicBlock::iterator NMBBI = std::next(MBBI);
395b121cb00SDimitry Andric Modified |= expandMI(MBB, MBBI, NMBBI);
396b121cb00SDimitry Andric MBBI = NMBBI;
397b121cb00SDimitry Andric }
398b121cb00SDimitry Andric
399b121cb00SDimitry Andric return Modified;
400b121cb00SDimitry Andric }
401b121cb00SDimitry Andric
expandMI(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)402b121cb00SDimitry Andric bool LoongArchExpandPseudo::expandMI(MachineBasicBlock &MBB,
403b121cb00SDimitry Andric MachineBasicBlock::iterator MBBI,
404b121cb00SDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
405b121cb00SDimitry Andric switch (MBBI->getOpcode()) {
406b121cb00SDimitry Andric case LoongArch::PseudoCopyCFR:
407b121cb00SDimitry Andric return expandCopyCFR(MBB, MBBI, NextMBBI);
4081db9f3b2SDimitry Andric case LoongArch::PseudoLA_PCREL_LARGE:
4091db9f3b2SDimitry Andric return expandLoadAddressPcrelLarge(MBB, MBBI, NextMBBI);
4101db9f3b2SDimitry Andric case LoongArch::PseudoLA_GOT_LARGE:
4111db9f3b2SDimitry Andric return expandLoadAddressGotLarge(MBB, MBBI, NextMBBI);
4121db9f3b2SDimitry Andric case LoongArch::PseudoLA_TLS_IE_LARGE:
4131db9f3b2SDimitry Andric return expandLoadAddressTLSIELarge(MBB, MBBI, NextMBBI);
4141db9f3b2SDimitry Andric case LoongArch::PseudoLA_TLS_LD_LARGE:
4151db9f3b2SDimitry Andric return expandLoadAddressTLSLDLarge(MBB, MBBI, NextMBBI);
4161db9f3b2SDimitry Andric case LoongArch::PseudoLA_TLS_GD_LARGE:
4171db9f3b2SDimitry Andric return expandLoadAddressTLSGDLarge(MBB, MBBI, NextMBBI);
4180fca6ea1SDimitry Andric case LoongArch::PseudoLA_TLS_DESC_PC_LARGE:
4190fca6ea1SDimitry Andric return expandLoadAddressTLSDescPcLarge(MBB, MBBI, NextMBBI);
4201db9f3b2SDimitry Andric case LoongArch::PseudoCALL:
4211db9f3b2SDimitry Andric case LoongArch::PseudoCALL_MEDIUM:
4221db9f3b2SDimitry Andric case LoongArch::PseudoCALL_LARGE:
4231db9f3b2SDimitry Andric return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
4241db9f3b2SDimitry Andric case LoongArch::PseudoTAIL:
4251db9f3b2SDimitry Andric case LoongArch::PseudoTAIL_MEDIUM:
4261db9f3b2SDimitry Andric case LoongArch::PseudoTAIL_LARGE:
4271db9f3b2SDimitry Andric return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
428b121cb00SDimitry Andric }
429b121cb00SDimitry Andric
430b121cb00SDimitry Andric return false;
431b121cb00SDimitry Andric }
432b121cb00SDimitry Andric
expandCopyCFR(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)433b121cb00SDimitry Andric bool LoongArchExpandPseudo::expandCopyCFR(
434b121cb00SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
435b121cb00SDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
436b121cb00SDimitry Andric MachineFunction *MF = MBB.getParent();
437b121cb00SDimitry Andric MachineInstr &MI = *MBBI;
438b121cb00SDimitry Andric DebugLoc DL = MI.getDebugLoc();
439b121cb00SDimitry Andric
440b121cb00SDimitry Andric // Expand:
441b121cb00SDimitry Andric // MBB:
442b121cb00SDimitry Andric // fcmp.caf.s $dst, $fa0, $fa0 # set $dst 0(false)
443b121cb00SDimitry Andric // bceqz $src, SinkBB
444b121cb00SDimitry Andric // FalseBB:
445b121cb00SDimitry Andric // fcmp.cueq.s $dst, $fa0, $fa0 # set $dst 1(true)
446b121cb00SDimitry Andric // SinkBB:
447b121cb00SDimitry Andric // fallthrough
448b121cb00SDimitry Andric
449b121cb00SDimitry Andric const BasicBlock *LLVM_BB = MBB.getBasicBlock();
450b121cb00SDimitry Andric auto *FalseBB = MF->CreateMachineBasicBlock(LLVM_BB);
451b121cb00SDimitry Andric auto *SinkBB = MF->CreateMachineBasicBlock(LLVM_BB);
452b121cb00SDimitry Andric
453b121cb00SDimitry Andric MF->insert(++MBB.getIterator(), FalseBB);
454b121cb00SDimitry Andric MF->insert(++FalseBB->getIterator(), SinkBB);
455b121cb00SDimitry Andric
456b121cb00SDimitry Andric Register DestReg = MI.getOperand(0).getReg();
457b121cb00SDimitry Andric Register SrcReg = MI.getOperand(1).getReg();
458b121cb00SDimitry Andric // DestReg = 0
459b121cb00SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::SET_CFR_FALSE), DestReg);
460b121cb00SDimitry Andric // Insert branch instruction.
461b121cb00SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::BCEQZ))
462b121cb00SDimitry Andric .addReg(SrcReg)
463b121cb00SDimitry Andric .addMBB(SinkBB);
464b121cb00SDimitry Andric // DestReg = 1
465b121cb00SDimitry Andric BuildMI(FalseBB, DL, TII->get(LoongArch::SET_CFR_TRUE), DestReg);
466b121cb00SDimitry Andric
467b121cb00SDimitry Andric FalseBB->addSuccessor(SinkBB);
468b121cb00SDimitry Andric
469b121cb00SDimitry Andric SinkBB->splice(SinkBB->end(), &MBB, MI, MBB.end());
470b121cb00SDimitry Andric SinkBB->transferSuccessors(&MBB);
471b121cb00SDimitry Andric
472b121cb00SDimitry Andric MBB.addSuccessor(FalseBB);
473b121cb00SDimitry Andric MBB.addSuccessor(SinkBB);
474b121cb00SDimitry Andric
475b121cb00SDimitry Andric NextMBBI = MBB.end();
476b121cb00SDimitry Andric MI.eraseFromParent();
477b121cb00SDimitry Andric
478b121cb00SDimitry Andric // Make sure live-ins are correctly attached to this new basic block.
479b121cb00SDimitry Andric LivePhysRegs LiveRegs;
480b121cb00SDimitry Andric computeAndAddLiveIns(LiveRegs, *FalseBB);
481b121cb00SDimitry Andric computeAndAddLiveIns(LiveRegs, *SinkBB);
482b121cb00SDimitry Andric
483b121cb00SDimitry Andric return true;
484b121cb00SDimitry Andric }
485b121cb00SDimitry Andric
expandLargeAddressLoad(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI,unsigned LastOpcode,unsigned IdentifyingMO)4861db9f3b2SDimitry Andric bool LoongArchExpandPseudo::expandLargeAddressLoad(
4871db9f3b2SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
4881db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode,
4891db9f3b2SDimitry Andric unsigned IdentifyingMO) {
4901db9f3b2SDimitry Andric MachineInstr &MI = *MBBI;
4911db9f3b2SDimitry Andric return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode, IdentifyingMO,
4921db9f3b2SDimitry Andric MI.getOperand(2), MI.getOperand(0).getReg(),
4931db9f3b2SDimitry Andric true);
4941db9f3b2SDimitry Andric }
4951db9f3b2SDimitry Andric
expandLargeAddressLoad(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI,unsigned LastOpcode,unsigned IdentifyingMO,const MachineOperand & Symbol,Register DestReg,bool EraseFromParent)4961db9f3b2SDimitry Andric bool LoongArchExpandPseudo::expandLargeAddressLoad(
4971db9f3b2SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
4981db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode,
4991db9f3b2SDimitry Andric unsigned IdentifyingMO, const MachineOperand &Symbol, Register DestReg,
5001db9f3b2SDimitry Andric bool EraseFromParent) {
5011db9f3b2SDimitry Andric // Code Sequence:
5021db9f3b2SDimitry Andric //
5031db9f3b2SDimitry Andric // Part1: pcalau12i $dst, %MO1(sym)
5041db9f3b2SDimitry Andric // Part0: addi.d $t8, $zero, %MO0(sym)
5051db9f3b2SDimitry Andric // Part2: lu32i.d $t8, %MO2(sym)
5061db9f3b2SDimitry Andric // Part3: lu52i.d $t8, $t8, %MO3(sym)
5071db9f3b2SDimitry Andric // Fin: LastOpcode $dst, $t8, $dst
5081db9f3b2SDimitry Andric
5091db9f3b2SDimitry Andric unsigned MO0, MO1, MO2, MO3;
5101db9f3b2SDimitry Andric switch (IdentifyingMO) {
5111db9f3b2SDimitry Andric default:
5121db9f3b2SDimitry Andric llvm_unreachable("unsupported identifying MO");
5131db9f3b2SDimitry Andric case LoongArchII::MO_PCREL_LO:
5141db9f3b2SDimitry Andric MO0 = IdentifyingMO;
5151db9f3b2SDimitry Andric MO1 = LoongArchII::MO_PCREL_HI;
5161db9f3b2SDimitry Andric MO2 = LoongArchII::MO_PCREL64_LO;
5171db9f3b2SDimitry Andric MO3 = LoongArchII::MO_PCREL64_HI;
5181db9f3b2SDimitry Andric break;
5191db9f3b2SDimitry Andric case LoongArchII::MO_GOT_PC_HI:
5201db9f3b2SDimitry Andric case LoongArchII::MO_LD_PC_HI:
5211db9f3b2SDimitry Andric case LoongArchII::MO_GD_PC_HI:
5221db9f3b2SDimitry Andric // These cases relocate just like the GOT case, except for Part1.
5231db9f3b2SDimitry Andric MO0 = LoongArchII::MO_GOT_PC_LO;
5241db9f3b2SDimitry Andric MO1 = IdentifyingMO;
5251db9f3b2SDimitry Andric MO2 = LoongArchII::MO_GOT_PC64_LO;
5261db9f3b2SDimitry Andric MO3 = LoongArchII::MO_GOT_PC64_HI;
5271db9f3b2SDimitry Andric break;
5281db9f3b2SDimitry Andric case LoongArchII::MO_IE_PC_LO:
5291db9f3b2SDimitry Andric MO0 = IdentifyingMO;
5301db9f3b2SDimitry Andric MO1 = LoongArchII::MO_IE_PC_HI;
5311db9f3b2SDimitry Andric MO2 = LoongArchII::MO_IE_PC64_LO;
5321db9f3b2SDimitry Andric MO3 = LoongArchII::MO_IE_PC64_HI;
5331db9f3b2SDimitry Andric break;
5341db9f3b2SDimitry Andric }
5351db9f3b2SDimitry Andric
5361db9f3b2SDimitry Andric MachineInstr &MI = *MBBI;
5371db9f3b2SDimitry Andric DebugLoc DL = MI.getDebugLoc();
5381db9f3b2SDimitry Andric Register ScratchReg = LoongArch::R20; // $t8
5391db9f3b2SDimitry Andric
5401db9f3b2SDimitry Andric assert(MBB.getParent()->getSubtarget<LoongArchSubtarget>().is64Bit() &&
5411db9f3b2SDimitry Andric "Large code model requires LA64");
5421db9f3b2SDimitry Andric
5431db9f3b2SDimitry Andric auto Part1 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), DestReg);
5441db9f3b2SDimitry Andric auto Part0 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADDI_D), ScratchReg)
5451db9f3b2SDimitry Andric .addReg(LoongArch::R0);
5461db9f3b2SDimitry Andric auto Part2 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), ScratchReg)
5471db9f3b2SDimitry Andric // "rj" is needed due to InstrInfo pattern requirement.
5481db9f3b2SDimitry Andric .addReg(ScratchReg);
5491db9f3b2SDimitry Andric auto Part3 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), ScratchReg)
5501db9f3b2SDimitry Andric .addReg(ScratchReg);
5511db9f3b2SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LastOpcode), DestReg)
5521db9f3b2SDimitry Andric .addReg(ScratchReg)
5531db9f3b2SDimitry Andric .addReg(DestReg);
5541db9f3b2SDimitry Andric
5551db9f3b2SDimitry Andric if (Symbol.getType() == MachineOperand::MO_ExternalSymbol) {
5561db9f3b2SDimitry Andric const char *SymName = Symbol.getSymbolName();
5571db9f3b2SDimitry Andric Part0.addExternalSymbol(SymName, MO0);
5581db9f3b2SDimitry Andric Part1.addExternalSymbol(SymName, MO1);
5591db9f3b2SDimitry Andric Part2.addExternalSymbol(SymName, MO2);
5601db9f3b2SDimitry Andric Part3.addExternalSymbol(SymName, MO3);
5611db9f3b2SDimitry Andric } else {
5621db9f3b2SDimitry Andric Part0.addDisp(Symbol, 0, MO0);
5631db9f3b2SDimitry Andric Part1.addDisp(Symbol, 0, MO1);
5641db9f3b2SDimitry Andric Part2.addDisp(Symbol, 0, MO2);
5651db9f3b2SDimitry Andric Part3.addDisp(Symbol, 0, MO3);
5661db9f3b2SDimitry Andric }
5671db9f3b2SDimitry Andric
5681db9f3b2SDimitry Andric if (EraseFromParent)
5691db9f3b2SDimitry Andric MI.eraseFromParent();
5701db9f3b2SDimitry Andric
5711db9f3b2SDimitry Andric return true;
5721db9f3b2SDimitry Andric }
5731db9f3b2SDimitry Andric
expandLoadAddressPcrelLarge(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)5741db9f3b2SDimitry Andric bool LoongArchExpandPseudo::expandLoadAddressPcrelLarge(
5751db9f3b2SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
5761db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
5771db9f3b2SDimitry Andric // Emit the 5-insn large address load sequence with the `%pc` family of
5781db9f3b2SDimitry Andric // relocs.
5791db9f3b2SDimitry Andric return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,
5801db9f3b2SDimitry Andric LoongArchII::MO_PCREL_LO);
5811db9f3b2SDimitry Andric }
5821db9f3b2SDimitry Andric
expandLoadAddressGotLarge(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)5831db9f3b2SDimitry Andric bool LoongArchExpandPseudo::expandLoadAddressGotLarge(
5841db9f3b2SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
5851db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
5861db9f3b2SDimitry Andric // Emit the 5-insn large address load sequence with the `%got_pc` family
5871db9f3b2SDimitry Andric // of relocs, loading the result from GOT with `ldx.d` in the end.
5881db9f3b2SDimitry Andric return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::LDX_D,
5891db9f3b2SDimitry Andric LoongArchII::MO_GOT_PC_HI);
5901db9f3b2SDimitry Andric }
5911db9f3b2SDimitry Andric
expandLoadAddressTLSIELarge(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)5921db9f3b2SDimitry Andric bool LoongArchExpandPseudo::expandLoadAddressTLSIELarge(
5931db9f3b2SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
5941db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
5951db9f3b2SDimitry Andric // Emit the 5-insn large address load sequence with the `%ie_pc` family
5961db9f3b2SDimitry Andric // of relocs, loading the result with `ldx.d` in the end.
5971db9f3b2SDimitry Andric return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::LDX_D,
5981db9f3b2SDimitry Andric LoongArchII::MO_IE_PC_LO);
5991db9f3b2SDimitry Andric }
6001db9f3b2SDimitry Andric
expandLoadAddressTLSLDLarge(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)6011db9f3b2SDimitry Andric bool LoongArchExpandPseudo::expandLoadAddressTLSLDLarge(
6021db9f3b2SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
6031db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
6041db9f3b2SDimitry Andric // Emit the 5-insn large address load sequence with the `%got_pc` family
6051db9f3b2SDimitry Andric // of relocs, with the `pcalau12i` insn relocated with `%ld_pc_hi20`.
6061db9f3b2SDimitry Andric return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,
6071db9f3b2SDimitry Andric LoongArchII::MO_LD_PC_HI);
6081db9f3b2SDimitry Andric }
6091db9f3b2SDimitry Andric
expandLoadAddressTLSGDLarge(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)6101db9f3b2SDimitry Andric bool LoongArchExpandPseudo::expandLoadAddressTLSGDLarge(
6111db9f3b2SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
6121db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
6131db9f3b2SDimitry Andric // Emit the 5-insn large address load sequence with the `%got_pc` family
6141db9f3b2SDimitry Andric // of relocs, with the `pcalau12i` insn relocated with `%gd_pc_hi20`.
6151db9f3b2SDimitry Andric return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,
6161db9f3b2SDimitry Andric LoongArchII::MO_GD_PC_HI);
6171db9f3b2SDimitry Andric }
6181db9f3b2SDimitry Andric
expandLoadAddressTLSDescPcLarge(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)6190fca6ea1SDimitry Andric bool LoongArchExpandPseudo::expandLoadAddressTLSDescPcLarge(
6200fca6ea1SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
6210fca6ea1SDimitry Andric MachineBasicBlock::iterator &NextMBBI) {
6220fca6ea1SDimitry Andric // Code Sequence:
6230fca6ea1SDimitry Andric //
6240fca6ea1SDimitry Andric // pcalau12i $a0, %desc_pc_hi20(sym)
6250fca6ea1SDimitry Andric // addi.d $t8, $zero, %desc_pc_lo12(sym)
6260fca6ea1SDimitry Andric // lu32i.d $t8, %desc64_pc_lo20(sym)
6270fca6ea1SDimitry Andric // lu52i.d $t8, $t8, %desc64_pc_hi12(sym)
6280fca6ea1SDimitry Andric // add.d $a0, $a0, $t8
6290fca6ea1SDimitry Andric // ld.d $ra, $a0, %desc_ld(sym)
6300fca6ea1SDimitry Andric // jirl $ra, $ra, %desc_call(sym)
6310fca6ea1SDimitry Andric // add.d $dst, $a0, $tp
6320fca6ea1SDimitry Andric
6330fca6ea1SDimitry Andric MachineInstr &MI = *MBBI;
6340fca6ea1SDimitry Andric DebugLoc DL = MI.getDebugLoc();
6350fca6ea1SDimitry Andric Register DestReg = MI.getOperand(0).getReg();
6360fca6ea1SDimitry Andric MachineOperand &Symbol = MI.getOperand(2);
6370fca6ea1SDimitry Andric Register ScratchReg = LoongArch::R20; // $t8
6380fca6ea1SDimitry Andric
6390fca6ea1SDimitry Andric assert(MBB.getParent()->getSubtarget<LoongArchSubtarget>().is64Bit() &&
6400fca6ea1SDimitry Andric "Large code model requires LA64");
6410fca6ea1SDimitry Andric
6420fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), LoongArch::R4)
6430fca6ea1SDimitry Andric .addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_HI);
6440fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADDI_D), ScratchReg)
6450fca6ea1SDimitry Andric .addReg(LoongArch::R0)
6460fca6ea1SDimitry Andric .addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_LO);
6470fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), ScratchReg)
6480fca6ea1SDimitry Andric .addReg(ScratchReg)
6490fca6ea1SDimitry Andric .addDisp(Symbol, 0, LoongArchII::MO_DESC64_PC_LO);
6500fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), ScratchReg)
6510fca6ea1SDimitry Andric .addReg(ScratchReg)
6520fca6ea1SDimitry Andric .addDisp(Symbol, 0, LoongArchII::MO_DESC64_PC_HI);
6530fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADD_D), LoongArch::R4)
6540fca6ea1SDimitry Andric .addReg(ScratchReg)
6550fca6ea1SDimitry Andric .addReg(LoongArch::R4);
6560fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LD_D), LoongArch::R1)
6570fca6ea1SDimitry Andric .addReg(LoongArch::R4)
6580fca6ea1SDimitry Andric .addDisp(Symbol, 0, LoongArchII::MO_DESC_LD);
6590fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PseudoDESC_CALL), LoongArch::R1)
6600fca6ea1SDimitry Andric .addReg(LoongArch::R1)
6610fca6ea1SDimitry Andric .addDisp(Symbol, 0, LoongArchII::MO_DESC_CALL);
6620fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADD_D), DestReg)
6630fca6ea1SDimitry Andric .addReg(LoongArch::R4)
6640fca6ea1SDimitry Andric .addReg(LoongArch::R2);
6650fca6ea1SDimitry Andric
6660fca6ea1SDimitry Andric MI.eraseFromParent();
6670fca6ea1SDimitry Andric
6680fca6ea1SDimitry Andric return true;
6690fca6ea1SDimitry Andric }
6700fca6ea1SDimitry Andric
expandFunctionCALL(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI,bool IsTailCall)6711db9f3b2SDimitry Andric bool LoongArchExpandPseudo::expandFunctionCALL(
6721db9f3b2SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
6731db9f3b2SDimitry Andric MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {
6741db9f3b2SDimitry Andric MachineFunction *MF = MBB.getParent();
6751db9f3b2SDimitry Andric MachineInstr &MI = *MBBI;
6761db9f3b2SDimitry Andric DebugLoc DL = MI.getDebugLoc();
6771db9f3b2SDimitry Andric const MachineOperand &Func = MI.getOperand(0);
6781db9f3b2SDimitry Andric MachineInstrBuilder CALL;
6791db9f3b2SDimitry Andric unsigned Opcode;
6801db9f3b2SDimitry Andric
6811db9f3b2SDimitry Andric switch (MF->getTarget().getCodeModel()) {
6821db9f3b2SDimitry Andric default:
6831db9f3b2SDimitry Andric report_fatal_error("Unsupported code model");
6841db9f3b2SDimitry Andric break;
6851db9f3b2SDimitry Andric case CodeModel::Small: {
6861db9f3b2SDimitry Andric // CALL:
6871db9f3b2SDimitry Andric // bl func
6881db9f3b2SDimitry Andric // TAIL:
6891db9f3b2SDimitry Andric // b func
6901db9f3b2SDimitry Andric Opcode = IsTailCall ? LoongArch::PseudoB_TAIL : LoongArch::BL;
6911db9f3b2SDimitry Andric CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).add(Func);
6921db9f3b2SDimitry Andric break;
6931db9f3b2SDimitry Andric }
6941db9f3b2SDimitry Andric case CodeModel::Medium: {
6951db9f3b2SDimitry Andric // CALL:
6961db9f3b2SDimitry Andric // pcaddu18i $ra, %call36(func)
6971db9f3b2SDimitry Andric // jirl $ra, $ra, 0
6981db9f3b2SDimitry Andric // TAIL:
6991db9f3b2SDimitry Andric // pcaddu18i $t8, %call36(func)
7001db9f3b2SDimitry Andric // jr $t8
7011db9f3b2SDimitry Andric Opcode =
7021db9f3b2SDimitry Andric IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
7031db9f3b2SDimitry Andric Register ScratchReg = IsTailCall ? LoongArch::R20 : LoongArch::R1;
7041db9f3b2SDimitry Andric MachineInstrBuilder MIB =
7051db9f3b2SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCADDU18I), ScratchReg);
7061db9f3b2SDimitry Andric
7071db9f3b2SDimitry Andric CALL =
7081db9f3b2SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(ScratchReg).addImm(0);
7091db9f3b2SDimitry Andric
7101db9f3b2SDimitry Andric if (Func.isSymbol())
7111db9f3b2SDimitry Andric MIB.addExternalSymbol(Func.getSymbolName(), LoongArchII::MO_CALL36);
7121db9f3b2SDimitry Andric else
7131db9f3b2SDimitry Andric MIB.addDisp(Func, 0, LoongArchII::MO_CALL36);
7141db9f3b2SDimitry Andric break;
7151db9f3b2SDimitry Andric }
7161db9f3b2SDimitry Andric case CodeModel::Large: {
7171db9f3b2SDimitry Andric // Emit the 5-insn large address load sequence, either directly or
7181db9f3b2SDimitry Andric // indirectly in case of going through the GOT, then JIRL_TAIL or
7191db9f3b2SDimitry Andric // JIRL_CALL to $addr.
7201db9f3b2SDimitry Andric Opcode =
7211db9f3b2SDimitry Andric IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
7221db9f3b2SDimitry Andric Register AddrReg = IsTailCall ? LoongArch::R19 : LoongArch::R1;
7231db9f3b2SDimitry Andric
724*71ac745dSDimitry Andric bool UseGOT = Func.getTargetFlags() == LoongArchII::MO_CALL_PLT;
7251db9f3b2SDimitry Andric unsigned MO = UseGOT ? LoongArchII::MO_GOT_PC_HI : LoongArchII::MO_PCREL_LO;
7261db9f3b2SDimitry Andric unsigned LAOpcode = UseGOT ? LoongArch::LDX_D : LoongArch::ADD_D;
7271db9f3b2SDimitry Andric expandLargeAddressLoad(MBB, MBBI, NextMBBI, LAOpcode, MO, Func, AddrReg,
7281db9f3b2SDimitry Andric false);
7291db9f3b2SDimitry Andric CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(AddrReg).addImm(0);
7301db9f3b2SDimitry Andric break;
7311db9f3b2SDimitry Andric }
7321db9f3b2SDimitry Andric }
7331db9f3b2SDimitry Andric
7341db9f3b2SDimitry Andric // Transfer implicit operands.
7351db9f3b2SDimitry Andric CALL.copyImplicitOps(MI);
7361db9f3b2SDimitry Andric
7371db9f3b2SDimitry Andric // Transfer MI flags.
7381db9f3b2SDimitry Andric CALL.setMIFlags(MI.getFlags());
7391db9f3b2SDimitry Andric
7401db9f3b2SDimitry Andric MI.eraseFromParent();
7411db9f3b2SDimitry Andric return true;
7421db9f3b2SDimitry Andric }
7431db9f3b2SDimitry Andric
744bdd1243dSDimitry Andric } // end namespace
745bdd1243dSDimitry Andric
746bdd1243dSDimitry Andric INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "loongarch-prera-expand-pseudo",
747bdd1243dSDimitry Andric LOONGARCH_PRERA_EXPAND_PSEUDO_NAME, false, false)
748bdd1243dSDimitry Andric
749b121cb00SDimitry Andric INITIALIZE_PASS(LoongArchExpandPseudo, "loongarch-expand-pseudo",
750b121cb00SDimitry Andric LOONGARCH_EXPAND_PSEUDO_NAME, false, false)
751b121cb00SDimitry Andric
752bdd1243dSDimitry Andric namespace llvm {
753bdd1243dSDimitry Andric
createLoongArchPreRAExpandPseudoPass()754bdd1243dSDimitry Andric FunctionPass *createLoongArchPreRAExpandPseudoPass() {
755bdd1243dSDimitry Andric return new LoongArchPreRAExpandPseudo();
756bdd1243dSDimitry Andric }
createLoongArchExpandPseudoPass()757b121cb00SDimitry Andric FunctionPass *createLoongArchExpandPseudoPass() {
758b121cb00SDimitry Andric return new LoongArchExpandPseudo();
759b121cb00SDimitry Andric }
760bdd1243dSDimitry Andric
761bdd1243dSDimitry Andric } // end namespace llvm
762