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
LoongArchPreRAExpandPseudo()37 LoongArchPreRAExpandPseudo() : MachineFunctionPass(ID) {
38 initializeLoongArchPreRAExpandPseudoPass(*PassRegistry::getPassRegistry());
39 }
40
41 bool runOnMachineFunction(MachineFunction &MF) override;
42
getAnalysisUsage(AnalysisUsage & AU) const43 void getAnalysisUsage(AnalysisUsage &AU) const override {
44 AU.setPreservesCFG();
45 MachineFunctionPass::getAnalysisUsage(AU);
46 }
getPassName() const47 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
runOnMachineFunction(MachineFunction & MF)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
expandMBB(MachineBasicBlock & MBB)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
expandMI(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)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
expandPcalau12iInstPair(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI,unsigned FlagsHi,unsigned SecondOpcode,unsigned FlagsLo)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
expandLoadAddressPcrel(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)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
expandLoadAddressGot(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)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
expandLoadAddressTLSLE(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)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
expandLoadAddressTLSIE(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)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
expandLoadAddressTLSLD(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)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
expandLoadAddressTLSGD(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI)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
expandFunctionCALL(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,MachineBasicBlock::iterator & NextMBBI,bool IsTailCall)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
createLoongArchPreRAExpandPseudoPass()321 FunctionPass *createLoongArchPreRAExpandPseudoPass() {
322 return new LoongArchPreRAExpandPseudo();
323 }
324
325 } // end namespace llvm
326