LLVM 20.0.0git
LoongArchExpandPseudoInsts.cpp
Go to the documentation of this file.
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"
24#include "llvm/MC/MCContext.h"
27
28using namespace llvm;
29
31
32#define LOONGARCH_PRERA_EXPAND_PSEUDO_NAME \
33 "LoongArch Pre-RA pseudo instruction expansion pass"
34#define LOONGARCH_EXPAND_PSEUDO_NAME \
35 "LoongArch pseudo instruction expansion pass"
36
37namespace {
38
39class LoongArchPreRAExpandPseudo : public MachineFunctionPass {
40public:
42 static char ID;
43
44 LoongArchPreRAExpandPseudo() : MachineFunctionPass(ID) {
46 }
47
48 bool runOnMachineFunction(MachineFunction &MF) override;
49
50 void getAnalysisUsage(AnalysisUsage &AU) const override {
51 AU.setPreservesCFG();
53 }
54 StringRef getPassName() const override {
56 }
57
58private:
59 bool expandMBB(MachineBasicBlock &MBB);
62 bool expandPcalau12iInstPair(MachineBasicBlock &MBB,
65 unsigned FlagsHi, unsigned SecondOpcode,
66 unsigned FlagsLo);
67 bool expandLargeAddressLoad(MachineBasicBlock &MBB,
70 unsigned LastOpcode, unsigned IdentifyingMO);
71 bool expandLargeAddressLoad(MachineBasicBlock &MBB,
74 unsigned LastOpcode, unsigned IdentifyingMO,
75 const MachineOperand &Symbol, Register DestReg,
76 bool EraseFromParent);
77 bool expandLoadAddressPcrel(MachineBasicBlock &MBB,
80 bool Large = false);
81 bool expandLoadAddressGot(MachineBasicBlock &MBB,
84 bool Large = false);
85 bool expandLoadAddressTLSLE(MachineBasicBlock &MBB,
88 bool expandLoadAddressTLSIE(MachineBasicBlock &MBB,
91 bool Large = false);
92 bool expandLoadAddressTLSLD(MachineBasicBlock &MBB,
95 bool Large = false);
96 bool expandLoadAddressTLSGD(MachineBasicBlock &MBB,
99 bool Large = false);
100 bool expandLoadAddressTLSDesc(MachineBasicBlock &MBB,
103 bool Large = false);
104 bool expandFunctionCALL(MachineBasicBlock &MBB,
107 bool IsTailCall);
108 void annotateTableJump(MachineBasicBlock &MBB,
110};
111
112char LoongArchPreRAExpandPseudo::ID = 0;
113
114bool LoongArchPreRAExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
115 TII =
116 static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo());
117 bool Modified = false;
118 for (auto &MBB : MF)
119 Modified |= expandMBB(MBB);
120 return Modified;
121}
122
123bool LoongArchPreRAExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
124 bool Modified = false;
125
127 while (MBBI != E) {
128 MachineBasicBlock::iterator NMBBI = std::next(MBBI);
129 Modified |= expandMI(MBB, MBBI, NMBBI);
130 MBBI = NMBBI;
131 }
132
133 return Modified;
134}
135
136bool LoongArchPreRAExpandPseudo::expandMI(
138 MachineBasicBlock::iterator &NextMBBI) {
139 switch (MBBI->getOpcode()) {
140 case LoongArch::PseudoLA_PCREL:
141 return expandLoadAddressPcrel(MBB, MBBI, NextMBBI);
142 case LoongArch::PseudoLA_PCREL_LARGE:
143 return expandLoadAddressPcrel(MBB, MBBI, NextMBBI, /*Large=*/true);
144 case LoongArch::PseudoLA_GOT:
145 return expandLoadAddressGot(MBB, MBBI, NextMBBI);
146 case LoongArch::PseudoLA_GOT_LARGE:
147 return expandLoadAddressGot(MBB, MBBI, NextMBBI, /*Large=*/true);
148 case LoongArch::PseudoLA_TLS_LE:
149 return expandLoadAddressTLSLE(MBB, MBBI, NextMBBI);
150 case LoongArch::PseudoLA_TLS_IE:
151 return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI);
152 case LoongArch::PseudoLA_TLS_IE_LARGE:
153 return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI, /*Large=*/true);
154 case LoongArch::PseudoLA_TLS_LD:
155 return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI);
156 case LoongArch::PseudoLA_TLS_LD_LARGE:
157 return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI, /*Large=*/true);
158 case LoongArch::PseudoLA_TLS_GD:
159 return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI);
160 case LoongArch::PseudoLA_TLS_GD_LARGE:
161 return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI, /*Large=*/true);
162 case LoongArch::PseudoLA_TLS_DESC:
163 return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI);
164 case LoongArch::PseudoLA_TLS_DESC_LARGE:
165 return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI, /*Large=*/true);
166 case LoongArch::PseudoCALL:
167 case LoongArch::PseudoCALL_LARGE:
168 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
169 case LoongArch::PseudoTAIL:
170 case LoongArch::PseudoTAIL_LARGE:
171 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
172 case LoongArch::PseudoBRIND:
173 // If the PseudoBRIND is used to table jump, then emit a label to annotate
174 // the `jr` instruction, and save the instructions.
176 annotateTableJump(MBB, MBBI);
177 break;
178 }
179 return false;
180}
181
182bool LoongArchPreRAExpandPseudo::expandPcalau12iInstPair(
184 MachineBasicBlock::iterator &NextMBBI, unsigned FlagsHi,
185 unsigned SecondOpcode, unsigned FlagsLo) {
187 MachineInstr &MI = *MBBI;
188 DebugLoc DL = MI.getDebugLoc();
189
190 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
191 bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax);
192
193 Register DestReg = MI.getOperand(0).getReg();
194 Register ScratchReg =
195 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
196 MachineOperand &Symbol = MI.getOperand(1);
197
198 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg)
199 .addDisp(Symbol, 0, LoongArchII::encodeFlags(FlagsHi, EnableRelax));
200
201 MachineInstr *SecondMI =
202 BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg)
203 .addReg(ScratchReg)
204 .addDisp(Symbol, 0, LoongArchII::encodeFlags(FlagsLo, EnableRelax));
205
206 if (MI.hasOneMemOperand())
207 SecondMI->addMemOperand(*MF, *MI.memoperands_begin());
208
209 MI.eraseFromParent();
210 return true;
211}
212
213bool LoongArchPreRAExpandPseudo::expandLargeAddressLoad(
215 MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode,
216 unsigned IdentifyingMO) {
217 MachineInstr &MI = *MBBI;
218 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode, IdentifyingMO,
219 MI.getOperand(2), MI.getOperand(0).getReg(),
220 true);
221}
222
223bool LoongArchPreRAExpandPseudo::expandLargeAddressLoad(
225 MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode,
226 unsigned IdentifyingMO, const MachineOperand &Symbol, Register DestReg,
227 bool EraseFromParent) {
228 // Code Sequence:
229 //
230 // Part1: pcalau12i $scratch, %MO1(sym)
231 // Part0: addi.d $dest, $zero, %MO0(sym)
232 // Part2: lu32i.d $dest, %MO2(sym)
233 // Part3: lu52i.d $dest, $dest, %MO3(sym)
234 // Fin: LastOpcode $dest, $dest, $scratch
235
236 unsigned MO0, MO1, MO2, MO3;
237 switch (IdentifyingMO) {
238 default:
239 llvm_unreachable("unsupported identifying MO");
241 MO0 = IdentifyingMO;
245 break;
249 // These cases relocate just like the GOT case, except for Part1.
251 MO1 = IdentifyingMO;
254 break;
256 MO0 = IdentifyingMO;
260 break;
261 }
262
264 MachineInstr &MI = *MBBI;
265 DebugLoc DL = MI.getDebugLoc();
266
268 "Large code model requires LA64");
269
270 Register TmpPart1 =
271 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
272 Register TmpPart0 =
273 DestReg.isVirtual()
274 ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)
275 : DestReg;
276 Register TmpParts02 =
277 DestReg.isVirtual()
278 ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)
279 : DestReg;
280 Register TmpParts023 =
281 DestReg.isVirtual()
282 ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)
283 : DestReg;
284
285 auto Part1 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), TmpPart1);
286 auto Part0 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADDI_D), TmpPart0)
287 .addReg(LoongArch::R0);
288 auto Part2 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), TmpParts02)
289 // "rj" is needed due to InstrInfo pattern requirement.
290 .addReg(TmpPart0, RegState::Kill);
291 auto Part3 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), TmpParts023)
292 .addReg(TmpParts02, RegState::Kill);
293 BuildMI(MBB, MBBI, DL, TII->get(LastOpcode), DestReg)
294 .addReg(TmpParts023)
295 .addReg(TmpPart1, RegState::Kill);
296
297 if (Symbol.getType() == MachineOperand::MO_ExternalSymbol) {
298 const char *SymName = Symbol.getSymbolName();
299 Part0.addExternalSymbol(SymName, MO0);
300 Part1.addExternalSymbol(SymName, MO1);
301 Part2.addExternalSymbol(SymName, MO2);
302 Part3.addExternalSymbol(SymName, MO3);
303 } else {
304 Part0.addDisp(Symbol, 0, MO0);
305 Part1.addDisp(Symbol, 0, MO1);
306 Part2.addDisp(Symbol, 0, MO2);
307 Part3.addDisp(Symbol, 0, MO3);
308 }
309
310 if (EraseFromParent)
311 MI.eraseFromParent();
312
313 return true;
314}
315
316bool LoongArchPreRAExpandPseudo::expandLoadAddressPcrel(
318 MachineBasicBlock::iterator &NextMBBI, bool Large) {
319 if (Large)
320 // Emit the 5-insn large address load sequence with the `%pc` family of
321 // relocs.
322 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,
324
325 // Code Sequence:
326 // pcalau12i $rd, %pc_hi20(sym)
327 // addi.w/d $rd, $rd, %pc_lo12(sym)
329 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
330 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
331 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_PCREL_HI,
332 SecondOpcode, LoongArchII::MO_PCREL_LO);
333}
334
335bool LoongArchPreRAExpandPseudo::expandLoadAddressGot(
337 MachineBasicBlock::iterator &NextMBBI, bool Large) {
338 if (Large)
339 // Emit the 5-insn large address load sequence with the `%got_pc` family
340 // of relocs, loading the result from GOT with `ldx.d` in the end.
341 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::LDX_D,
343
344 // Code Sequence:
345 // pcalau12i $rd, %got_pc_hi20(sym)
346 // ld.w/d $rd, $rd, %got_pc_lo12(sym)
348 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
349 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
350 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GOT_PC_HI,
351 SecondOpcode, LoongArchII::MO_GOT_PC_LO);
352}
353
354bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLE(
356 MachineBasicBlock::iterator &NextMBBI) {
357 // Code Sequence:
358 // lu12i.w $rd, %le_hi20_r(sym)
359 // add.w/d $rd, $rd, $tp, %le_add_r(sym)
360 // addi.w/d $rd, $rd, %le_lo12_r(sym)
361 //
362 // Code Sequence while using the large code model:
363 // lu12i.w $rd, %le_hi20(sym)
364 // ori $rd, $rd, %le_lo12(sym)
365 // lu32i.d $rd, %le64_lo20(sym)
366 // lu52i.d $rd, $rd, %le64_hi12(sym)
368 MachineInstr &MI = *MBBI;
369 DebugLoc DL = MI.getDebugLoc();
370
371 bool Large = MF->getTarget().getCodeModel() == CodeModel::Large;
372 Register DestReg = MI.getOperand(0).getReg();
373 Register Parts01 =
374 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
375 Register Part1 =
376 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
377 MachineOperand &Symbol = MI.getOperand(1);
378
379 if (!Large) {
380 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W), Part1)
381 .addDisp(Symbol, 0, LoongArchII::MO_LE_HI_R);
382
383 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
384 unsigned AddOp = STI.is64Bit() ? LoongArch::PseudoAddTPRel_D
385 : LoongArch::PseudoAddTPRel_W;
386 BuildMI(MBB, MBBI, DL, TII->get(AddOp), Parts01)
387 .addReg(Part1, RegState::Kill)
388 .addReg(LoongArch::R2)
390
391 unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
392 BuildMI(MBB, MBBI, DL, TII->get(AddiOp), DestReg)
393 .addReg(Parts01, RegState::Kill)
394 .addDisp(Symbol, 0, LoongArchII::MO_LE_LO_R);
395 } else {
396 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W), Part1)
397 .addDisp(Symbol, 0, LoongArchII::MO_LE_HI);
398
399 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ORI), Parts01)
400 .addReg(Part1, RegState::Kill)
401 .addDisp(Symbol, 0, LoongArchII::MO_LE_LO);
402
403 Register Parts012 =
404 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
405
406 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), Parts012)
407 // "rj" is needed due to InstrInfo pattern requirement.
408 .addReg(Parts01, RegState::Kill)
409 .addDisp(Symbol, 0, LoongArchII::MO_LE64_LO);
410 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), DestReg)
411 .addReg(Parts012, RegState::Kill)
412 .addDisp(Symbol, 0, LoongArchII::MO_LE64_HI);
413 }
414
415 MI.eraseFromParent();
416 return true;
417}
418
419bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSIE(
421 MachineBasicBlock::iterator &NextMBBI, bool Large) {
422 if (Large)
423 // Emit the 5-insn large address load sequence with the `%ie_pc` family
424 // of relocs, loading the result with `ldx.d` in the end.
425 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::LDX_D,
427
428 // Code Sequence:
429 // pcalau12i $rd, %ie_pc_hi20(sym)
430 // ld.w/d $rd, $rd, %ie_pc_lo12(sym)
432 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
433 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
434 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_IE_PC_HI,
435 SecondOpcode, LoongArchII::MO_IE_PC_LO);
436}
437
438bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLD(
440 MachineBasicBlock::iterator &NextMBBI, bool Large) {
441 if (Large)
442 // Emit the 5-insn large address load sequence with the `%got_pc` family
443 // of relocs, with the `pcalau12i` insn relocated with `%ld_pc_hi20`.
444 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,
446
447 // Code Sequence:
448 // pcalau12i $rd, %ld_pc_hi20(sym)
449 // addi.w/d $rd, $rd, %got_pc_lo12(sym)
451 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
452 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
453 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_LD_PC_HI,
454 SecondOpcode, LoongArchII::MO_GOT_PC_LO);
455}
456
457bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSGD(
459 MachineBasicBlock::iterator &NextMBBI, bool Large) {
460 if (Large)
461 // Emit the 5-insn large address load sequence with the `%got_pc` family
462 // of relocs, with the `pcalau12i` insn relocated with `%gd_pc_hi20`.
463 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,
465
466 // Code Sequence:
467 // pcalau12i $rd, %gd_pc_hi20(sym)
468 // addi.w/d $rd, $rd, %got_pc_lo12(sym)
470 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
471 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
472 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GD_PC_HI,
473 SecondOpcode, LoongArchII::MO_GOT_PC_LO);
474}
475
476bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc(
478 MachineBasicBlock::iterator &NextMBBI, bool Large) {
480 MachineInstr &MI = *MBBI;
481 DebugLoc DL = MI.getDebugLoc();
482
483 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
484 unsigned ADD = STI.is64Bit() ? LoongArch::ADD_D : LoongArch::ADD_W;
485 unsigned ADDI = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
486 unsigned LD = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
487 bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax);
488
489 Register DestReg = MI.getOperand(0).getReg();
490 Register Tmp1Reg =
491 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
492 MachineOperand &Symbol = MI.getOperand(Large ? 2 : 1);
493
494 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), Tmp1Reg)
495 .addDisp(Symbol, 0,
497 EnableRelax && !Large));
498
499 if (Large) {
500 // Code Sequence:
501 //
502 // pcalau12i $a0, %desc_pc_hi20(sym)
503 // addi.d $a1, $zero, %desc_pc_lo12(sym)
504 // lu32i.d $a1, %desc64_pc_lo20(sym)
505 // lu52i.d $a1, $a1, %desc64_pc_hi12(sym)
506 // add.d $a0, $a0, $a1
507 // ld.d $ra, $a0, %desc_ld(sym)
508 // jirl $ra, $ra, %desc_call(sym)
509 // add.d $dst, $a0, $tp
511 "Large code model requires LA64");
512 Register Tmp2Reg =
513 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
514 Register Tmp3Reg =
515 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
516 Register Tmp4Reg =
517 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
518 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADDI_D), Tmp2Reg)
519 .addReg(LoongArch::R0)
521 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), Tmp3Reg)
522 .addReg(Tmp2Reg, RegState::Kill)
524 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), Tmp4Reg)
525 .addReg(Tmp3Reg)
527 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADD_D), LoongArch::R4)
528 .addReg(Tmp1Reg)
529 .addReg(Tmp4Reg);
530 } else {
531 // Code Sequence:
532 // pcalau12i $a0, %desc_pc_hi20(sym)
533 // addi.w/d $a0, $a0, %desc_pc_lo12(sym)
534 // ld.w/d $ra, $a0, %desc_ld(sym)
535 // jirl $ra, $ra, %desc_call(sym)
536 // add.w/d $dst, $a0, $tp
537 BuildMI(MBB, MBBI, DL, TII->get(ADDI), LoongArch::R4)
538 .addReg(Tmp1Reg)
539 .addDisp(
540 Symbol, 0,
542 }
543
544 BuildMI(MBB, MBBI, DL, TII->get(LD), LoongArch::R1)
545 .addReg(LoongArch::R4)
546 .addDisp(Symbol, 0,
548 EnableRelax && !Large));
549 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PseudoDESC_CALL), LoongArch::R1)
550 .addReg(LoongArch::R1)
551 .addDisp(Symbol, 0,
553 EnableRelax && !Large));
554 BuildMI(MBB, MBBI, DL, TII->get(ADD), DestReg)
555 .addReg(LoongArch::R4)
556 .addReg(LoongArch::R2);
557
558 MI.eraseFromParent();
559 return true;
560}
561
562bool LoongArchPreRAExpandPseudo::expandFunctionCALL(
564 MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {
566 MachineInstr &MI = *MBBI;
567 DebugLoc DL = MI.getDebugLoc();
568 const MachineOperand &Func = MI.getOperand(0);
570 unsigned Opcode;
571
572 switch (MF->getTarget().getCodeModel()) {
573 default:
574 report_fatal_error("Unexpected code model");
575 break;
576 case CodeModel::Small: {
577 // CALL:
578 // bl func
579 // TAIL:
580 // b func
581 Opcode = IsTailCall ? LoongArch::PseudoB_TAIL : LoongArch::BL;
582 CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).add(Func);
583 break;
584 }
585 case CodeModel::Large: {
586 // Emit the 5-insn large address load sequence, either directly or
587 // indirectly in case of going through the GOT, then JIRL_TAIL or
588 // JIRL_CALL to $addr.
589 Opcode =
590 IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
591 Register AddrReg =
592 IsTailCall
593 ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)
594 : LoongArch::R1;
595
596 bool UseGOT = Func.getTargetFlags() == LoongArchII::MO_CALL_PLT;
598 unsigned LAOpcode = UseGOT ? LoongArch::LDX_D : LoongArch::ADD_D;
599 expandLargeAddressLoad(MBB, MBBI, NextMBBI, LAOpcode, MO, Func, AddrReg,
600 false);
601 CALL = BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(AddrReg).addImm(0);
602 break;
603 }
604 }
605
606 // Transfer implicit operands.
607 CALL.copyImplicitOps(MI);
608
609 // Transfer MI flags.
610 CALL.setMIFlags(MI.getFlags());
611
612 MI.eraseFromParent();
613 return true;
614}
615
616void LoongArchPreRAExpandPseudo::annotateTableJump(
620
621 bool IsFound = false;
622
623 std::function<void(MachineInstr *, int)> FindJTIMI = [&](MachineInstr *MInst,
624 int FindDepth) {
625 if (FindDepth < 0)
626 return;
627 for (auto &MO : MInst->all_uses()) {
628 if (IsFound)
629 return;
630 Register Reg = MO.getReg();
631 if (!Reg.isVirtual())
632 continue;
633 MachineInstr *DefMI = MRI.getVRegDef(Reg);
634 if (!DefMI)
635 continue;
636 for (unsigned Idx = 0; Idx < DefMI->getNumOperands(); ++Idx) {
638 if (MO.isJTI()) {
639 MBBI->setPreInstrSymbol(
640 *MF, MF->getContext().createNamedTempSymbol("jrtb_"));
641 MF->getInfo<LoongArchMachineFunctionInfo>()->setJumpInfo(&*MBBI, &MO);
642 IsFound = true;
643 return;
644 }
645 }
646 FindJTIMI(DefMI, --FindDepth);
647 }
648 };
649
650 // FindDepth = 3, probably sufficient.
651 FindJTIMI(&*MBBI, /*FindDepth=*/3);
652}
653
654class LoongArchExpandPseudo : public MachineFunctionPass {
655public:
656 const LoongArchInstrInfo *TII;
657 static char ID;
658
659 LoongArchExpandPseudo() : MachineFunctionPass(ID) {
661 }
662
663 bool runOnMachineFunction(MachineFunction &MF) override;
664
665 StringRef getPassName() const override {
667 }
668
669private:
670 bool expandMBB(MachineBasicBlock &MBB);
675 bool expandFunctionCALL(MachineBasicBlock &MBB,
678 bool IsTailCall);
679};
680
681char LoongArchExpandPseudo::ID = 0;
682
683bool LoongArchExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
684 TII =
685 static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo());
686
687 bool Modified = false;
688 for (auto &MBB : MF)
689 Modified |= expandMBB(MBB);
690
691 return Modified;
692}
693
694bool LoongArchExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
695 bool Modified = false;
696
698 while (MBBI != E) {
699 MachineBasicBlock::iterator NMBBI = std::next(MBBI);
700 Modified |= expandMI(MBB, MBBI, NMBBI);
701 MBBI = NMBBI;
702 }
703
704 return Modified;
705}
706
707bool LoongArchExpandPseudo::expandMI(MachineBasicBlock &MBB,
709 MachineBasicBlock::iterator &NextMBBI) {
710 switch (MBBI->getOpcode()) {
711 case LoongArch::PseudoCopyCFR:
712 return expandCopyCFR(MBB, MBBI, NextMBBI);
713 case LoongArch::PseudoCALL_MEDIUM:
714 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
715 case LoongArch::PseudoTAIL_MEDIUM:
716 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
717 }
718
719 return false;
720}
721
722bool LoongArchExpandPseudo::expandCopyCFR(
724 MachineBasicBlock::iterator &NextMBBI) {
726 MachineInstr &MI = *MBBI;
727 DebugLoc DL = MI.getDebugLoc();
728
729 // Expand:
730 // MBB:
731 // fcmp.caf.s $dst, $fa0, $fa0 # set $dst 0(false)
732 // bceqz $src, SinkBB
733 // FalseBB:
734 // fcmp.cueq.s $dst, $fa0, $fa0 # set $dst 1(true)
735 // SinkBB:
736 // fallthrough
737
738 const BasicBlock *LLVM_BB = MBB.getBasicBlock();
739 auto *FalseBB = MF->CreateMachineBasicBlock(LLVM_BB);
740 auto *SinkBB = MF->CreateMachineBasicBlock(LLVM_BB);
741
742 MF->insert(++MBB.getIterator(), FalseBB);
743 MF->insert(++FalseBB->getIterator(), SinkBB);
744
745 Register DestReg = MI.getOperand(0).getReg();
746 Register SrcReg = MI.getOperand(1).getReg();
747 // DestReg = 0
748 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::SET_CFR_FALSE), DestReg);
749 // Insert branch instruction.
750 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::BCEQZ))
751 .addReg(SrcReg)
752 .addMBB(SinkBB);
753 // DestReg = 1
754 BuildMI(FalseBB, DL, TII->get(LoongArch::SET_CFR_TRUE), DestReg);
755
756 FalseBB->addSuccessor(SinkBB);
757
758 SinkBB->splice(SinkBB->end(), &MBB, MI, MBB.end());
759 SinkBB->transferSuccessors(&MBB);
760
761 MBB.addSuccessor(FalseBB);
762 MBB.addSuccessor(SinkBB);
763
764 NextMBBI = MBB.end();
765 MI.eraseFromParent();
766
767 // Make sure live-ins are correctly attached to this new basic block.
768 LivePhysRegs LiveRegs;
769 computeAndAddLiveIns(LiveRegs, *FalseBB);
770 computeAndAddLiveIns(LiveRegs, *SinkBB);
771
772 return true;
773}
774
775bool LoongArchExpandPseudo::expandFunctionCALL(
777 MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {
779 MachineInstr &MI = *MBBI;
780 DebugLoc DL = MI.getDebugLoc();
781 const MachineOperand &Func = MI.getOperand(0);
783 unsigned Opcode;
784
785 switch (MF->getTarget().getCodeModel()) {
786 default:
787 report_fatal_error("Unexpected code model");
788 break;
789 case CodeModel::Medium: {
790 // CALL:
791 // pcaddu18i $ra, %call36(func)
792 // jirl $ra, $ra, 0
793 // TAIL:
794 // pcaddu18i $t8, %call36(func)
795 // jirl $r0, $t8, 0
796 Opcode =
797 IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
798 Register ScratchReg = IsTailCall ? LoongArch::R20 : LoongArch::R1;
800 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCADDU18I), ScratchReg);
801
802 CALL =
803 BuildMI(MBB, MBBI, DL, TII->get(Opcode)).addReg(ScratchReg).addImm(0);
804
805 if (Func.isSymbol())
806 MIB.addExternalSymbol(Func.getSymbolName(), LoongArchII::MO_CALL36);
807 else
808 MIB.addDisp(Func, 0, LoongArchII::MO_CALL36);
809 break;
810 }
811 }
812
813 // Transfer implicit operands.
814 CALL.copyImplicitOps(MI);
815
816 // Transfer MI flags.
817 CALL.setMIFlags(MI.getFlags());
818
819 MI.eraseFromParent();
820 return true;
821}
822
823} // end namespace
824
825INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "loongarch-prera-expand-pseudo",
827
828INITIALIZE_PASS(LoongArchExpandPseudo, "loongarch-expand-pseudo",
830
831namespace llvm {
832
834 return new LoongArchPreRAExpandPseudo();
835}
837 return new LoongArchExpandPseudo();
838}
839
840} // end namespace llvm
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder MachineInstrBuilder & DefMI
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
static Expected< BitVector > expand(StringRef S, StringRef Original)
Definition: GlobPattern.cpp:21
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
loongarch expand pseudo
#define LOONGARCH_PRERA_EXPAND_PSEUDO_NAME
cl::opt< bool > LArchAnnotateTableJump
#define LOONGARCH_EXPAND_PSEUDO_NAME
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Represent the analysis usage information of a pass.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:256
LLVM Basic Block Representation.
Definition: BasicBlock.h:61
A debug info location.
Definition: DebugLoc.h:33
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
A set of physical registers with utility functions to track liveness when walking backward/forward th...
Definition: LivePhysRegs.h:52
LoongArchMachineFunctionInfo - This class is derived from MachineFunctionInfo and contains private Lo...
MCSymbol * createNamedTempSymbol()
Create a temporary symbol with a unique name whose name cannot be omitted in the symbol table.
Definition: MCContext.cpp:347
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MCContext & getContext() const
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineBasicBlock - Allocate a new MachineBasicBlock.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
const MachineInstrBuilder & addExternalSymbol(const char *FnName, unsigned TargetFlags=0) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addDisp(const MachineOperand &Disp, int64_t off, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
Definition: MachineInstr.h:69
iterator_range< filtered_mop_iterator > all_uses()
Returns an iterator range over all operands that are (explicit or implicit) register uses.
Definition: MachineInstr.h:772
unsigned getNumOperands() const
Retuns the total number of operands.
Definition: MachineInstr.h:578
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:585
void addMemOperand(MachineFunction &MF, MachineMemOperand *MO)
Add a MachineMemOperand to the machine instruction.
MachineOperand class - Representation of each machine instruction operand.
bool isJTI() const
isJTI - Tests if this is a MO_JumpTableIndex operand.
@ MO_ExternalSymbol
Name of external global symbol.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition: Register.h:91
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
CodeModel::Model getCodeModel() const
Returns the code model.
virtual const TargetInstrInfo * getInstrInfo() const
self_iterator getIterator()
Definition: ilist_node.h:132
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
TargetPassConfig.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
static unsigned encodeFlags(unsigned Flags, bool Relax)
@ Kill
The last use of a register.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
void initializeLoongArchPreRAExpandPseudoPass(PassRegistry &)
void initializeLoongArchExpandPseudoPass(PassRegistry &)
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:167
FunctionPass * createLoongArchPreRAExpandPseudoPass()
FunctionPass * createLoongArchExpandPseudoPass()
void computeAndAddLiveIns(LivePhysRegs &LiveRegs, MachineBasicBlock &MBB)
Convenience function combining computeLiveIns() and addLiveIns().