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/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 | |
28 | using namespace llvm; |
29 | |
30 | #define LOONGARCH_PRERA_EXPAND_PSEUDO_NAME \ |
31 | "LoongArch Pre-RA pseudo instruction expansion pass" |
32 | #define LOONGARCH_EXPAND_PSEUDO_NAME \ |
33 | "LoongArch pseudo instruction expansion pass" |
34 | |
35 | namespace { |
36 | |
37 | class LoongArchPreRAExpandPseudo : public MachineFunctionPass { |
38 | public: |
39 | const LoongArchInstrInfo *TII; |
40 | static char ID; |
41 | |
42 | LoongArchPreRAExpandPseudo() : MachineFunctionPass(ID) { |
43 | initializeLoongArchPreRAExpandPseudoPass(*PassRegistry::getPassRegistry()); |
44 | } |
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 | |
56 | private: |
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 expandLoadAddressPcrel(MachineBasicBlock &MBB, |
66 | MachineBasicBlock::iterator MBBI, |
67 | MachineBasicBlock::iterator &NextMBBI); |
68 | bool expandLoadAddressGot(MachineBasicBlock &MBB, |
69 | MachineBasicBlock::iterator MBBI, |
70 | MachineBasicBlock::iterator &NextMBBI); |
71 | bool expandLoadAddressTLSLE(MachineBasicBlock &MBB, |
72 | MachineBasicBlock::iterator MBBI, |
73 | MachineBasicBlock::iterator &NextMBBI); |
74 | bool expandLoadAddressTLSIE(MachineBasicBlock &MBB, |
75 | MachineBasicBlock::iterator MBBI, |
76 | MachineBasicBlock::iterator &NextMBBI); |
77 | bool expandLoadAddressTLSLD(MachineBasicBlock &MBB, |
78 | MachineBasicBlock::iterator MBBI, |
79 | MachineBasicBlock::iterator &NextMBBI); |
80 | bool expandLoadAddressTLSGD(MachineBasicBlock &MBB, |
81 | MachineBasicBlock::iterator MBBI, |
82 | MachineBasicBlock::iterator &NextMBBI); |
83 | }; |
84 | |
85 | char LoongArchPreRAExpandPseudo::ID = 0; |
86 | |
87 | bool LoongArchPreRAExpandPseudo::runOnMachineFunction(MachineFunction &MF) { |
88 | TII = |
89 | static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo()); |
90 | bool Modified = false; |
91 | for (auto &MBB : MF) |
92 | Modified |= expandMBB(MBB); |
93 | return Modified; |
94 | } |
95 | |
96 | bool LoongArchPreRAExpandPseudo::expandMBB(MachineBasicBlock &MBB) { |
97 | bool Modified = false; |
98 | |
99 | MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); |
100 | while (MBBI != E) { |
101 | MachineBasicBlock::iterator NMBBI = std::next(x: MBBI); |
102 | Modified |= expandMI(MBB, MBBI, NextMBBI&: NMBBI); |
103 | MBBI = NMBBI; |
104 | } |
105 | |
106 | return Modified; |
107 | } |
108 | |
109 | bool LoongArchPreRAExpandPseudo::expandMI( |
110 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
111 | MachineBasicBlock::iterator &NextMBBI) { |
112 | switch (MBBI->getOpcode()) { |
113 | case LoongArch::PseudoLA_PCREL: |
114 | return expandLoadAddressPcrel(MBB, MBBI, NextMBBI); |
115 | case LoongArch::PseudoLA_GOT: |
116 | return expandLoadAddressGot(MBB, MBBI, NextMBBI); |
117 | case LoongArch::PseudoLA_TLS_LE: |
118 | return expandLoadAddressTLSLE(MBB, MBBI, NextMBBI); |
119 | case LoongArch::PseudoLA_TLS_IE: |
120 | return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI); |
121 | case LoongArch::PseudoLA_TLS_LD: |
122 | return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI); |
123 | case LoongArch::PseudoLA_TLS_GD: |
124 | return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI); |
125 | } |
126 | return false; |
127 | } |
128 | |
129 | bool LoongArchPreRAExpandPseudo::expandPcalau12iInstPair( |
130 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
131 | MachineBasicBlock::iterator &NextMBBI, unsigned FlagsHi, |
132 | unsigned SecondOpcode, unsigned FlagsLo) { |
133 | MachineFunction *MF = MBB.getParent(); |
134 | MachineInstr &MI = *MBBI; |
135 | DebugLoc DL = MI.getDebugLoc(); |
136 | |
137 | Register DestReg = MI.getOperand(i: 0).getReg(); |
138 | Register ScratchReg = |
139 | MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); |
140 | MachineOperand &Symbol = MI.getOperand(i: 1); |
141 | |
142 | BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg) |
143 | .addDisp(Symbol, 0, FlagsHi); |
144 | |
145 | MachineInstr *SecondMI = |
146 | BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg) |
147 | .addReg(ScratchReg) |
148 | .addDisp(Symbol, 0, FlagsLo); |
149 | |
150 | if (MI.hasOneMemOperand()) |
151 | SecondMI->addMemOperand(MF&: *MF, MO: *MI.memoperands_begin()); |
152 | |
153 | MI.eraseFromParent(); |
154 | return true; |
155 | } |
156 | |
157 | bool LoongArchPreRAExpandPseudo::expandLoadAddressPcrel( |
158 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
159 | MachineBasicBlock::iterator &NextMBBI) { |
160 | // Code Sequence: |
161 | // pcalau12i $rd, %pc_hi20(sym) |
162 | // addi.w/d $rd, $rd, %pc_lo12(sym) |
163 | MachineFunction *MF = MBB.getParent(); |
164 | const auto &STI = MF->getSubtarget<LoongArchSubtarget>(); |
165 | unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; |
166 | return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, FlagsHi: LoongArchII::MO_PCREL_HI, |
167 | SecondOpcode, FlagsLo: LoongArchII::MO_PCREL_LO); |
168 | } |
169 | |
170 | bool LoongArchPreRAExpandPseudo::expandLoadAddressGot( |
171 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
172 | MachineBasicBlock::iterator &NextMBBI) { |
173 | // Code Sequence: |
174 | // pcalau12i $rd, %got_pc_hi20(sym) |
175 | // ld.w/d $rd, $rd, %got_pc_lo12(sym) |
176 | MachineFunction *MF = MBB.getParent(); |
177 | const auto &STI = MF->getSubtarget<LoongArchSubtarget>(); |
178 | unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; |
179 | return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, FlagsHi: LoongArchII::MO_GOT_PC_HI, |
180 | SecondOpcode, FlagsLo: LoongArchII::MO_GOT_PC_LO); |
181 | } |
182 | |
183 | bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLE( |
184 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
185 | MachineBasicBlock::iterator &NextMBBI) { |
186 | // Code Sequence: |
187 | // lu12i.w $rd, %le_hi20(sym) |
188 | // ori $rd, $rd, %le_lo12(sym) |
189 | // |
190 | // And additionally if generating code using the large code model: |
191 | // |
192 | // lu32i.d $rd, %le64_lo20(sym) |
193 | // lu52i.d $rd, $rd, %le64_hi12(sym) |
194 | MachineFunction *MF = MBB.getParent(); |
195 | MachineInstr &MI = *MBBI; |
196 | DebugLoc DL = MI.getDebugLoc(); |
197 | |
198 | bool Large = MF->getTarget().getCodeModel() == CodeModel::Large; |
199 | Register DestReg = MI.getOperand(i: 0).getReg(); |
200 | Register Parts01 = |
201 | Large ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass) |
202 | : DestReg; |
203 | Register Part1 = |
204 | MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); |
205 | MachineOperand &Symbol = MI.getOperand(i: 1); |
206 | |
207 | BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W), Part1) |
208 | .addDisp(Symbol, 0, LoongArchII::MO_LE_HI); |
209 | |
210 | BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ORI), Parts01) |
211 | .addReg(Part1, RegState::Kill) |
212 | .addDisp(Symbol, 0, LoongArchII::MO_LE_LO); |
213 | |
214 | if (Large) { |
215 | Register Parts012 = |
216 | MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); |
217 | |
218 | BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), Parts012) |
219 | // "rj" is needed due to InstrInfo pattern requirement. |
220 | .addReg(Parts01, RegState::Kill) |
221 | .addDisp(Symbol, 0, LoongArchII::MO_LE64_LO); |
222 | BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), DestReg) |
223 | .addReg(Parts012, RegState::Kill) |
224 | .addDisp(Symbol, 0, LoongArchII::MO_LE64_HI); |
225 | } |
226 | |
227 | MI.eraseFromParent(); |
228 | return true; |
229 | } |
230 | |
231 | bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSIE( |
232 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
233 | MachineBasicBlock::iterator &NextMBBI) { |
234 | // Code Sequence: |
235 | // pcalau12i $rd, %ie_pc_hi20(sym) |
236 | // ld.w/d $rd, $rd, %ie_pc_lo12(sym) |
237 | MachineFunction *MF = MBB.getParent(); |
238 | const auto &STI = MF->getSubtarget<LoongArchSubtarget>(); |
239 | unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; |
240 | return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, FlagsHi: LoongArchII::MO_IE_PC_HI, |
241 | SecondOpcode, FlagsLo: LoongArchII::MO_IE_PC_LO); |
242 | } |
243 | |
244 | bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLD( |
245 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
246 | MachineBasicBlock::iterator &NextMBBI) { |
247 | // Code Sequence: |
248 | // pcalau12i $rd, %ld_pc_hi20(sym) |
249 | // addi.w/d $rd, $rd, %got_pc_lo12(sym) |
250 | MachineFunction *MF = MBB.getParent(); |
251 | const auto &STI = MF->getSubtarget<LoongArchSubtarget>(); |
252 | unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; |
253 | return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, FlagsHi: LoongArchII::MO_LD_PC_HI, |
254 | SecondOpcode, FlagsLo: LoongArchII::MO_GOT_PC_LO); |
255 | } |
256 | |
257 | bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSGD( |
258 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
259 | MachineBasicBlock::iterator &NextMBBI) { |
260 | // Code Sequence: |
261 | // pcalau12i $rd, %gd_pc_hi20(sym) |
262 | // addi.w/d $rd, $rd, %got_pc_lo12(sym) |
263 | MachineFunction *MF = MBB.getParent(); |
264 | const auto &STI = MF->getSubtarget<LoongArchSubtarget>(); |
265 | unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; |
266 | return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, FlagsHi: LoongArchII::MO_GD_PC_HI, |
267 | SecondOpcode, FlagsLo: LoongArchII::MO_GOT_PC_LO); |
268 | } |
269 | |
270 | class LoongArchExpandPseudo : public MachineFunctionPass { |
271 | public: |
272 | const LoongArchInstrInfo *TII; |
273 | static char ID; |
274 | |
275 | LoongArchExpandPseudo() : MachineFunctionPass(ID) { |
276 | initializeLoongArchExpandPseudoPass(*PassRegistry::getPassRegistry()); |
277 | } |
278 | |
279 | bool runOnMachineFunction(MachineFunction &MF) override; |
280 | |
281 | StringRef getPassName() const override { |
282 | return LOONGARCH_EXPAND_PSEUDO_NAME; |
283 | } |
284 | |
285 | private: |
286 | bool expandMBB(MachineBasicBlock &MBB); |
287 | bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
288 | MachineBasicBlock::iterator &NextMBBI); |
289 | bool expandCopyCFR(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
290 | MachineBasicBlock::iterator &NextMBBI); |
291 | bool expandLargeAddressLoad(MachineBasicBlock &MBB, |
292 | MachineBasicBlock::iterator MBBI, |
293 | MachineBasicBlock::iterator &NextMBBI, |
294 | unsigned LastOpcode, unsigned IdentifyingMO); |
295 | bool expandLargeAddressLoad(MachineBasicBlock &MBB, |
296 | MachineBasicBlock::iterator MBBI, |
297 | MachineBasicBlock::iterator &NextMBBI, |
298 | unsigned LastOpcode, unsigned IdentifyingMO, |
299 | const MachineOperand &Symbol, Register DestReg, |
300 | bool EraseFromParent); |
301 | bool expandLoadAddressPcrelLarge(MachineBasicBlock &MBB, |
302 | MachineBasicBlock::iterator MBBI, |
303 | MachineBasicBlock::iterator &NextMBBI); |
304 | bool expandLoadAddressGotLarge(MachineBasicBlock &MBB, |
305 | MachineBasicBlock::iterator MBBI, |
306 | MachineBasicBlock::iterator &NextMBBI); |
307 | bool expandLoadAddressTLSIELarge(MachineBasicBlock &MBB, |
308 | MachineBasicBlock::iterator MBBI, |
309 | MachineBasicBlock::iterator &NextMBBI); |
310 | bool expandLoadAddressTLSLDLarge(MachineBasicBlock &MBB, |
311 | MachineBasicBlock::iterator MBBI, |
312 | MachineBasicBlock::iterator &NextMBBI); |
313 | bool expandLoadAddressTLSGDLarge(MachineBasicBlock &MBB, |
314 | MachineBasicBlock::iterator MBBI, |
315 | MachineBasicBlock::iterator &NextMBBI); |
316 | bool expandFunctionCALL(MachineBasicBlock &MBB, |
317 | MachineBasicBlock::iterator MBBI, |
318 | MachineBasicBlock::iterator &NextMBBI, |
319 | bool IsTailCall); |
320 | }; |
321 | |
322 | char LoongArchExpandPseudo::ID = 0; |
323 | |
324 | bool LoongArchExpandPseudo::runOnMachineFunction(MachineFunction &MF) { |
325 | TII = |
326 | static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo()); |
327 | |
328 | bool Modified = false; |
329 | for (auto &MBB : MF) |
330 | Modified |= expandMBB(MBB); |
331 | |
332 | return Modified; |
333 | } |
334 | |
335 | bool LoongArchExpandPseudo::expandMBB(MachineBasicBlock &MBB) { |
336 | bool Modified = false; |
337 | |
338 | MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); |
339 | while (MBBI != E) { |
340 | MachineBasicBlock::iterator NMBBI = std::next(x: MBBI); |
341 | Modified |= expandMI(MBB, MBBI, NextMBBI&: NMBBI); |
342 | MBBI = NMBBI; |
343 | } |
344 | |
345 | return Modified; |
346 | } |
347 | |
348 | bool LoongArchExpandPseudo::expandMI(MachineBasicBlock &MBB, |
349 | MachineBasicBlock::iterator MBBI, |
350 | MachineBasicBlock::iterator &NextMBBI) { |
351 | switch (MBBI->getOpcode()) { |
352 | case LoongArch::PseudoCopyCFR: |
353 | return expandCopyCFR(MBB, MBBI, NextMBBI); |
354 | case LoongArch::PseudoLA_PCREL_LARGE: |
355 | return expandLoadAddressPcrelLarge(MBB, MBBI, NextMBBI); |
356 | case LoongArch::PseudoLA_GOT_LARGE: |
357 | return expandLoadAddressGotLarge(MBB, MBBI, NextMBBI); |
358 | case LoongArch::PseudoLA_TLS_IE_LARGE: |
359 | return expandLoadAddressTLSIELarge(MBB, MBBI, NextMBBI); |
360 | case LoongArch::PseudoLA_TLS_LD_LARGE: |
361 | return expandLoadAddressTLSLDLarge(MBB, MBBI, NextMBBI); |
362 | case LoongArch::PseudoLA_TLS_GD_LARGE: |
363 | return expandLoadAddressTLSGDLarge(MBB, MBBI, NextMBBI); |
364 | case LoongArch::PseudoCALL: |
365 | case LoongArch::PseudoCALL_MEDIUM: |
366 | case LoongArch::PseudoCALL_LARGE: |
367 | return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false); |
368 | case LoongArch::PseudoTAIL: |
369 | case LoongArch::PseudoTAIL_MEDIUM: |
370 | case LoongArch::PseudoTAIL_LARGE: |
371 | return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true); |
372 | } |
373 | |
374 | return false; |
375 | } |
376 | |
377 | bool LoongArchExpandPseudo::expandCopyCFR( |
378 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
379 | MachineBasicBlock::iterator &NextMBBI) { |
380 | MachineFunction *MF = MBB.getParent(); |
381 | MachineInstr &MI = *MBBI; |
382 | DebugLoc DL = MI.getDebugLoc(); |
383 | |
384 | // Expand: |
385 | // MBB: |
386 | // fcmp.caf.s $dst, $fa0, $fa0 # set $dst 0(false) |
387 | // bceqz $src, SinkBB |
388 | // FalseBB: |
389 | // fcmp.cueq.s $dst, $fa0, $fa0 # set $dst 1(true) |
390 | // SinkBB: |
391 | // fallthrough |
392 | |
393 | const BasicBlock *LLVM_BB = MBB.getBasicBlock(); |
394 | auto *FalseBB = MF->CreateMachineBasicBlock(BB: LLVM_BB); |
395 | auto *SinkBB = MF->CreateMachineBasicBlock(BB: LLVM_BB); |
396 | |
397 | MF->insert(MBBI: ++MBB.getIterator(), MBB: FalseBB); |
398 | MF->insert(MBBI: ++FalseBB->getIterator(), MBB: SinkBB); |
399 | |
400 | Register DestReg = MI.getOperand(i: 0).getReg(); |
401 | Register SrcReg = MI.getOperand(i: 1).getReg(); |
402 | // DestReg = 0 |
403 | BuildMI(MBB, MBBI, DL, TII->get(LoongArch::SET_CFR_FALSE), DestReg); |
404 | // Insert branch instruction. |
405 | BuildMI(MBB, MBBI, DL, TII->get(LoongArch::BCEQZ)) |
406 | .addReg(SrcReg) |
407 | .addMBB(SinkBB); |
408 | // DestReg = 1 |
409 | BuildMI(FalseBB, DL, TII->get(LoongArch::SET_CFR_TRUE), DestReg); |
410 | |
411 | FalseBB->addSuccessor(Succ: SinkBB); |
412 | |
413 | SinkBB->splice(Where: SinkBB->end(), Other: &MBB, From: MI, To: MBB.end()); |
414 | SinkBB->transferSuccessors(FromMBB: &MBB); |
415 | |
416 | MBB.addSuccessor(Succ: FalseBB); |
417 | MBB.addSuccessor(Succ: SinkBB); |
418 | |
419 | NextMBBI = MBB.end(); |
420 | MI.eraseFromParent(); |
421 | |
422 | // Make sure live-ins are correctly attached to this new basic block. |
423 | LivePhysRegs LiveRegs; |
424 | computeAndAddLiveIns(LiveRegs, MBB&: *FalseBB); |
425 | computeAndAddLiveIns(LiveRegs, MBB&: *SinkBB); |
426 | |
427 | return true; |
428 | } |
429 | |
430 | bool LoongArchExpandPseudo::expandLargeAddressLoad( |
431 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
432 | MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode, |
433 | unsigned IdentifyingMO) { |
434 | MachineInstr &MI = *MBBI; |
435 | return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode, IdentifyingMO, |
436 | Symbol: MI.getOperand(i: 2), DestReg: MI.getOperand(i: 0).getReg(), |
437 | EraseFromParent: true); |
438 | } |
439 | |
440 | bool LoongArchExpandPseudo::expandLargeAddressLoad( |
441 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
442 | MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode, |
443 | unsigned IdentifyingMO, const MachineOperand &Symbol, Register DestReg, |
444 | bool EraseFromParent) { |
445 | // Code Sequence: |
446 | // |
447 | // Part1: pcalau12i $dst, %MO1(sym) |
448 | // Part0: addi.d $t8, $zero, %MO0(sym) |
449 | // Part2: lu32i.d $t8, %MO2(sym) |
450 | // Part3: lu52i.d $t8, $t8, %MO3(sym) |
451 | // Fin: LastOpcode $dst, $t8, $dst |
452 | |
453 | unsigned MO0, MO1, MO2, MO3; |
454 | switch (IdentifyingMO) { |
455 | default: |
456 | llvm_unreachable("unsupported identifying MO" ); |
457 | case LoongArchII::MO_PCREL_LO: |
458 | MO0 = IdentifyingMO; |
459 | MO1 = LoongArchII::MO_PCREL_HI; |
460 | MO2 = LoongArchII::MO_PCREL64_LO; |
461 | MO3 = LoongArchII::MO_PCREL64_HI; |
462 | break; |
463 | case LoongArchII::MO_GOT_PC_HI: |
464 | case LoongArchII::MO_LD_PC_HI: |
465 | case LoongArchII::MO_GD_PC_HI: |
466 | // These cases relocate just like the GOT case, except for Part1. |
467 | MO0 = LoongArchII::MO_GOT_PC_LO; |
468 | MO1 = IdentifyingMO; |
469 | MO2 = LoongArchII::MO_GOT_PC64_LO; |
470 | MO3 = LoongArchII::MO_GOT_PC64_HI; |
471 | break; |
472 | case LoongArchII::MO_IE_PC_LO: |
473 | MO0 = IdentifyingMO; |
474 | MO1 = LoongArchII::MO_IE_PC_HI; |
475 | MO2 = LoongArchII::MO_IE_PC64_LO; |
476 | MO3 = LoongArchII::MO_IE_PC64_HI; |
477 | break; |
478 | } |
479 | |
480 | MachineInstr &MI = *MBBI; |
481 | DebugLoc DL = MI.getDebugLoc(); |
482 | Register ScratchReg = LoongArch::R20; // $t8 |
483 | |
484 | assert(MBB.getParent()->getSubtarget<LoongArchSubtarget>().is64Bit() && |
485 | "Large code model requires LA64" ); |
486 | |
487 | auto Part1 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), DestReg); |
488 | auto Part0 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADDI_D), ScratchReg) |
489 | .addReg(LoongArch::R0); |
490 | auto Part2 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), ScratchReg) |
491 | // "rj" is needed due to InstrInfo pattern requirement. |
492 | .addReg(ScratchReg); |
493 | auto Part3 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), ScratchReg) |
494 | .addReg(ScratchReg); |
495 | BuildMI(MBB, MBBI, DL, TII->get(LastOpcode), DestReg) |
496 | .addReg(ScratchReg) |
497 | .addReg(DestReg); |
498 | |
499 | if (Symbol.getType() == MachineOperand::MO_ExternalSymbol) { |
500 | const char *SymName = Symbol.getSymbolName(); |
501 | Part0.addExternalSymbol(SymName, MO0); |
502 | Part1.addExternalSymbol(SymName, MO1); |
503 | Part2.addExternalSymbol(SymName, MO2); |
504 | Part3.addExternalSymbol(SymName, MO3); |
505 | } else { |
506 | Part0.addDisp(Symbol, 0, MO0); |
507 | Part1.addDisp(Symbol, 0, MO1); |
508 | Part2.addDisp(Symbol, 0, MO2); |
509 | Part3.addDisp(Symbol, 0, MO3); |
510 | } |
511 | |
512 | if (EraseFromParent) |
513 | MI.eraseFromParent(); |
514 | |
515 | return true; |
516 | } |
517 | |
518 | bool LoongArchExpandPseudo::expandLoadAddressPcrelLarge( |
519 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
520 | MachineBasicBlock::iterator &NextMBBI) { |
521 | // Emit the 5-insn large address load sequence with the `%pc` family of |
522 | // relocs. |
523 | return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D, |
524 | LoongArchII::MO_PCREL_LO); |
525 | } |
526 | |
527 | bool LoongArchExpandPseudo::expandLoadAddressGotLarge( |
528 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
529 | MachineBasicBlock::iterator &NextMBBI) { |
530 | // Emit the 5-insn large address load sequence with the `%got_pc` family |
531 | // of relocs, loading the result from GOT with `ldx.d` in the end. |
532 | return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::LDX_D, |
533 | LoongArchII::MO_GOT_PC_HI); |
534 | } |
535 | |
536 | bool LoongArchExpandPseudo::expandLoadAddressTLSIELarge( |
537 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
538 | MachineBasicBlock::iterator &NextMBBI) { |
539 | // Emit the 5-insn large address load sequence with the `%ie_pc` family |
540 | // of relocs, loading the result with `ldx.d` in the end. |
541 | return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::LDX_D, |
542 | LoongArchII::MO_IE_PC_LO); |
543 | } |
544 | |
545 | bool LoongArchExpandPseudo::expandLoadAddressTLSLDLarge( |
546 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
547 | MachineBasicBlock::iterator &NextMBBI) { |
548 | // Emit the 5-insn large address load sequence with the `%got_pc` family |
549 | // of relocs, with the `pcalau12i` insn relocated with `%ld_pc_hi20`. |
550 | return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D, |
551 | LoongArchII::MO_LD_PC_HI); |
552 | } |
553 | |
554 | bool LoongArchExpandPseudo::expandLoadAddressTLSGDLarge( |
555 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
556 | MachineBasicBlock::iterator &NextMBBI) { |
557 | // Emit the 5-insn large address load sequence with the `%got_pc` family |
558 | // of relocs, with the `pcalau12i` insn relocated with `%gd_pc_hi20`. |
559 | return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D, |
560 | LoongArchII::MO_GD_PC_HI); |
561 | } |
562 | |
563 | bool LoongArchExpandPseudo::expandFunctionCALL( |
564 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
565 | MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) { |
566 | MachineFunction *MF = MBB.getParent(); |
567 | MachineInstr &MI = *MBBI; |
568 | DebugLoc DL = MI.getDebugLoc(); |
569 | const MachineOperand &Func = MI.getOperand(i: 0); |
570 | MachineInstrBuilder CALL; |
571 | unsigned Opcode; |
572 | |
573 | switch (MF->getTarget().getCodeModel()) { |
574 | default: |
575 | report_fatal_error(reason: "Unsupported code model" ); |
576 | break; |
577 | case CodeModel::Small: { |
578 | // CALL: |
579 | // bl func |
580 | // TAIL: |
581 | // b func |
582 | Opcode = IsTailCall ? LoongArch::PseudoB_TAIL : LoongArch::BL; |
583 | CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).add(Func); |
584 | break; |
585 | } |
586 | case CodeModel::Medium: { |
587 | // CALL: |
588 | // pcaddu18i $ra, %call36(func) |
589 | // jirl $ra, $ra, 0 |
590 | // TAIL: |
591 | // pcaddu18i $t8, %call36(func) |
592 | // jr $t8 |
593 | Opcode = |
594 | IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL; |
595 | Register ScratchReg = IsTailCall ? LoongArch::R20 : LoongArch::R1; |
596 | MachineInstrBuilder MIB = |
597 | BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCADDU18I), ScratchReg); |
598 | |
599 | CALL = |
600 | BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(ScratchReg).addImm(0); |
601 | |
602 | if (Func.isSymbol()) |
603 | MIB.addExternalSymbol(FnName: Func.getSymbolName(), TargetFlags: LoongArchII::MO_CALL36); |
604 | else |
605 | MIB.addDisp(Disp: Func, off: 0, TargetFlags: LoongArchII::MO_CALL36); |
606 | break; |
607 | } |
608 | case CodeModel::Large: { |
609 | // Emit the 5-insn large address load sequence, either directly or |
610 | // indirectly in case of going through the GOT, then JIRL_TAIL or |
611 | // JIRL_CALL to $addr. |
612 | Opcode = |
613 | IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL; |
614 | Register AddrReg = IsTailCall ? LoongArch::R19 : LoongArch::R1; |
615 | |
616 | bool UseGOT = Func.isGlobal() && !Func.getGlobal()->isDSOLocal(); |
617 | unsigned MO = UseGOT ? LoongArchII::MO_GOT_PC_HI : LoongArchII::MO_PCREL_LO; |
618 | unsigned LAOpcode = UseGOT ? LoongArch::LDX_D : LoongArch::ADD_D; |
619 | expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode: LAOpcode, IdentifyingMO: MO, Symbol: Func, DestReg: AddrReg, |
620 | EraseFromParent: false); |
621 | CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(AddrReg).addImm(0); |
622 | break; |
623 | } |
624 | } |
625 | |
626 | // Transfer implicit operands. |
627 | CALL.copyImplicitOps(OtherMI: MI); |
628 | |
629 | // Transfer MI flags. |
630 | CALL.setMIFlags(MI.getFlags()); |
631 | |
632 | MI.eraseFromParent(); |
633 | return true; |
634 | } |
635 | |
636 | } // end namespace |
637 | |
638 | INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "loongarch-prera-expand-pseudo" , |
639 | LOONGARCH_PRERA_EXPAND_PSEUDO_NAME, false, false) |
640 | |
641 | INITIALIZE_PASS(LoongArchExpandPseudo, "loongarch-expand-pseudo" , |
642 | LOONGARCH_EXPAND_PSEUDO_NAME, false, false) |
643 | |
644 | namespace llvm { |
645 | |
646 | FunctionPass *createLoongArchPreRAExpandPseudoPass() { |
647 | return new LoongArchPreRAExpandPseudo(); |
648 | } |
649 | FunctionPass *createLoongArchExpandPseudoPass() { |
650 | return new LoongArchExpandPseudo(); |
651 | } |
652 | |
653 | } // end namespace llvm |
654 | |