//===-- LoongArchExpandPseudoInsts.cpp - Expand pseudo instructions -------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains a pass that expands pseudo instructions into target // instructions. // //===----------------------------------------------------------------------===// #include "LoongArch.h" #include "LoongArchInstrInfo.h" #include "LoongArchMachineFunctionInfo.h" #include "MCTargetDesc/LoongArchBaseInfo.h" #include "MCTargetDesc/LoongArchMCTargetDesc.h" #include "llvm/CodeGen/LivePhysRegs.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/Register.h" #include "llvm/MC/MCContext.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; extern cl::opt LArchAnnotateTableJump; #define LOONGARCH_PRERA_EXPAND_PSEUDO_NAME \ "LoongArch Pre-RA pseudo instruction expansion pass" #define LOONGARCH_EXPAND_PSEUDO_NAME \ "LoongArch pseudo instruction expansion pass" namespace { class LoongArchPreRAExpandPseudo : public MachineFunctionPass { public: const LoongArchInstrInfo *TII; static char ID; LoongArchPreRAExpandPseudo() : MachineFunctionPass(ID) { initializeLoongArchPreRAExpandPseudoPass(*PassRegistry::getPassRegistry()); } bool runOnMachineFunction(MachineFunction &MF) override; void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); MachineFunctionPass::getAnalysisUsage(AU); } StringRef getPassName() const override { return LOONGARCH_PRERA_EXPAND_PSEUDO_NAME; } private: bool expandMBB(MachineBasicBlock &MBB); bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI); bool expandPcalau12iInstPair(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, unsigned FlagsHi, unsigned SecondOpcode, unsigned FlagsLo); bool expandLargeAddressLoad(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode, unsigned IdentifyingMO); bool expandLargeAddressLoad(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode, unsigned IdentifyingMO, const MachineOperand &Symbol, Register DestReg, bool EraseFromParent); bool expandLoadAddressPcrel(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool Large = false); bool expandLoadAddressGot(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool Large = false); bool expandLoadAddressTLSLE(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI); bool expandLoadAddressTLSIE(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool Large = false); bool expandLoadAddressTLSLD(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool Large = false); bool expandLoadAddressTLSGD(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool Large = false); bool expandLoadAddressTLSDesc(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool Large = false); bool expandFunctionCALL(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool IsTailCall); void annotateTableJump(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI); }; char LoongArchPreRAExpandPseudo::ID = 0; bool LoongArchPreRAExpandPseudo::runOnMachineFunction(MachineFunction &MF) { TII = static_cast(MF.getSubtarget().getInstrInfo()); bool Modified = false; for (auto &MBB : MF) Modified |= expandMBB(MBB); return Modified; } bool LoongArchPreRAExpandPseudo::expandMBB(MachineBasicBlock &MBB) { bool Modified = false; MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); while (MBBI != E) { MachineBasicBlock::iterator NMBBI = std::next(MBBI); Modified |= expandMI(MBB, MBBI, NMBBI); MBBI = NMBBI; } return Modified; } bool LoongArchPreRAExpandPseudo::expandMI( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI) { switch (MBBI->getOpcode()) { case LoongArch::PseudoLA_PCREL: return expandLoadAddressPcrel(MBB, MBBI, NextMBBI); case LoongArch::PseudoLA_PCREL_LARGE: return expandLoadAddressPcrel(MBB, MBBI, NextMBBI, /*Large=*/true); case LoongArch::PseudoLA_GOT: return expandLoadAddressGot(MBB, MBBI, NextMBBI); case LoongArch::PseudoLA_GOT_LARGE: return expandLoadAddressGot(MBB, MBBI, NextMBBI, /*Large=*/true); case LoongArch::PseudoLA_TLS_LE: return expandLoadAddressTLSLE(MBB, MBBI, NextMBBI); case LoongArch::PseudoLA_TLS_IE: return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI); case LoongArch::PseudoLA_TLS_IE_LARGE: return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI, /*Large=*/true); case LoongArch::PseudoLA_TLS_LD: return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI); case LoongArch::PseudoLA_TLS_LD_LARGE: return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI, /*Large=*/true); case LoongArch::PseudoLA_TLS_GD: return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI); case LoongArch::PseudoLA_TLS_GD_LARGE: return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI, /*Large=*/true); case LoongArch::PseudoLA_TLS_DESC: return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI); case LoongArch::PseudoLA_TLS_DESC_LARGE: return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI, /*Large=*/true); case LoongArch::PseudoCALL: case LoongArch::PseudoCALL_LARGE: return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false); case LoongArch::PseudoTAIL: case LoongArch::PseudoTAIL_LARGE: return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true); case LoongArch::PseudoBRIND: // If the PseudoBRIND is used to table jump, then emit a label to annotate // the `jr` instruction, and save the instructions. if (LArchAnnotateTableJump) annotateTableJump(MBB, MBBI); break; } return false; } bool LoongArchPreRAExpandPseudo::expandPcalau12iInstPair( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, unsigned FlagsHi, unsigned SecondOpcode, unsigned FlagsLo) { MachineFunction *MF = MBB.getParent(); MachineInstr &MI = *MBBI; DebugLoc DL = MI.getDebugLoc(); const auto &STI = MF->getSubtarget(); bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax); Register DestReg = MI.getOperand(0).getReg(); Register ScratchReg = MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); MachineOperand &Symbol = MI.getOperand(1); BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg) .addDisp(Symbol, 0, LoongArchII::encodeFlags(FlagsHi, EnableRelax)); MachineInstr *SecondMI = BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg) .addReg(ScratchReg) .addDisp(Symbol, 0, LoongArchII::encodeFlags(FlagsLo, EnableRelax)); if (MI.hasOneMemOperand()) SecondMI->addMemOperand(*MF, *MI.memoperands_begin()); MI.eraseFromParent(); return true; } bool LoongArchPreRAExpandPseudo::expandLargeAddressLoad( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode, unsigned IdentifyingMO) { MachineInstr &MI = *MBBI; return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode, IdentifyingMO, MI.getOperand(2), MI.getOperand(0).getReg(), true); } bool LoongArchPreRAExpandPseudo::expandLargeAddressLoad( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode, unsigned IdentifyingMO, const MachineOperand &Symbol, Register DestReg, bool EraseFromParent) { // Code Sequence: // // Part1: pcalau12i $scratch, %MO1(sym) // Part0: addi.d $dest, $zero, %MO0(sym) // Part2: lu32i.d $dest, %MO2(sym) // Part3: lu52i.d $dest, $dest, %MO3(sym) // Fin: LastOpcode $dest, $dest, $scratch unsigned MO0, MO1, MO2, MO3; switch (IdentifyingMO) { default: llvm_unreachable("unsupported identifying MO"); case LoongArchII::MO_PCREL_LO: MO0 = IdentifyingMO; MO1 = LoongArchII::MO_PCREL_HI; MO2 = LoongArchII::MO_PCREL64_LO; MO3 = LoongArchII::MO_PCREL64_HI; break; case LoongArchII::MO_GOT_PC_HI: case LoongArchII::MO_LD_PC_HI: case LoongArchII::MO_GD_PC_HI: // These cases relocate just like the GOT case, except for Part1. MO0 = LoongArchII::MO_GOT_PC_LO; MO1 = IdentifyingMO; MO2 = LoongArchII::MO_GOT_PC64_LO; MO3 = LoongArchII::MO_GOT_PC64_HI; break; case LoongArchII::MO_IE_PC_LO: MO0 = IdentifyingMO; MO1 = LoongArchII::MO_IE_PC_HI; MO2 = LoongArchII::MO_IE_PC64_LO; MO3 = LoongArchII::MO_IE_PC64_HI; break; } MachineFunction *MF = MBB.getParent(); MachineInstr &MI = *MBBI; DebugLoc DL = MI.getDebugLoc(); assert(MF->getSubtarget().is64Bit() && "Large code model requires LA64"); Register TmpPart1 = MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); Register TmpPart0 = DestReg.isVirtual() ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass) : DestReg; Register TmpParts02 = DestReg.isVirtual() ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass) : DestReg; Register TmpParts023 = DestReg.isVirtual() ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass) : DestReg; auto Part1 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), TmpPart1); auto Part0 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADDI_D), TmpPart0) .addReg(LoongArch::R0); auto Part2 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), TmpParts02) // "rj" is needed due to InstrInfo pattern requirement. .addReg(TmpPart0, RegState::Kill); auto Part3 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), TmpParts023) .addReg(TmpParts02, RegState::Kill); BuildMI(MBB, MBBI, DL, TII->get(LastOpcode), DestReg) .addReg(TmpParts023) .addReg(TmpPart1, RegState::Kill); if (Symbol.getType() == MachineOperand::MO_ExternalSymbol) { const char *SymName = Symbol.getSymbolName(); Part0.addExternalSymbol(SymName, MO0); Part1.addExternalSymbol(SymName, MO1); Part2.addExternalSymbol(SymName, MO2); Part3.addExternalSymbol(SymName, MO3); } else { Part0.addDisp(Symbol, 0, MO0); Part1.addDisp(Symbol, 0, MO1); Part2.addDisp(Symbol, 0, MO2); Part3.addDisp(Symbol, 0, MO3); } if (EraseFromParent) MI.eraseFromParent(); return true; } bool LoongArchPreRAExpandPseudo::expandLoadAddressPcrel( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool Large) { if (Large) // Emit the 5-insn large address load sequence with the `%pc` family of // relocs. return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D, LoongArchII::MO_PCREL_LO); // Code Sequence: // pcalau12i $rd, %pc_hi20(sym) // addi.w/d $rd, $rd, %pc_lo12(sym) MachineFunction *MF = MBB.getParent(); const auto &STI = MF->getSubtarget(); unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_PCREL_HI, SecondOpcode, LoongArchII::MO_PCREL_LO); } bool LoongArchPreRAExpandPseudo::expandLoadAddressGot( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool Large) { if (Large) // Emit the 5-insn large address load sequence with the `%got_pc` family // of relocs, loading the result from GOT with `ldx.d` in the end. return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::LDX_D, LoongArchII::MO_GOT_PC_HI); // Code Sequence: // pcalau12i $rd, %got_pc_hi20(sym) // ld.w/d $rd, $rd, %got_pc_lo12(sym) MachineFunction *MF = MBB.getParent(); const auto &STI = MF->getSubtarget(); unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GOT_PC_HI, SecondOpcode, LoongArchII::MO_GOT_PC_LO); } bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLE( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI) { // Code Sequence: // lu12i.w $rd, %le_hi20_r(sym) // add.w/d $rd, $rd, $tp, %le_add_r(sym) // addi.w/d $rd, $rd, %le_lo12_r(sym) // // Code Sequence while using the large code model: // lu12i.w $rd, %le_hi20(sym) // ori $rd, $rd, %le_lo12(sym) // lu32i.d $rd, %le64_lo20(sym) // lu52i.d $rd, $rd, %le64_hi12(sym) MachineFunction *MF = MBB.getParent(); MachineInstr &MI = *MBBI; DebugLoc DL = MI.getDebugLoc(); bool Large = MF->getTarget().getCodeModel() == CodeModel::Large; Register DestReg = MI.getOperand(0).getReg(); Register Parts01 = MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); Register Part1 = MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); MachineOperand &Symbol = MI.getOperand(1); if (!Large) { BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W), Part1) .addDisp(Symbol, 0, LoongArchII::MO_LE_HI_R); const auto &STI = MF->getSubtarget(); unsigned AddOp = STI.is64Bit() ? LoongArch::PseudoAddTPRel_D : LoongArch::PseudoAddTPRel_W; BuildMI(MBB, MBBI, DL, TII->get(AddOp), Parts01) .addReg(Part1, RegState::Kill) .addReg(LoongArch::R2) .addDisp(Symbol, 0, LoongArchII::MO_LE_ADD_R); unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; BuildMI(MBB, MBBI, DL, TII->get(AddiOp), DestReg) .addReg(Parts01, RegState::Kill) .addDisp(Symbol, 0, LoongArchII::MO_LE_LO_R); } else { BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W), Part1) .addDisp(Symbol, 0, LoongArchII::MO_LE_HI); BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ORI), Parts01) .addReg(Part1, RegState::Kill) .addDisp(Symbol, 0, LoongArchII::MO_LE_LO); Register Parts012 = MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), Parts012) // "rj" is needed due to InstrInfo pattern requirement. .addReg(Parts01, RegState::Kill) .addDisp(Symbol, 0, LoongArchII::MO_LE64_LO); BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), DestReg) .addReg(Parts012, RegState::Kill) .addDisp(Symbol, 0, LoongArchII::MO_LE64_HI); } MI.eraseFromParent(); return true; } bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSIE( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool Large) { if (Large) // Emit the 5-insn large address load sequence with the `%ie_pc` family // of relocs, loading the result with `ldx.d` in the end. return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::LDX_D, LoongArchII::MO_IE_PC_LO); // Code Sequence: // pcalau12i $rd, %ie_pc_hi20(sym) // ld.w/d $rd, $rd, %ie_pc_lo12(sym) MachineFunction *MF = MBB.getParent(); const auto &STI = MF->getSubtarget(); unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_IE_PC_HI, SecondOpcode, LoongArchII::MO_IE_PC_LO); } bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLD( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool Large) { if (Large) // Emit the 5-insn large address load sequence with the `%got_pc` family // of relocs, with the `pcalau12i` insn relocated with `%ld_pc_hi20`. return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D, LoongArchII::MO_LD_PC_HI); // Code Sequence: // pcalau12i $rd, %ld_pc_hi20(sym) // addi.w/d $rd, $rd, %got_pc_lo12(sym) MachineFunction *MF = MBB.getParent(); const auto &STI = MF->getSubtarget(); unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_LD_PC_HI, SecondOpcode, LoongArchII::MO_GOT_PC_LO); } bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSGD( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool Large) { if (Large) // Emit the 5-insn large address load sequence with the `%got_pc` family // of relocs, with the `pcalau12i` insn relocated with `%gd_pc_hi20`. return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D, LoongArchII::MO_GD_PC_HI); // Code Sequence: // pcalau12i $rd, %gd_pc_hi20(sym) // addi.w/d $rd, $rd, %got_pc_lo12(sym) MachineFunction *MF = MBB.getParent(); const auto &STI = MF->getSubtarget(); unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GD_PC_HI, SecondOpcode, LoongArchII::MO_GOT_PC_LO); } bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool Large) { MachineFunction *MF = MBB.getParent(); MachineInstr &MI = *MBBI; DebugLoc DL = MI.getDebugLoc(); const auto &STI = MF->getSubtarget(); unsigned ADD = STI.is64Bit() ? LoongArch::ADD_D : LoongArch::ADD_W; unsigned ADDI = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; unsigned LD = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax); Register DestReg = MI.getOperand(0).getReg(); Register Tmp1Reg = MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); MachineOperand &Symbol = MI.getOperand(Large ? 2 : 1); BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), Tmp1Reg) .addDisp(Symbol, 0, LoongArchII::encodeFlags(LoongArchII::MO_DESC_PC_HI, EnableRelax && !Large)); if (Large) { // Code Sequence: // // pcalau12i $a0, %desc_pc_hi20(sym) // addi.d $a1, $zero, %desc_pc_lo12(sym) // lu32i.d $a1, %desc64_pc_lo20(sym) // lu52i.d $a1, $a1, %desc64_pc_hi12(sym) // add.d $a0, $a0, $a1 // ld.d $ra, $a0, %desc_ld(sym) // jirl $ra, $ra, %desc_call(sym) // add.d $dst, $a0, $tp assert(MBB.getParent()->getSubtarget().is64Bit() && "Large code model requires LA64"); Register Tmp2Reg = MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); Register Tmp3Reg = MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); Register Tmp4Reg = MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADDI_D), Tmp2Reg) .addReg(LoongArch::R0) .addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_LO); BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), Tmp3Reg) .addReg(Tmp2Reg, RegState::Kill) .addDisp(Symbol, 0, LoongArchII::MO_DESC64_PC_LO); BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), Tmp4Reg) .addReg(Tmp3Reg) .addDisp(Symbol, 0, LoongArchII::MO_DESC64_PC_HI); BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADD_D), LoongArch::R4) .addReg(Tmp1Reg) .addReg(Tmp4Reg); } else { // Code Sequence: // pcalau12i $a0, %desc_pc_hi20(sym) // addi.w/d $a0, $a0, %desc_pc_lo12(sym) // ld.w/d $ra, $a0, %desc_ld(sym) // jirl $ra, $ra, %desc_call(sym) // add.w/d $dst, $a0, $tp BuildMI(MBB, MBBI, DL, TII->get(ADDI), LoongArch::R4) .addReg(Tmp1Reg) .addDisp( Symbol, 0, LoongArchII::encodeFlags(LoongArchII::MO_DESC_PC_LO, EnableRelax)); } BuildMI(MBB, MBBI, DL, TII->get(LD), LoongArch::R1) .addReg(LoongArch::R4) .addDisp(Symbol, 0, LoongArchII::encodeFlags(LoongArchII::MO_DESC_LD, EnableRelax && !Large)); BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PseudoDESC_CALL), LoongArch::R1) .addReg(LoongArch::R1) .addDisp(Symbol, 0, LoongArchII::encodeFlags(LoongArchII::MO_DESC_CALL, EnableRelax && !Large)); BuildMI(MBB, MBBI, DL, TII->get(ADD), DestReg) .addReg(LoongArch::R4) .addReg(LoongArch::R2); MI.eraseFromParent(); return true; } bool LoongArchPreRAExpandPseudo::expandFunctionCALL( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) { MachineFunction *MF = MBB.getParent(); MachineInstr &MI = *MBBI; DebugLoc DL = MI.getDebugLoc(); const MachineOperand &Func = MI.getOperand(0); MachineInstrBuilder CALL; unsigned Opcode; switch (MF->getTarget().getCodeModel()) { default: report_fatal_error("Unexpected code model"); break; case CodeModel::Small: { // CALL: // bl func // TAIL: // b func Opcode = IsTailCall ? LoongArch::PseudoB_TAIL : LoongArch::BL; CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).add(Func); break; } case CodeModel::Large: { // Emit the 5-insn large address load sequence, either directly or // indirectly in case of going through the GOT, then JIRL_TAIL or // JIRL_CALL to $addr. Opcode = IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL; Register AddrReg = IsTailCall ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass) : LoongArch::R1; bool UseGOT = Func.getTargetFlags() == LoongArchII::MO_CALL_PLT; unsigned MO = UseGOT ? LoongArchII::MO_GOT_PC_HI : LoongArchII::MO_PCREL_LO; unsigned LAOpcode = UseGOT ? LoongArch::LDX_D : LoongArch::ADD_D; expandLargeAddressLoad(MBB, MBBI, NextMBBI, LAOpcode, MO, Func, AddrReg, false); CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(AddrReg).addImm(0); break; } } // Transfer implicit operands. CALL.copyImplicitOps(MI); // Transfer MI flags. CALL.setMIFlags(MI.getFlags()); MI.eraseFromParent(); return true; } void LoongArchPreRAExpandPseudo::annotateTableJump( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) { MachineFunction *MF = MBB.getParent(); MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); bool IsFound = false; std::function FindJTIMI = [&](MachineInstr *MInst, int FindDepth) { if (FindDepth < 0) return; for (auto &MO : MInst->all_uses()) { if (IsFound) return; Register Reg = MO.getReg(); if (!Reg.isVirtual()) continue; MachineInstr *DefMI = MRI.getVRegDef(Reg); if (!DefMI) continue; for (unsigned Idx = 0; Idx < DefMI->getNumOperands(); ++Idx) { MachineOperand &MO = DefMI->getOperand(Idx); if (MO.isJTI()) { MBBI->setPreInstrSymbol( *MF, MF->getContext().createNamedTempSymbol("jrtb_")); MF->getInfo()->setJumpInfo(&*MBBI, &MO); IsFound = true; return; } } FindJTIMI(DefMI, --FindDepth); } }; // FindDepth = 3, probably sufficient. FindJTIMI(&*MBBI, /*FindDepth=*/3); } class LoongArchExpandPseudo : public MachineFunctionPass { public: const LoongArchInstrInfo *TII; static char ID; LoongArchExpandPseudo() : MachineFunctionPass(ID) { initializeLoongArchExpandPseudoPass(*PassRegistry::getPassRegistry()); } bool runOnMachineFunction(MachineFunction &MF) override; StringRef getPassName() const override { return LOONGARCH_EXPAND_PSEUDO_NAME; } private: bool expandMBB(MachineBasicBlock &MBB); bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI); bool expandCopyCFR(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI); bool expandFunctionCALL(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool IsTailCall); }; char LoongArchExpandPseudo::ID = 0; bool LoongArchExpandPseudo::runOnMachineFunction(MachineFunction &MF) { TII = static_cast(MF.getSubtarget().getInstrInfo()); bool Modified = false; for (auto &MBB : MF) Modified |= expandMBB(MBB); return Modified; } bool LoongArchExpandPseudo::expandMBB(MachineBasicBlock &MBB) { bool Modified = false; MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); while (MBBI != E) { MachineBasicBlock::iterator NMBBI = std::next(MBBI); Modified |= expandMI(MBB, MBBI, NMBBI); MBBI = NMBBI; } return Modified; } bool LoongArchExpandPseudo::expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI) { switch (MBBI->getOpcode()) { case LoongArch::PseudoCopyCFR: return expandCopyCFR(MBB, MBBI, NextMBBI); case LoongArch::PseudoCALL_MEDIUM: return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false); case LoongArch::PseudoTAIL_MEDIUM: return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true); } return false; } bool LoongArchExpandPseudo::expandCopyCFR( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI) { MachineFunction *MF = MBB.getParent(); MachineInstr &MI = *MBBI; DebugLoc DL = MI.getDebugLoc(); // Expand: // MBB: // fcmp.caf.s $dst, $fa0, $fa0 # set $dst 0(false) // bceqz $src, SinkBB // FalseBB: // fcmp.cueq.s $dst, $fa0, $fa0 # set $dst 1(true) // SinkBB: // fallthrough const BasicBlock *LLVM_BB = MBB.getBasicBlock(); auto *FalseBB = MF->CreateMachineBasicBlock(LLVM_BB); auto *SinkBB = MF->CreateMachineBasicBlock(LLVM_BB); MF->insert(++MBB.getIterator(), FalseBB); MF->insert(++FalseBB->getIterator(), SinkBB); Register DestReg = MI.getOperand(0).getReg(); Register SrcReg = MI.getOperand(1).getReg(); // DestReg = 0 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::SET_CFR_FALSE), DestReg); // Insert branch instruction. BuildMI(MBB, MBBI, DL, TII->get(LoongArch::BCEQZ)) .addReg(SrcReg) .addMBB(SinkBB); // DestReg = 1 BuildMI(FalseBB, DL, TII->get(LoongArch::SET_CFR_TRUE), DestReg); FalseBB->addSuccessor(SinkBB); SinkBB->splice(SinkBB->end(), &MBB, MI, MBB.end()); SinkBB->transferSuccessors(&MBB); MBB.addSuccessor(FalseBB); MBB.addSuccessor(SinkBB); NextMBBI = MBB.end(); MI.eraseFromParent(); // Make sure live-ins are correctly attached to this new basic block. LivePhysRegs LiveRegs; computeAndAddLiveIns(LiveRegs, *FalseBB); computeAndAddLiveIns(LiveRegs, *SinkBB); return true; } bool LoongArchExpandPseudo::expandFunctionCALL( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) { MachineFunction *MF = MBB.getParent(); MachineInstr &MI = *MBBI; DebugLoc DL = MI.getDebugLoc(); const MachineOperand &Func = MI.getOperand(0); MachineInstrBuilder CALL; unsigned Opcode; switch (MF->getTarget().getCodeModel()) { default: report_fatal_error("Unexpected code model"); break; case CodeModel::Medium: { // CALL: // pcaddu18i $ra, %call36(func) // jirl $ra, $ra, 0 // TAIL: // pcaddu18i $t8, %call36(func) // jirl $r0, $t8, 0 Opcode = IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL; Register ScratchReg = IsTailCall ? LoongArch::R20 : LoongArch::R1; MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCADDU18I), ScratchReg); CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(ScratchReg).addImm(0); if (Func.isSymbol()) MIB.addExternalSymbol(Func.getSymbolName(), LoongArchII::MO_CALL36); else MIB.addDisp(Func, 0, LoongArchII::MO_CALL36); break; } } // Transfer implicit operands. CALL.copyImplicitOps(MI); // Transfer MI flags. CALL.setMIFlags(MI.getFlags()); MI.eraseFromParent(); return true; } } // end namespace INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "loongarch-prera-expand-pseudo", LOONGARCH_PRERA_EXPAND_PSEUDO_NAME, false, false) INITIALIZE_PASS(LoongArchExpandPseudo, "loongarch-expand-pseudo", LOONGARCH_EXPAND_PSEUDO_NAME, false, false) namespace llvm { FunctionPass *createLoongArchPreRAExpandPseudoPass() { return new LoongArchPreRAExpandPseudo(); } FunctionPass *createLoongArchExpandPseudoPass() { return new LoongArchExpandPseudo(); } } // end namespace llvm