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 42bdd1243dSDimitry Andric LoongArchPreRAExpandPseudo() : MachineFunctionPass(ID) { 43bdd1243dSDimitry Andric initializeLoongArchPreRAExpandPseudoPass(*PassRegistry::getPassRegistry()); 44bdd1243dSDimitry Andric } 45bdd1243dSDimitry Andric 46bdd1243dSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 47bdd1243dSDimitry Andric 48bdd1243dSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 49bdd1243dSDimitry Andric AU.setPreservesCFG(); 50bdd1243dSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 51bdd1243dSDimitry Andric } 52bdd1243dSDimitry 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 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 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 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 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 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 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 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 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 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 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 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 326b121cb00SDimitry Andric LoongArchExpandPseudo() : MachineFunctionPass(ID) { 327b121cb00SDimitry Andric initializeLoongArchExpandPseudoPass(*PassRegistry::getPassRegistry()); 328b121cb00SDimitry Andric } 329b121cb00SDimitry Andric 330b121cb00SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 331b121cb00SDimitry Andric 332b121cb00SDimitry 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 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 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 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 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 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 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 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 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 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 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 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 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 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 754bdd1243dSDimitry Andric FunctionPass *createLoongArchPreRAExpandPseudoPass() { 755bdd1243dSDimitry Andric return new LoongArchPreRAExpandPseudo(); 756bdd1243dSDimitry Andric } 757b121cb00SDimitry Andric FunctionPass *createLoongArchExpandPseudoPass() { 758b121cb00SDimitry Andric return new LoongArchExpandPseudo(); 759b121cb00SDimitry Andric } 760bdd1243dSDimitry Andric 761bdd1243dSDimitry Andric } // end namespace llvm 762