838 lines · cpp
1//===-- LoongArchExpandPseudoInsts.cpp - Expand pseudo instructions -------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains a pass that expands pseudo instructions into target10// instructions.11//12//===----------------------------------------------------------------------===//13 14#include "LoongArch.h"15#include "LoongArchInstrInfo.h"16#include "LoongArchMachineFunctionInfo.h"17#include "MCTargetDesc/LoongArchBaseInfo.h"18#include "MCTargetDesc/LoongArchMCTargetDesc.h"19#include "llvm/CodeGen/LivePhysRegs.h"20#include "llvm/CodeGen/MachineFunctionPass.h"21#include "llvm/CodeGen/MachineInstrBuilder.h"22#include "llvm/CodeGen/MachineOperand.h"23#include "llvm/CodeGen/Register.h"24#include "llvm/MC/MCContext.h"25#include "llvm/Support/CodeGen.h"26#include "llvm/Support/ErrorHandling.h"27 28using namespace llvm;29 30extern cl::opt<bool> LArchAnnotateTableJump;31 32#define LOONGARCH_PRERA_EXPAND_PSEUDO_NAME \33 "LoongArch Pre-RA pseudo instruction expansion pass"34#define LOONGARCH_EXPAND_PSEUDO_NAME \35 "LoongArch pseudo instruction expansion pass"36 37namespace {38 39class LoongArchPreRAExpandPseudo : public MachineFunctionPass {40public:41 const LoongArchInstrInfo *TII;42 static char ID;43 44 LoongArchPreRAExpandPseudo() : MachineFunctionPass(ID) {}45 46 bool runOnMachineFunction(MachineFunction &MF) override;47 48 void getAnalysisUsage(AnalysisUsage &AU) const override {49 AU.setPreservesCFG();50 MachineFunctionPass::getAnalysisUsage(AU);51 }52 StringRef getPassName() const override {53 return LOONGARCH_PRERA_EXPAND_PSEUDO_NAME;54 }55 56private:57 bool expandMBB(MachineBasicBlock &MBB);58 bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,59 MachineBasicBlock::iterator &NextMBBI);60 bool expandPcalau12iInstPair(MachineBasicBlock &MBB,61 MachineBasicBlock::iterator MBBI,62 MachineBasicBlock::iterator &NextMBBI,63 unsigned FlagsHi, unsigned SecondOpcode,64 unsigned FlagsLo);65 bool expandLargeAddressLoad(MachineBasicBlock &MBB,66 MachineBasicBlock::iterator MBBI,67 MachineBasicBlock::iterator &NextMBBI,68 unsigned LastOpcode, unsigned IdentifyingMO);69 bool expandLargeAddressLoad(MachineBasicBlock &MBB,70 MachineBasicBlock::iterator MBBI,71 MachineBasicBlock::iterator &NextMBBI,72 unsigned LastOpcode, unsigned IdentifyingMO,73 const MachineOperand &Symbol, Register DestReg,74 bool EraseFromParent);75 bool expandLoadAddressPcrel(MachineBasicBlock &MBB,76 MachineBasicBlock::iterator MBBI,77 MachineBasicBlock::iterator &NextMBBI,78 bool Large = false);79 bool expandLoadAddressGot(MachineBasicBlock &MBB,80 MachineBasicBlock::iterator MBBI,81 MachineBasicBlock::iterator &NextMBBI,82 bool Large = false);83 bool expandLoadAddressTLSLE(MachineBasicBlock &MBB,84 MachineBasicBlock::iterator MBBI,85 MachineBasicBlock::iterator &NextMBBI);86 bool expandLoadAddressTLSIE(MachineBasicBlock &MBB,87 MachineBasicBlock::iterator MBBI,88 MachineBasicBlock::iterator &NextMBBI,89 bool Large = false);90 bool expandLoadAddressTLSLD(MachineBasicBlock &MBB,91 MachineBasicBlock::iterator MBBI,92 MachineBasicBlock::iterator &NextMBBI,93 bool Large = false);94 bool expandLoadAddressTLSGD(MachineBasicBlock &MBB,95 MachineBasicBlock::iterator MBBI,96 MachineBasicBlock::iterator &NextMBBI,97 bool Large = false);98 bool expandLoadAddressTLSDesc(MachineBasicBlock &MBB,99 MachineBasicBlock::iterator MBBI,100 MachineBasicBlock::iterator &NextMBBI,101 bool Large = false);102 bool expandFunctionCALL(MachineBasicBlock &MBB,103 MachineBasicBlock::iterator MBBI,104 MachineBasicBlock::iterator &NextMBBI,105 bool IsTailCall);106 void annotateTableJump(MachineBasicBlock &MBB,107 MachineBasicBlock::iterator MBBI);108};109 110char LoongArchPreRAExpandPseudo::ID = 0;111 112bool LoongArchPreRAExpandPseudo::runOnMachineFunction(MachineFunction &MF) {113 TII =114 static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo());115 bool Modified = false;116 for (auto &MBB : MF)117 Modified |= expandMBB(MBB);118 return Modified;119}120 121bool LoongArchPreRAExpandPseudo::expandMBB(MachineBasicBlock &MBB) {122 bool Modified = false;123 124 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();125 while (MBBI != E) {126 MachineBasicBlock::iterator NMBBI = std::next(MBBI);127 Modified |= expandMI(MBB, MBBI, NMBBI);128 MBBI = NMBBI;129 }130 131 return Modified;132}133 134bool LoongArchPreRAExpandPseudo::expandMI(135 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,136 MachineBasicBlock::iterator &NextMBBI) {137 switch (MBBI->getOpcode()) {138 case LoongArch::PseudoLA_PCREL:139 return expandLoadAddressPcrel(MBB, MBBI, NextMBBI);140 case LoongArch::PseudoLA_PCREL_LARGE:141 return expandLoadAddressPcrel(MBB, MBBI, NextMBBI, /*Large=*/true);142 case LoongArch::PseudoLA_GOT:143 return expandLoadAddressGot(MBB, MBBI, NextMBBI);144 case LoongArch::PseudoLA_GOT_LARGE:145 return expandLoadAddressGot(MBB, MBBI, NextMBBI, /*Large=*/true);146 case LoongArch::PseudoLA_TLS_LE:147 return expandLoadAddressTLSLE(MBB, MBBI, NextMBBI);148 case LoongArch::PseudoLA_TLS_IE:149 return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI);150 case LoongArch::PseudoLA_TLS_IE_LARGE:151 return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI, /*Large=*/true);152 case LoongArch::PseudoLA_TLS_LD:153 return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI);154 case LoongArch::PseudoLA_TLS_LD_LARGE:155 return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI, /*Large=*/true);156 case LoongArch::PseudoLA_TLS_GD:157 return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI);158 case LoongArch::PseudoLA_TLS_GD_LARGE:159 return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI, /*Large=*/true);160 case LoongArch::PseudoLA_TLS_DESC:161 return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI);162 case LoongArch::PseudoLA_TLS_DESC_LARGE:163 return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI, /*Large=*/true);164 case LoongArch::PseudoCALL:165 case LoongArch::PseudoCALL_LARGE:166 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);167 case LoongArch::PseudoTAIL:168 case LoongArch::PseudoTAIL_LARGE:169 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);170 case LoongArch::PseudoBRIND:171 // If the PseudoBRIND is used to table jump, then emit a label to annotate172 // the `jr` instruction, and save the instructions.173 if (LArchAnnotateTableJump)174 annotateTableJump(MBB, MBBI);175 break;176 }177 return false;178}179 180bool LoongArchPreRAExpandPseudo::expandPcalau12iInstPair(181 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,182 MachineBasicBlock::iterator &NextMBBI, unsigned FlagsHi,183 unsigned SecondOpcode, unsigned FlagsLo) {184 MachineFunction *MF = MBB.getParent();185 MachineInstr &MI = *MBBI;186 DebugLoc DL = MI.getDebugLoc();187 188 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();189 bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax);190 191 Register DestReg = MI.getOperand(0).getReg();192 Register ScratchReg =193 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);194 MachineOperand &Symbol = MI.getOperand(1);195 196 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg)197 .addDisp(Symbol, 0, LoongArchII::encodeFlags(FlagsHi, EnableRelax));198 199 MachineInstr *SecondMI =200 BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg)201 .addReg(ScratchReg)202 .addDisp(Symbol, 0, LoongArchII::encodeFlags(FlagsLo, EnableRelax));203 204 if (MI.hasOneMemOperand())205 SecondMI->addMemOperand(*MF, *MI.memoperands_begin());206 207 MI.eraseFromParent();208 return true;209}210 211bool LoongArchPreRAExpandPseudo::expandLargeAddressLoad(212 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,213 MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode,214 unsigned IdentifyingMO) {215 MachineInstr &MI = *MBBI;216 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode, IdentifyingMO,217 MI.getOperand(2), MI.getOperand(0).getReg(),218 true);219}220 221bool LoongArchPreRAExpandPseudo::expandLargeAddressLoad(222 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,223 MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode,224 unsigned IdentifyingMO, const MachineOperand &Symbol, Register DestReg,225 bool EraseFromParent) {226 // Code Sequence:227 //228 // Part1: pcalau12i $scratch, %MO1(sym)229 // Part0: addi.d $dest, $zero, %MO0(sym)230 // Part2: lu32i.d $dest, %MO2(sym)231 // Part3: lu52i.d $dest, $dest, %MO3(sym)232 // Fin: LastOpcode $dest, $dest, $scratch233 234 unsigned MO0, MO1, MO2, MO3;235 switch (IdentifyingMO) {236 default:237 llvm_unreachable("unsupported identifying MO");238 case LoongArchII::MO_PCREL_LO:239 MO0 = IdentifyingMO;240 MO1 = LoongArchII::MO_PCREL_HI;241 MO2 = LoongArchII::MO_PCREL64_LO;242 MO3 = LoongArchII::MO_PCREL64_HI;243 break;244 case LoongArchII::MO_GOT_PC_HI:245 case LoongArchII::MO_LD_PC_HI:246 case LoongArchII::MO_GD_PC_HI:247 // These cases relocate just like the GOT case, except for Part1.248 MO0 = LoongArchII::MO_GOT_PC_LO;249 MO1 = IdentifyingMO;250 MO2 = LoongArchII::MO_GOT_PC64_LO;251 MO3 = LoongArchII::MO_GOT_PC64_HI;252 break;253 case LoongArchII::MO_IE_PC_LO:254 MO0 = IdentifyingMO;255 MO1 = LoongArchII::MO_IE_PC_HI;256 MO2 = LoongArchII::MO_IE_PC64_LO;257 MO3 = LoongArchII::MO_IE_PC64_HI;258 break;259 }260 261 MachineFunction *MF = MBB.getParent();262 MachineInstr &MI = *MBBI;263 DebugLoc DL = MI.getDebugLoc();264 265 assert(MF->getSubtarget<LoongArchSubtarget>().is64Bit() &&266 "Large code model requires LA64");267 268 Register TmpPart1 =269 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);270 Register TmpPart0 =271 DestReg.isVirtual()272 ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)273 : DestReg;274 Register TmpParts02 =275 DestReg.isVirtual()276 ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)277 : DestReg;278 Register TmpParts023 =279 DestReg.isVirtual()280 ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)281 : DestReg;282 283 auto Part1 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), TmpPart1);284 auto Part0 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADDI_D), TmpPart0)285 .addReg(LoongArch::R0);286 auto Part2 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), TmpParts02)287 // "rj" is needed due to InstrInfo pattern requirement.288 .addReg(TmpPart0, RegState::Kill);289 auto Part3 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), TmpParts023)290 .addReg(TmpParts02, RegState::Kill);291 BuildMI(MBB, MBBI, DL, TII->get(LastOpcode), DestReg)292 .addReg(TmpParts023)293 .addReg(TmpPart1, RegState::Kill);294 295 if (Symbol.getType() == MachineOperand::MO_ExternalSymbol) {296 const char *SymName = Symbol.getSymbolName();297 Part0.addExternalSymbol(SymName, MO0);298 Part1.addExternalSymbol(SymName, MO1);299 Part2.addExternalSymbol(SymName, MO2);300 Part3.addExternalSymbol(SymName, MO3);301 } else {302 Part0.addDisp(Symbol, 0, MO0);303 Part1.addDisp(Symbol, 0, MO1);304 Part2.addDisp(Symbol, 0, MO2);305 Part3.addDisp(Symbol, 0, MO3);306 }307 308 if (EraseFromParent)309 MI.eraseFromParent();310 311 return true;312}313 314bool LoongArchPreRAExpandPseudo::expandLoadAddressPcrel(315 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,316 MachineBasicBlock::iterator &NextMBBI, bool Large) {317 if (Large)318 // Emit the 5-insn large address load sequence with the `%pc` family of319 // relocs.320 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,321 LoongArchII::MO_PCREL_LO);322 323 // Code Sequence:324 // pcalau12i $rd, %pc_hi20(sym)325 // addi.w/d $rd, $rd, %pc_lo12(sym)326 MachineFunction *MF = MBB.getParent();327 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();328 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;329 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_PCREL_HI,330 SecondOpcode, LoongArchII::MO_PCREL_LO);331}332 333bool LoongArchPreRAExpandPseudo::expandLoadAddressGot(334 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,335 MachineBasicBlock::iterator &NextMBBI, bool Large) {336 if (Large)337 // Emit the 5-insn large address load sequence with the `%got_pc` family338 // of relocs, loading the result from GOT with `ldx.d` in the end.339 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::LDX_D,340 LoongArchII::MO_GOT_PC_HI);341 342 // Code Sequence:343 // pcalau12i $rd, %got_pc_hi20(sym)344 // ld.w/d $rd, $rd, %got_pc_lo12(sym)345 MachineFunction *MF = MBB.getParent();346 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();347 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;348 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GOT_PC_HI,349 SecondOpcode, LoongArchII::MO_GOT_PC_LO);350}351 352bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLE(353 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,354 MachineBasicBlock::iterator &NextMBBI) {355 // Code Sequence:356 // lu12i.w $rd, %le_hi20_r(sym)357 // add.w/d $rd, $rd, $tp, %le_add_r(sym)358 // addi.w/d $rd, $rd, %le_lo12_r(sym)359 //360 // Code Sequence while using the large code model:361 // lu12i.w $rd, %le_hi20(sym)362 // ori $rd, $rd, %le_lo12(sym)363 // lu32i.d $rd, %le64_lo20(sym)364 // lu52i.d $rd, $rd, %le64_hi12(sym)365 MachineFunction *MF = MBB.getParent();366 MachineInstr &MI = *MBBI;367 DebugLoc DL = MI.getDebugLoc();368 369 bool Large = MF->getTarget().getCodeModel() == CodeModel::Large;370 Register DestReg = MI.getOperand(0).getReg();371 Register Parts01 =372 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);373 Register Part1 =374 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);375 MachineOperand &Symbol = MI.getOperand(1);376 377 if (!Large) {378 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W), Part1)379 .addDisp(Symbol, 0, LoongArchII::MO_LE_HI_R);380 381 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();382 unsigned AddOp = STI.is64Bit() ? LoongArch::PseudoAddTPRel_D383 : LoongArch::PseudoAddTPRel_W;384 BuildMI(MBB, MBBI, DL, TII->get(AddOp), Parts01)385 .addReg(Part1, RegState::Kill)386 .addReg(LoongArch::R2)387 .addDisp(Symbol, 0, LoongArchII::MO_LE_ADD_R);388 389 unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;390 BuildMI(MBB, MBBI, DL, TII->get(AddiOp), DestReg)391 .addReg(Parts01, RegState::Kill)392 .addDisp(Symbol, 0, LoongArchII::MO_LE_LO_R);393 } else {394 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W), Part1)395 .addDisp(Symbol, 0, LoongArchII::MO_LE_HI);396 397 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ORI), Parts01)398 .addReg(Part1, RegState::Kill)399 .addDisp(Symbol, 0, LoongArchII::MO_LE_LO);400 401 Register Parts012 =402 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);403 404 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), Parts012)405 // "rj" is needed due to InstrInfo pattern requirement.406 .addReg(Parts01, RegState::Kill)407 .addDisp(Symbol, 0, LoongArchII::MO_LE64_LO);408 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), DestReg)409 .addReg(Parts012, RegState::Kill)410 .addDisp(Symbol, 0, LoongArchII::MO_LE64_HI);411 }412 413 MI.eraseFromParent();414 return true;415}416 417bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSIE(418 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,419 MachineBasicBlock::iterator &NextMBBI, bool Large) {420 if (Large)421 // Emit the 5-insn large address load sequence with the `%ie_pc` family422 // of relocs, loading the result with `ldx.d` in the end.423 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::LDX_D,424 LoongArchII::MO_IE_PC_LO);425 426 // Code Sequence:427 // pcalau12i $rd, %ie_pc_hi20(sym)428 // ld.w/d $rd, $rd, %ie_pc_lo12(sym)429 MachineFunction *MF = MBB.getParent();430 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();431 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;432 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_IE_PC_HI,433 SecondOpcode, LoongArchII::MO_IE_PC_LO);434}435 436bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLD(437 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,438 MachineBasicBlock::iterator &NextMBBI, bool Large) {439 if (Large)440 // Emit the 5-insn large address load sequence with the `%got_pc` family441 // of relocs, with the `pcalau12i` insn relocated with `%ld_pc_hi20`.442 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,443 LoongArchII::MO_LD_PC_HI);444 445 // Code Sequence:446 // pcalau12i $rd, %ld_pc_hi20(sym)447 // addi.w/d $rd, $rd, %got_pc_lo12(sym)448 MachineFunction *MF = MBB.getParent();449 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();450 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;451 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_LD_PC_HI,452 SecondOpcode, LoongArchII::MO_GOT_PC_LO);453}454 455bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSGD(456 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,457 MachineBasicBlock::iterator &NextMBBI, bool Large) {458 if (Large)459 // Emit the 5-insn large address load sequence with the `%got_pc` family460 // of relocs, with the `pcalau12i` insn relocated with `%gd_pc_hi20`.461 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,462 LoongArchII::MO_GD_PC_HI);463 464 // Code Sequence:465 // pcalau12i $rd, %gd_pc_hi20(sym)466 // addi.w/d $rd, $rd, %got_pc_lo12(sym)467 MachineFunction *MF = MBB.getParent();468 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();469 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;470 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GD_PC_HI,471 SecondOpcode, LoongArchII::MO_GOT_PC_LO);472}473 474bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc(475 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,476 MachineBasicBlock::iterator &NextMBBI, bool Large) {477 MachineFunction *MF = MBB.getParent();478 MachineInstr &MI = *MBBI;479 DebugLoc DL = MI.getDebugLoc();480 481 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();482 unsigned ADD = STI.is64Bit() ? LoongArch::ADD_D : LoongArch::ADD_W;483 unsigned ADDI = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;484 unsigned LD = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;485 bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax);486 487 Register DestReg = MI.getOperand(0).getReg();488 Register Tmp1Reg =489 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);490 MachineOperand &Symbol = MI.getOperand(Large ? 2 : 1);491 492 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), Tmp1Reg)493 .addDisp(Symbol, 0,494 LoongArchII::encodeFlags(LoongArchII::MO_DESC_PC_HI,495 EnableRelax && !Large));496 497 if (Large) {498 // Code Sequence:499 //500 // pcalau12i $a0, %desc_pc_hi20(sym)501 // addi.d $a1, $zero, %desc_pc_lo12(sym)502 // lu32i.d $a1, %desc64_pc_lo20(sym)503 // lu52i.d $a1, $a1, %desc64_pc_hi12(sym)504 // add.d $a0, $a0, $a1505 // ld.d $ra, $a0, %desc_ld(sym)506 // jirl $ra, $ra, %desc_call(sym)507 // add.d $dst, $a0, $tp508 assert(MBB.getParent()->getSubtarget<LoongArchSubtarget>().is64Bit() &&509 "Large code model requires LA64");510 Register Tmp2Reg =511 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);512 Register Tmp3Reg =513 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);514 Register Tmp4Reg =515 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);516 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADDI_D), Tmp2Reg)517 .addReg(LoongArch::R0)518 .addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_LO);519 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), Tmp3Reg)520 .addReg(Tmp2Reg, RegState::Kill)521 .addDisp(Symbol, 0, LoongArchII::MO_DESC64_PC_LO);522 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), Tmp4Reg)523 .addReg(Tmp3Reg)524 .addDisp(Symbol, 0, LoongArchII::MO_DESC64_PC_HI);525 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADD_D), LoongArch::R4)526 .addReg(Tmp1Reg)527 .addReg(Tmp4Reg);528 } else {529 // Code Sequence:530 // pcalau12i $a0, %desc_pc_hi20(sym)531 // addi.w/d $a0, $a0, %desc_pc_lo12(sym)532 // ld.w/d $ra, $a0, %desc_ld(sym)533 // jirl $ra, $ra, %desc_call(sym)534 // add.w/d $dst, $a0, $tp535 BuildMI(MBB, MBBI, DL, TII->get(ADDI), LoongArch::R4)536 .addReg(Tmp1Reg)537 .addDisp(538 Symbol, 0,539 LoongArchII::encodeFlags(LoongArchII::MO_DESC_PC_LO, EnableRelax));540 }541 542 BuildMI(MBB, MBBI, DL, TII->get(LD), LoongArch::R1)543 .addReg(LoongArch::R4)544 .addDisp(Symbol, 0,545 LoongArchII::encodeFlags(LoongArchII::MO_DESC_LD,546 EnableRelax && !Large));547 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PseudoDESC_CALL), LoongArch::R1)548 .addReg(LoongArch::R1)549 .addDisp(Symbol, 0,550 LoongArchII::encodeFlags(LoongArchII::MO_DESC_CALL,551 EnableRelax && !Large));552 BuildMI(MBB, MBBI, DL, TII->get(ADD), DestReg)553 .addReg(LoongArch::R4)554 .addReg(LoongArch::R2);555 556 MI.eraseFromParent();557 return true;558}559 560bool LoongArchPreRAExpandPseudo::expandFunctionCALL(561 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,562 MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {563 MachineFunction *MF = MBB.getParent();564 MachineInstr &MI = *MBBI;565 DebugLoc DL = MI.getDebugLoc();566 const MachineOperand &Func = MI.getOperand(0);567 MachineInstrBuilder CALL;568 unsigned Opcode;569 570 switch (MF->getTarget().getCodeModel()) {571 default:572 report_fatal_error("Unexpected code model");573 break;574 case CodeModel::Small: {575 // CALL:576 // bl func577 // TAIL:578 // b func579 Opcode = IsTailCall ? LoongArch::PseudoB_TAIL : LoongArch::BL;580 CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).add(Func);581 break;582 }583 case CodeModel::Large: {584 // Emit the 5-insn large address load sequence, either directly or585 // indirectly in case of going through the GOT, then JIRL_TAIL or586 // JIRL_CALL to $addr.587 Opcode =588 IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;589 Register AddrReg =590 IsTailCall591 ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)592 : LoongArch::R1;593 594 bool UseGOT = Func.getTargetFlags() == LoongArchII::MO_CALL_PLT;595 unsigned MO = UseGOT ? LoongArchII::MO_GOT_PC_HI : LoongArchII::MO_PCREL_LO;596 unsigned LAOpcode = UseGOT ? LoongArch::LDX_D : LoongArch::ADD_D;597 expandLargeAddressLoad(MBB, MBBI, NextMBBI, LAOpcode, MO, Func, AddrReg,598 false);599 CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(AddrReg).addImm(0);600 break;601 }602 }603 604 // Transfer implicit operands.605 CALL.copyImplicitOps(MI);606 607 // Transfer MI flags.608 CALL.setMIFlags(MI.getFlags());609 610 MI.eraseFromParent();611 return true;612}613 614void LoongArchPreRAExpandPseudo::annotateTableJump(615 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) {616 MachineFunction *MF = MBB.getParent();617 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();618 619 bool IsFound = false;620 621 std::function<void(MachineInstr *, int)> FindJTIMI = [&](MachineInstr *MInst,622 int FindDepth) {623 if (FindDepth < 0)624 return;625 for (auto &MO : MInst->all_uses()) {626 if (IsFound)627 return;628 Register Reg = MO.getReg();629 if (!Reg.isVirtual())630 continue;631 MachineInstr *DefMI = MRI.getVRegDef(Reg);632 if (!DefMI)633 continue;634 for (unsigned Idx = 0; Idx < DefMI->getNumOperands(); ++Idx) {635 MachineOperand &MO = DefMI->getOperand(Idx);636 if (MO.isJTI()) {637 MBBI->setPreInstrSymbol(638 *MF, MF->getContext().createNamedTempSymbol("jrtb_"));639 MF->getInfo<LoongArchMachineFunctionInfo>()->setJumpInfo(640 &*MBBI, MO.getIndex());641 IsFound = true;642 return;643 }644 }645 FindJTIMI(DefMI, --FindDepth);646 }647 };648 649 // FindDepth = 3, probably sufficient.650 FindJTIMI(&*MBBI, /*FindDepth=*/3);651}652 653class LoongArchExpandPseudo : public MachineFunctionPass {654public:655 const LoongArchInstrInfo *TII;656 static char ID;657 658 LoongArchExpandPseudo() : MachineFunctionPass(ID) {}659 660 bool runOnMachineFunction(MachineFunction &MF) override;661 662 StringRef getPassName() const override {663 return LOONGARCH_EXPAND_PSEUDO_NAME;664 }665 666private:667 bool expandMBB(MachineBasicBlock &MBB);668 bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,669 MachineBasicBlock::iterator &NextMBBI);670 bool expandCopyCFR(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,671 MachineBasicBlock::iterator &NextMBBI);672 bool expandFunctionCALL(MachineBasicBlock &MBB,673 MachineBasicBlock::iterator MBBI,674 MachineBasicBlock::iterator &NextMBBI,675 bool IsTailCall);676};677 678char LoongArchExpandPseudo::ID = 0;679 680bool LoongArchExpandPseudo::runOnMachineFunction(MachineFunction &MF) {681 TII =682 static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo());683 684 bool Modified = false;685 for (auto &MBB : MF)686 Modified |= expandMBB(MBB);687 688 return Modified;689}690 691bool LoongArchExpandPseudo::expandMBB(MachineBasicBlock &MBB) {692 bool Modified = false;693 694 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();695 while (MBBI != E) {696 MachineBasicBlock::iterator NMBBI = std::next(MBBI);697 Modified |= expandMI(MBB, MBBI, NMBBI);698 MBBI = NMBBI;699 }700 701 return Modified;702}703 704bool LoongArchExpandPseudo::expandMI(MachineBasicBlock &MBB,705 MachineBasicBlock::iterator MBBI,706 MachineBasicBlock::iterator &NextMBBI) {707 switch (MBBI->getOpcode()) {708 case LoongArch::PseudoCopyCFR:709 return expandCopyCFR(MBB, MBBI, NextMBBI);710 case LoongArch::PseudoCALL_MEDIUM:711 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);712 case LoongArch::PseudoTAIL_MEDIUM:713 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);714 }715 716 return false;717}718 719bool LoongArchExpandPseudo::expandCopyCFR(720 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,721 MachineBasicBlock::iterator &NextMBBI) {722 MachineFunction *MF = MBB.getParent();723 MachineInstr &MI = *MBBI;724 DebugLoc DL = MI.getDebugLoc();725 726 // Expand:727 // MBB:728 // fcmp.caf.s $dst, $fa0, $fa0 # set $dst 0(false)729 // bceqz $src, SinkBB730 // FalseBB:731 // fcmp.cueq.s $dst, $fa0, $fa0 # set $dst 1(true)732 // SinkBB:733 // fallthrough734 735 const BasicBlock *LLVM_BB = MBB.getBasicBlock();736 auto *FalseBB = MF->CreateMachineBasicBlock(LLVM_BB);737 auto *SinkBB = MF->CreateMachineBasicBlock(LLVM_BB);738 739 MF->insert(++MBB.getIterator(), FalseBB);740 MF->insert(++FalseBB->getIterator(), SinkBB);741 742 Register DestReg = MI.getOperand(0).getReg();743 Register SrcReg = MI.getOperand(1).getReg();744 // DestReg = 0745 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::SET_CFR_FALSE), DestReg);746 // Insert branch instruction.747 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::BCEQZ))748 .addReg(SrcReg)749 .addMBB(SinkBB);750 // DestReg = 1751 BuildMI(FalseBB, DL, TII->get(LoongArch::SET_CFR_TRUE), DestReg);752 753 FalseBB->addSuccessor(SinkBB);754 755 SinkBB->splice(SinkBB->end(), &MBB, MI, MBB.end());756 SinkBB->transferSuccessors(&MBB);757 758 MBB.addSuccessor(FalseBB);759 MBB.addSuccessor(SinkBB);760 761 NextMBBI = MBB.end();762 MI.eraseFromParent();763 764 // Make sure live-ins are correctly attached to this new basic block.765 LivePhysRegs LiveRegs;766 computeAndAddLiveIns(LiveRegs, *FalseBB);767 computeAndAddLiveIns(LiveRegs, *SinkBB);768 769 return true;770}771 772bool LoongArchExpandPseudo::expandFunctionCALL(773 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,774 MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {775 MachineFunction *MF = MBB.getParent();776 MachineInstr &MI = *MBBI;777 DebugLoc DL = MI.getDebugLoc();778 const MachineOperand &Func = MI.getOperand(0);779 MachineInstrBuilder CALL;780 unsigned Opcode;781 782 switch (MF->getTarget().getCodeModel()) {783 default:784 report_fatal_error("Unexpected code model");785 break;786 case CodeModel::Medium: {787 // CALL:788 // pcaddu18i $ra, %call36(func)789 // jirl $ra, $ra, 0790 // TAIL:791 // pcaddu18i $t8, %call36(func)792 // jirl $r0, $t8, 0793 Opcode =794 IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;795 Register ScratchReg = IsTailCall ? LoongArch::R20 : LoongArch::R1;796 MachineInstrBuilder MIB =797 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCADDU18I), ScratchReg);798 799 CALL =800 BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(ScratchReg).addImm(0);801 802 if (Func.isSymbol())803 MIB.addExternalSymbol(Func.getSymbolName(), LoongArchII::MO_CALL36);804 else805 MIB.addDisp(Func, 0, LoongArchII::MO_CALL36);806 break;807 }808 }809 810 // Transfer implicit operands.811 CALL.copyImplicitOps(MI);812 813 // Transfer MI flags.814 CALL.setMIFlags(MI.getFlags());815 816 MI.eraseFromParent();817 return true;818}819 820} // end namespace821 822INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "loongarch-prera-expand-pseudo",823 LOONGARCH_PRERA_EXPAND_PSEUDO_NAME, false, false)824 825INITIALIZE_PASS(LoongArchExpandPseudo, "loongarch-expand-pseudo",826 LOONGARCH_EXPAND_PSEUDO_NAME, false, false)827 828namespace llvm {829 830FunctionPass *createLoongArchPreRAExpandPseudoPass() {831 return new LoongArchPreRAExpandPseudo();832}833FunctionPass *createLoongArchExpandPseudoPass() {834 return new LoongArchExpandPseudo();835}836 837} // end namespace llvm838