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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains a pass that expands pseudo instructions into target 10 // instructions. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "LoongArch.h" 15 #include "LoongArchInstrInfo.h" 16 #include "LoongArchTargetMachine.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/MC/MCContext.h" 23 #include "llvm/Support/CodeGen.h" 24 25 using namespace llvm; 26 27 #define LOONGARCH_PRERA_EXPAND_PSEUDO_NAME \ 28 "LoongArch Pre-RA pseudo instruction expansion pass" 29 30 namespace { 31 32 class LoongArchPreRAExpandPseudo : public MachineFunctionPass { 33 public: 34 const LoongArchInstrInfo *TII; 35 static char ID; 36 37 LoongArchPreRAExpandPseudo() : MachineFunctionPass(ID) { 38 initializeLoongArchPreRAExpandPseudoPass(*PassRegistry::getPassRegistry()); 39 } 40 41 bool runOnMachineFunction(MachineFunction &MF) override; 42 43 void getAnalysisUsage(AnalysisUsage &AU) const override { 44 AU.setPreservesCFG(); 45 MachineFunctionPass::getAnalysisUsage(AU); 46 } 47 StringRef getPassName() const override { 48 return LOONGARCH_PRERA_EXPAND_PSEUDO_NAME; 49 } 50 51 private: 52 bool expandMBB(MachineBasicBlock &MBB); 53 bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 54 MachineBasicBlock::iterator &NextMBBI); 55 bool expandPcalau12iInstPair(MachineBasicBlock &MBB, 56 MachineBasicBlock::iterator MBBI, 57 MachineBasicBlock::iterator &NextMBBI, 58 unsigned FlagsHi, unsigned SecondOpcode, 59 unsigned FlagsLo); 60 bool expandLoadAddressPcrel(MachineBasicBlock &MBB, 61 MachineBasicBlock::iterator MBBI, 62 MachineBasicBlock::iterator &NextMBBI); 63 bool expandLoadAddressGot(MachineBasicBlock &MBB, 64 MachineBasicBlock::iterator MBBI, 65 MachineBasicBlock::iterator &NextMBBI); 66 bool expandLoadAddressTLSLE(MachineBasicBlock &MBB, 67 MachineBasicBlock::iterator MBBI, 68 MachineBasicBlock::iterator &NextMBBI); 69 bool expandLoadAddressTLSIE(MachineBasicBlock &MBB, 70 MachineBasicBlock::iterator MBBI, 71 MachineBasicBlock::iterator &NextMBBI); 72 bool expandLoadAddressTLSLD(MachineBasicBlock &MBB, 73 MachineBasicBlock::iterator MBBI, 74 MachineBasicBlock::iterator &NextMBBI); 75 bool expandLoadAddressTLSGD(MachineBasicBlock &MBB, 76 MachineBasicBlock::iterator MBBI, 77 MachineBasicBlock::iterator &NextMBBI); 78 bool expandFunctionCALL(MachineBasicBlock &MBB, 79 MachineBasicBlock::iterator MBBI, 80 MachineBasicBlock::iterator &NextMBBI, 81 bool IsTailCall); 82 }; 83 84 char LoongArchPreRAExpandPseudo::ID = 0; 85 86 bool LoongArchPreRAExpandPseudo::runOnMachineFunction(MachineFunction &MF) { 87 TII = 88 static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo()); 89 bool Modified = false; 90 for (auto &MBB : MF) 91 Modified |= expandMBB(MBB); 92 return Modified; 93 } 94 95 bool LoongArchPreRAExpandPseudo::expandMBB(MachineBasicBlock &MBB) { 96 bool Modified = false; 97 98 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); 99 while (MBBI != E) { 100 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 101 Modified |= expandMI(MBB, MBBI, NMBBI); 102 MBBI = NMBBI; 103 } 104 105 return Modified; 106 } 107 108 bool LoongArchPreRAExpandPseudo::expandMI( 109 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 110 MachineBasicBlock::iterator &NextMBBI) { 111 switch (MBBI->getOpcode()) { 112 case LoongArch::PseudoLA_PCREL: 113 return expandLoadAddressPcrel(MBB, MBBI, NextMBBI); 114 case LoongArch::PseudoLA_GOT: 115 return expandLoadAddressGot(MBB, MBBI, NextMBBI); 116 case LoongArch::PseudoLA_TLS_LE: 117 return expandLoadAddressTLSLE(MBB, MBBI, NextMBBI); 118 case LoongArch::PseudoLA_TLS_IE: 119 return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI); 120 case LoongArch::PseudoLA_TLS_LD: 121 return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI); 122 case LoongArch::PseudoLA_TLS_GD: 123 return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI); 124 case LoongArch::PseudoCALL: 125 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false); 126 case LoongArch::PseudoTAIL: 127 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true); 128 } 129 return false; 130 } 131 132 bool LoongArchPreRAExpandPseudo::expandPcalau12iInstPair( 133 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 134 MachineBasicBlock::iterator &NextMBBI, unsigned FlagsHi, 135 unsigned SecondOpcode, unsigned FlagsLo) { 136 MachineFunction *MF = MBB.getParent(); 137 MachineInstr &MI = *MBBI; 138 DebugLoc DL = MI.getDebugLoc(); 139 140 Register DestReg = MI.getOperand(0).getReg(); 141 Register ScratchReg = 142 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); 143 MachineOperand &Symbol = MI.getOperand(1); 144 145 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg) 146 .addDisp(Symbol, 0, FlagsHi); 147 148 MachineInstr *SecondMI = 149 BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg) 150 .addReg(ScratchReg) 151 .addDisp(Symbol, 0, FlagsLo); 152 153 if (MI.hasOneMemOperand()) 154 SecondMI->addMemOperand(*MF, *MI.memoperands_begin()); 155 156 MI.eraseFromParent(); 157 return true; 158 } 159 160 bool LoongArchPreRAExpandPseudo::expandLoadAddressPcrel( 161 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 162 MachineBasicBlock::iterator &NextMBBI) { 163 // Code Sequence: 164 // pcalau12i $rd, %pc_hi20(sym) 165 // addi.w/d $rd, $rd, %pc_lo12(sym) 166 MachineFunction *MF = MBB.getParent(); 167 const auto &STI = MF->getSubtarget<LoongArchSubtarget>(); 168 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; 169 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_PCREL_HI, 170 SecondOpcode, LoongArchII::MO_PCREL_LO); 171 } 172 173 bool LoongArchPreRAExpandPseudo::expandLoadAddressGot( 174 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 175 MachineBasicBlock::iterator &NextMBBI) { 176 // Code Sequence: 177 // pcalau12i $rd, %got_pc_hi20(sym) 178 // ld.w/d $rd, $rd, %got_pc_lo12(sym) 179 MachineFunction *MF = MBB.getParent(); 180 const auto &STI = MF->getSubtarget<LoongArchSubtarget>(); 181 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; 182 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GOT_PC_HI, 183 SecondOpcode, LoongArchII::MO_GOT_PC_LO); 184 } 185 186 bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLE( 187 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 188 MachineBasicBlock::iterator &NextMBBI) { 189 // Code Sequence: 190 // lu12i.w $rd, %le_hi20(sym) 191 // ori $rd, $rd, %le_lo12(sym) 192 MachineFunction *MF = MBB.getParent(); 193 MachineInstr &MI = *MBBI; 194 DebugLoc DL = MI.getDebugLoc(); 195 196 Register DestReg = MI.getOperand(0).getReg(); 197 Register ScratchReg = 198 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); 199 MachineOperand &Symbol = MI.getOperand(1); 200 201 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W), ScratchReg) 202 .addDisp(Symbol, 0, LoongArchII::MO_LE_HI); 203 204 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ORI), DestReg) 205 .addReg(ScratchReg) 206 .addDisp(Symbol, 0, LoongArchII::MO_LE_LO); 207 208 MI.eraseFromParent(); 209 return true; 210 } 211 212 bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSIE( 213 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 214 MachineBasicBlock::iterator &NextMBBI) { 215 // Code Sequence: 216 // pcalau12i $rd, %ie_pc_hi20(sym) 217 // ld.w/d $rd, $rd, %ie_pc_lo12(sym) 218 MachineFunction *MF = MBB.getParent(); 219 const auto &STI = MF->getSubtarget<LoongArchSubtarget>(); 220 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; 221 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_IE_PC_HI, 222 SecondOpcode, LoongArchII::MO_IE_PC_LO); 223 } 224 225 bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLD( 226 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 227 MachineBasicBlock::iterator &NextMBBI) { 228 // Code Sequence: 229 // pcalau12i $rd, %ld_pc_hi20(sym) 230 // addi.w/d $rd, $rd, %got_pc_lo12(sym) 231 MachineFunction *MF = MBB.getParent(); 232 const auto &STI = MF->getSubtarget<LoongArchSubtarget>(); 233 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; 234 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_LD_PC_HI, 235 SecondOpcode, LoongArchII::MO_GOT_PC_LO); 236 } 237 238 bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSGD( 239 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 240 MachineBasicBlock::iterator &NextMBBI) { 241 // Code Sequence: 242 // pcalau12i $rd, %gd_pc_hi20(sym) 243 // addi.w/d $rd, $rd, %got_pc_lo12(sym) 244 MachineFunction *MF = MBB.getParent(); 245 const auto &STI = MF->getSubtarget<LoongArchSubtarget>(); 246 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; 247 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GD_PC_HI, 248 SecondOpcode, LoongArchII::MO_GOT_PC_LO); 249 } 250 251 bool LoongArchPreRAExpandPseudo::expandFunctionCALL( 252 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 253 MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) { 254 MachineFunction *MF = MBB.getParent(); 255 MachineInstr &MI = *MBBI; 256 DebugLoc DL = MI.getDebugLoc(); 257 const MachineOperand &Func = MI.getOperand(0); 258 MachineInstrBuilder CALL; 259 unsigned Opcode; 260 261 switch (MF->getTarget().getCodeModel()) { 262 default: 263 report_fatal_error("Unsupported code model"); 264 break; 265 case CodeModel::Small: { 266 // CALL: 267 // bl func 268 // TAIL: 269 // b func 270 Opcode = IsTailCall ? LoongArch::PseudoB_TAIL : LoongArch::BL; 271 CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).add(Func); 272 break; 273 } 274 case CodeModel::Medium: { 275 // CALL: 276 // pcalau12i $ra, %pc_hi20(func) 277 // jirl $ra, $ra, %pc_lo12(func) 278 // TAIL: 279 // pcalau12i $scratch, %pc_hi20(func) 280 // jirl $r0, $scratch, %pc_lo12(func) 281 Opcode = 282 IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL; 283 Register ScratchReg = 284 IsTailCall 285 ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass) 286 : LoongArch::R1; 287 MachineInstrBuilder MIB = 288 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg); 289 CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(ScratchReg); 290 if (Func.isSymbol()) { 291 const char *FnName = Func.getSymbolName(); 292 MIB.addExternalSymbol(FnName, LoongArchII::MO_PCREL_HI); 293 CALL.addExternalSymbol(FnName, LoongArchII::MO_PCREL_LO); 294 break; 295 } 296 assert(Func.isGlobal() && "Expected a GlobalValue at this time"); 297 const GlobalValue *GV = Func.getGlobal(); 298 MIB.addGlobalAddress(GV, 0, LoongArchII::MO_PCREL_HI); 299 CALL.addGlobalAddress(GV, 0, LoongArchII::MO_PCREL_LO); 300 break; 301 } 302 } 303 304 // Transfer implicit operands. 305 CALL.copyImplicitOps(MI); 306 307 // Transfer MI flags. 308 CALL.setMIFlags(MI.getFlags()); 309 310 MI.eraseFromParent(); 311 return true; 312 } 313 314 } // end namespace 315 316 INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "loongarch-prera-expand-pseudo", 317 LOONGARCH_PRERA_EXPAND_PSEUDO_NAME, false, false) 318 319 namespace llvm { 320 321 FunctionPass *createLoongArchPreRAExpandPseudoPass() { 322 return new LoongArchPreRAExpandPseudo(); 323 } 324 325 } // end namespace llvm 326