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
28using 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
35namespace {
36
37class LoongArchPreRAExpandPseudo : public MachineFunctionPass {
38public:
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
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 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
85char LoongArchPreRAExpandPseudo::ID = 0;
86
87bool 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
96bool 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
109bool 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
129bool 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
157bool 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
170bool 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
183bool 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
231bool 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
244bool 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
257bool 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
270class LoongArchExpandPseudo : public MachineFunctionPass {
271public:
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
285private:
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
322char LoongArchExpandPseudo::ID = 0;
323
324bool 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
335bool 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
348bool 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
377bool 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
430bool 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
440bool 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
518bool 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
527bool 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
536bool 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
545bool 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
554bool 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
563bool 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
638INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "loongarch-prera-expand-pseudo",
639 LOONGARCH_PRERA_EXPAND_PSEUDO_NAME, false, false)
640
641INITIALIZE_PASS(LoongArchExpandPseudo, "loongarch-expand-pseudo",
642 LOONGARCH_EXPAND_PSEUDO_NAME, false, false)
643
644namespace llvm {
645
646FunctionPass *createLoongArchPreRAExpandPseudoPass() {
647 return new LoongArchPreRAExpandPseudo();
648}
649FunctionPass *createLoongArchExpandPseudoPass() {
650 return new LoongArchExpandPseudo();
651}
652
653} // end namespace llvm
654

source code of llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp