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