LLVM 24.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) {}
45
46 bool runOnMachineFunction(MachineFunction &MF) override;
47
48 void getAnalysisUsage(AnalysisUsage &AU) const override {
49 AU.setPreservesCFG();
51 }
52 StringRef getPassName() const override {
54 }
55
56private:
60 bool expandPcaxxu12iInstPair(MachineBasicBlock &MBB,
63 unsigned OpcodeHi, unsigned OpcodeLo,
64 unsigned FlagsHi, unsigned FlagsLo);
65 bool expandLargeAddressLoad(MachineBasicBlock &MBB,
68 unsigned LastOpcode, unsigned IdentifyingMO);
69 bool expandLargeAddressLoad(MachineBasicBlock &MBB,
72 unsigned LastOpcode, unsigned IdentifyingMO,
73 const MachineOperand &Symbol, Register DestReg,
74 bool EraseFromParent);
75 bool expandLoadAddressPcrel(MachineBasicBlock &MBB,
78 bool Large = false);
79 bool expandLoadAddressGot(MachineBasicBlock &MBB,
82 bool Large = false);
83 bool expandLoadAddressTLSLE(MachineBasicBlock &MBB,
86 bool expandLoadAddressTLSIE(MachineBasicBlock &MBB,
89 bool Large = false);
90 bool expandLoadAddressTLSLD(MachineBasicBlock &MBB,
93 bool Large = false);
94 bool expandLoadAddressTLSGD(MachineBasicBlock &MBB,
97 bool Large = false);
98 bool expandLoadAddressTLSDesc(MachineBasicBlock &MBB,
101 bool Large = false);
102 bool expandFunctionCALL(MachineBasicBlock &MBB,
105 bool IsTailCall);
106 bool expandMOVCF2GRViaFR(MachineBasicBlock &MBB,
109 void annotateTableJump(MachineBasicBlock &MBB,
111};
112
113char LoongArchPreRAExpandPseudo::ID = 0;
114
115bool LoongArchPreRAExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
116 TII =
117 static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo());
118 bool Modified = false;
119 for (auto &MBB : MF)
121 return Modified;
122}
123
124bool LoongArchPreRAExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
125 bool Modified = false;
126
127 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
128 while (MBBI != E) {
129 MachineBasicBlock::iterator NMBBI = std::next(MBBI);
130 Modified |= expandMI(MBB, MBBI, NMBBI);
131 MBBI = NMBBI;
132 }
133
134 return Modified;
135}
136
137bool LoongArchPreRAExpandPseudo::expandMI(
139 MachineBasicBlock::iterator &NextMBBI) {
140 switch (MBBI->getOpcode()) {
141 case LoongArch::PseudoLA_PCREL:
142 return expandLoadAddressPcrel(MBB, MBBI, NextMBBI);
143 case LoongArch::PseudoLA_PCREL_LARGE:
144 return expandLoadAddressPcrel(MBB, MBBI, NextMBBI, /*Large=*/true);
145 case LoongArch::PseudoLA_GOT:
146 return expandLoadAddressGot(MBB, MBBI, NextMBBI);
147 case LoongArch::PseudoLA_GOT_LARGE:
148 return expandLoadAddressGot(MBB, MBBI, NextMBBI, /*Large=*/true);
149 case LoongArch::PseudoLA_TLS_LE:
150 return expandLoadAddressTLSLE(MBB, MBBI, NextMBBI);
151 case LoongArch::PseudoLA_TLS_IE:
152 return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI);
153 case LoongArch::PseudoLA_TLS_IE_LARGE:
154 return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI, /*Large=*/true);
155 case LoongArch::PseudoLA_TLS_LD:
156 return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI);
157 case LoongArch::PseudoLA_TLS_LD_LARGE:
158 return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI, /*Large=*/true);
159 case LoongArch::PseudoLA_TLS_GD:
160 return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI);
161 case LoongArch::PseudoLA_TLS_GD_LARGE:
162 return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI, /*Large=*/true);
163 case LoongArch::PseudoLA_TLS_DESC:
164 return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI);
165 case LoongArch::PseudoLA_TLS_DESC_LARGE:
166 return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI, /*Large=*/true);
167 case LoongArch::PseudoCALL_SMALL:
168 case LoongArch::PseudoCALL_LARGE:
169 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
170 case LoongArch::PseudoTAIL_SMALL:
171 case LoongArch::PseudoTAIL_LARGE:
172 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
173 case LoongArch::PseudoMOVCF2GRViaFR:
174 return expandMOVCF2GRViaFR(MBB, MBBI, NextMBBI);
175 case LoongArch::PseudoBRIND:
176 // If the PseudoBRIND is used to table jump, then emit a label to annotate
177 // the `jr` instruction, and save the instructions.
179 annotateTableJump(MBB, MBBI);
180 break;
181 }
182 return false;
183}
184
185bool LoongArchPreRAExpandPseudo::expandPcaxxu12iInstPair(
187 MachineBasicBlock::iterator &NextMBBI, unsigned OpcodeHi, unsigned OpcodeLo,
188 unsigned FlagsHi, unsigned FlagsLo) {
189 MachineFunction *MF = MBB.getParent();
190 MachineInstr &MI = *MBBI;
191 DebugLoc DL = MI.getDebugLoc();
192
193 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
194 bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax);
195
196 Register DestReg = MI.getOperand(0).getReg();
197 Register ScratchReg =
198 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
199 MachineOperand &Symbol = MI.getOperand(1);
200
201 MachineInstr *FirstMI =
202 BuildMI(MBB, MBBI, DL, TII->get(OpcodeHi), ScratchReg)
203 .addDisp(Symbol, 0, LoongArchII::encodeFlags(FlagsHi, EnableRelax));
204
205 MachineInstr *SecondMI = nullptr;
206 FlagsLo = LoongArchII::encodeFlags(FlagsLo, EnableRelax);
207
208 if (OpcodeHi == LoongArch::PCALAU12I) {
209 SecondMI = BuildMI(MBB, MBBI, DL, TII->get(OpcodeLo), DestReg)
210 .addReg(ScratchReg)
211 .addDisp(Symbol, 0, FlagsLo);
212 } else {
213 MCSymbol *PCAddSymbol = MF->getContext().createNamedTempSymbol("pcadd_hi");
214 FirstMI->setPreInstrSymbol(*MF, PCAddSymbol);
215 SecondMI = BuildMI(MBB, MBBI, DL, TII->get(OpcodeLo), DestReg)
216 .addReg(ScratchReg)
217 .addSym(PCAddSymbol, FlagsLo);
218 }
219
220 if (MI.hasOneMemOperand())
221 SecondMI->addMemOperand(*MF, *MI.memoperands_begin());
222
223 MI.eraseFromParent();
224 return true;
225}
226
227bool LoongArchPreRAExpandPseudo::expandLargeAddressLoad(
229 MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode,
230 unsigned IdentifyingMO) {
231 MachineInstr &MI = *MBBI;
232 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode, IdentifyingMO,
233 MI.getOperand(2), MI.getOperand(0).getReg(),
234 true);
235}
236
237bool LoongArchPreRAExpandPseudo::expandLargeAddressLoad(
239 MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode,
240 unsigned IdentifyingMO, const MachineOperand &Symbol, Register DestReg,
241 bool EraseFromParent) {
242 // Code Sequence:
243 //
244 // Part1: pcalau12i $scratch, %MO1(sym)
245 // Part0: addi.d $dest, $zero, %MO0(sym)
246 // Part2: lu32i.d $dest, %MO2(sym)
247 // Part3: lu52i.d $dest, $dest, %MO3(sym)
248 // Fin: LastOpcode $dest, $dest, $scratch
249
250 unsigned MO0, MO1, MO2, MO3;
251 switch (IdentifyingMO) {
252 default:
253 llvm_unreachable("unsupported identifying MO");
255 MO0 = IdentifyingMO;
259 break;
263 // These cases relocate just like the GOT case, except for Part1.
265 MO1 = IdentifyingMO;
268 break;
270 MO0 = IdentifyingMO;
274 break;
275 }
276
277 MachineFunction *MF = MBB.getParent();
278 MachineInstr &MI = *MBBI;
279 DebugLoc DL = MI.getDebugLoc();
280
282 "Large code model requires LA64");
283
284 Register TmpPart1 =
285 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
286 Register TmpPart0 =
287 DestReg.isVirtual()
288 ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)
289 : DestReg;
290 Register TmpParts02 =
291 DestReg.isVirtual()
292 ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)
293 : DestReg;
294 Register TmpParts023 =
295 DestReg.isVirtual()
296 ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)
297 : DestReg;
298
299 auto Part1 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), TmpPart1);
300 auto Part0 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADDI_D), TmpPart0)
301 .addReg(LoongArch::R0);
302 auto Part2 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), TmpParts02)
303 // "rj" is needed due to InstrInfo pattern requirement.
304 .addReg(TmpPart0);
305 auto Part3 = BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), TmpParts023)
306 .addReg(TmpParts02);
307 BuildMI(MBB, MBBI, DL, TII->get(LastOpcode), DestReg)
308 .addReg(TmpParts023)
309 .addReg(TmpPart1);
310
311 if (Symbol.getType() == MachineOperand::MO_ExternalSymbol) {
312 const char *SymName = Symbol.getSymbolName();
313 Part0.addExternalSymbol(SymName, MO0);
314 Part1.addExternalSymbol(SymName, MO1);
315 Part2.addExternalSymbol(SymName, MO2);
316 Part3.addExternalSymbol(SymName, MO3);
317 } else {
318 Part0.addDisp(Symbol, 0, MO0);
319 Part1.addDisp(Symbol, 0, MO1);
320 Part2.addDisp(Symbol, 0, MO2);
321 Part3.addDisp(Symbol, 0, MO3);
322 }
323
324 if (EraseFromParent)
325 MI.eraseFromParent();
326
327 return true;
328}
329
330bool LoongArchPreRAExpandPseudo::expandLoadAddressPcrel(
332 MachineBasicBlock::iterator &NextMBBI, bool Large) {
333 if (Large)
334 // Emit the 5-insn large address load sequence with the `%pc` family of
335 // relocs.
336 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,
338
339 // Code Sequence:
340 //
341 // for la32r expands to:
342 // .Lpcadd_hi:
343 // pcaddu12i $rd, %pcadd_hi20(sym)
344 // addi.w $rd, $rd, %pcadd_lo12(.Lpcadd_hi)
345 //
346 // for la32s and la64 expands to:
347 // pcalau12i $rd, %pc_hi20(sym)
348 // addi.w/d $rd, $rd, %pc_lo12(sym)
349 MachineFunction *MF = MBB.getParent();
350 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
351 bool Has32S = STI.hasFeature(LoongArch::Feature32S);
352 unsigned OpcodeHi = Has32S ? LoongArch::PCALAU12I : LoongArch::PCADDU12I;
353 unsigned OpcodeLo = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
354 unsigned FlagsHi =
356 unsigned FlagsLo =
358 return expandPcaxxu12iInstPair(MBB, MBBI, NextMBBI, OpcodeHi, OpcodeLo,
359 FlagsHi, FlagsLo);
360}
361
362bool LoongArchPreRAExpandPseudo::expandLoadAddressGot(
364 MachineBasicBlock::iterator &NextMBBI, bool Large) {
365 if (Large)
366 // Emit the 5-insn large address load sequence with the `%got_pc` family
367 // of relocs, loading the result from GOT with `ldx.d` in the end.
368 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::LDX_D,
370
371 // Code Sequence:
372 //
373 // for la32r expands to:
374 // .Lpcadd_hi:
375 // pcaddu12i $rd, %got_pcadd_hi20(sym)
376 // ld.w $rd, $rd, %got_pcadd_lo12(.Lpcadd_hi)
377 //
378 // for la32s and la64 expands to:
379 // pcalau12i $rd, %got_pc_hi20(sym)
380 // ld.w/d $rd, $rd, %got_pc_lo12(sym)
381 MachineFunction *MF = MBB.getParent();
382 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
383 bool Has32S = STI.hasFeature(LoongArch::Feature32S);
384 unsigned OpcodeHi = Has32S ? LoongArch::PCALAU12I : LoongArch::PCADDU12I;
385 unsigned OpcodeLo = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
386 unsigned FlagsHi =
388 unsigned FlagsLo =
390 return expandPcaxxu12iInstPair(MBB, MBBI, NextMBBI, OpcodeHi, OpcodeLo,
391 FlagsHi, FlagsLo);
392}
393
394bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLE(
396 MachineBasicBlock::iterator &NextMBBI) {
397 // Code Sequence:
398 // lu12i.w $rd, %le_hi20_r(sym)
399 // add.w/d $rd, $rd, $tp, %le_add_r(sym)
400 // addi.w/d $rd, $rd, %le_lo12_r(sym)
401 //
402 // Code Sequence while using the large code model:
403 // lu12i.w $rd, %le_hi20(sym)
404 // ori $rd, $rd, %le_lo12(sym)
405 // lu32i.d $rd, %le64_lo20(sym)
406 // lu52i.d $rd, $rd, %le64_hi12(sym)
407 MachineFunction *MF = MBB.getParent();
408 MachineInstr &MI = *MBBI;
409 DebugLoc DL = MI.getDebugLoc();
410
411 bool Large = MF->getTarget().getCodeModel() == CodeModel::Large;
412 Register DestReg = MI.getOperand(0).getReg();
413 Register Parts01 =
414 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
415 Register Part1 =
416 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
417 MachineOperand &Symbol = MI.getOperand(1);
418
419 if (!Large) {
420 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W), Part1)
421 .addDisp(Symbol, 0, LoongArchII::MO_LE_HI_R);
422
423 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
424 unsigned AddOp = STI.is64Bit() ? LoongArch::PseudoAddTPRel_D
425 : LoongArch::PseudoAddTPRel_W;
426 BuildMI(MBB, MBBI, DL, TII->get(AddOp), Parts01)
427 .addReg(Part1)
428 .addReg(LoongArch::R2)
430
431 unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
432 BuildMI(MBB, MBBI, DL, TII->get(AddiOp), DestReg)
433 .addReg(Parts01)
434 .addDisp(Symbol, 0, LoongArchII::MO_LE_LO_R);
435 } else {
436 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W), Part1)
437 .addDisp(Symbol, 0, LoongArchII::MO_LE_HI);
438
439 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ORI), Parts01)
440 .addReg(Part1)
441 .addDisp(Symbol, 0, LoongArchII::MO_LE_LO);
442
443 Register Parts012 =
444 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
445
446 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), Parts012)
447 // "rj" is needed due to InstrInfo pattern requirement.
448 .addReg(Parts01)
449 .addDisp(Symbol, 0, LoongArchII::MO_LE64_LO);
450 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), DestReg)
451 .addReg(Parts012)
452 .addDisp(Symbol, 0, LoongArchII::MO_LE64_HI);
453 }
454
455 MI.eraseFromParent();
456 return true;
457}
458
459bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSIE(
461 MachineBasicBlock::iterator &NextMBBI, bool Large) {
462 if (Large)
463 // Emit the 5-insn large address load sequence with the `%ie_pc` family
464 // of relocs, loading the result with `ldx.d` in the end.
465 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::LDX_D,
467
468 // Code Sequence:
469 //
470 // for la32r expands to:
471 // .Lpcadd_hi:
472 // pcaddu12i $rd, %ie_pcadd_hi20(sym)
473 // ld.w $rd, $rd, %ie_pcadd_lo12(.Lpcadd_hi)
474 //
475 // for la32s and la64 expands to:
476 // pcalau12i $rd, %ie_pc_hi20(sym)
477 // ld.w/d $rd, $rd, %ie_pc_lo12(sym)
478 MachineFunction *MF = MBB.getParent();
479 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
480 bool Has32S = STI.hasFeature(LoongArch::Feature32S);
481 unsigned OpcodeHi = Has32S ? LoongArch::PCALAU12I : LoongArch::PCADDU12I;
482 unsigned OpcodeLo = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
483 unsigned FlagsHi =
485 unsigned FlagsLo =
487 return expandPcaxxu12iInstPair(MBB, MBBI, NextMBBI, OpcodeHi, OpcodeLo,
488 FlagsHi, FlagsLo);
489}
490
491bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLD(
493 MachineBasicBlock::iterator &NextMBBI, bool Large) {
494 if (Large)
495 // Emit the 5-insn large address load sequence with the `%got_pc` family
496 // of relocs, with the `pcalau12i` insn relocated with `%ld_pc_hi20`.
497 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,
499
500 // Code Sequence:
501 //
502 // for la32r expands to:
503 // .Lpcadd_hi:
504 // pcaddu12i $rd, %ld_pcadd_hi20(sym)
505 // addi.w $rd, $rd, %ld_pcadd_lo12(.Lpcadd_hi)
506 //
507 // for la32s and la64 expands to:
508 // pcalau12i $rd, %ld_pc_hi20(sym)
509 // addi.w/d $rd, $rd, %got_pc_lo12(sym)
510 MachineFunction *MF = MBB.getParent();
511 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
512 bool Has32S = STI.hasFeature(LoongArch::Feature32S);
513 unsigned OpcodeHi = Has32S ? LoongArch::PCALAU12I : LoongArch::PCADDU12I;
514 unsigned OpcodeLo = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
515 unsigned FlagsHi =
517 unsigned FlagsLo =
519 return expandPcaxxu12iInstPair(MBB, MBBI, NextMBBI, OpcodeHi, OpcodeLo,
520 FlagsHi, FlagsLo);
521}
522
523bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSGD(
525 MachineBasicBlock::iterator &NextMBBI, bool Large) {
526 if (Large)
527 // Emit the 5-insn large address load sequence with the `%got_pc` family
528 // of relocs, with the `pcalau12i` insn relocated with `%gd_pc_hi20`.
529 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LoongArch::ADD_D,
531
532 // Code Sequence:
533 //
534 // for la32r expands to:
535 // .Lpcadd_hi:
536 // pcaddu12i $rd, %gd_pcadd_hi20(sym)
537 // addi.w $rd, $rd, %gd_pcadd_lo12(.Lpcadd_hi)
538 //
539 // for la32s and la64 expands to:
540 // pcalau12i $rd, %gd_pc_hi20(sym)
541 // addi.w/d $rd, $rd, %got_pc_lo12(sym)
542 MachineFunction *MF = MBB.getParent();
543 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
544 bool Has32S = STI.hasFeature(LoongArch::Feature32S);
545 unsigned OpcodeHi = Has32S ? LoongArch::PCALAU12I : LoongArch::PCADDU12I;
546 unsigned OpcodeLo = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
547 unsigned FlagsHi =
549 unsigned FlagsLo =
551 return expandPcaxxu12iInstPair(MBB, MBBI, NextMBBI, OpcodeHi, OpcodeLo,
552 FlagsHi, FlagsLo);
553}
554
555bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc(
557 MachineBasicBlock::iterator &NextMBBI, bool Large) {
558 MachineFunction *MF = MBB.getParent();
559 MachineInstr &MI = *MBBI;
560 DebugLoc DL = MI.getDebugLoc();
561
562 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
563 bool Has32S = STI.hasFeature(LoongArch::Feature32S);
564 bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax);
565 unsigned PCA = Has32S ? LoongArch::PCALAU12I : LoongArch::PCADDU12I;
566 unsigned ADD = STI.is64Bit() ? LoongArch::ADD_D : LoongArch::ADD_W;
567 unsigned ADDI = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
568 unsigned LD = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
569 unsigned MO =
571
572 Register DestReg = MI.getOperand(0).getReg();
573 Register Tmp1Reg =
574 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
575 MachineOperand &Symbol = MI.getOperand(Large ? 2 : 1);
576
577 MachineInstr *PCAMI =
578 BuildMI(MBB, MBBI, DL, TII->get(PCA), Tmp1Reg)
579 .addDisp(Symbol, 0,
580 LoongArchII::encodeFlags(MO, EnableRelax && !Large));
581
582 if (Large) {
583 // Code Sequence:
584 //
585 // pcalau12i $a0, %desc_pc_hi20(sym)
586 // addi.d $a1, $zero, %desc_pc_lo12(sym)
587 // lu32i.d $a1, %desc64_pc_lo20(sym)
588 // lu52i.d $a1, $a1, %desc64_pc_hi12(sym)
589 // add.d $a0, $a0, $a1
590 // ld.d $ra, $a0, %desc_ld(sym)
591 // jirl $ra, $ra, %desc_call(sym)
592 // add.d $dst, $a0, $tp
593 assert(MBB.getParent()->getSubtarget<LoongArchSubtarget>().is64Bit() &&
594 "Large code model requires LA64");
595 Register Tmp2Reg =
596 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
597 Register Tmp3Reg =
598 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
599 Register Tmp4Reg =
600 MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
601 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADDI_D), Tmp2Reg)
602 .addReg(LoongArch::R0)
604 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), Tmp3Reg)
605 .addReg(Tmp2Reg)
607 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), Tmp4Reg)
608 .addReg(Tmp3Reg)
610 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADD_D), LoongArch::R4)
611 .addReg(Tmp1Reg)
612 .addReg(Tmp4Reg);
613 } else {
614 // Code Sequence:
615 //
616 // for la32r expands to:
617 // .Lpcadd_hi:
618 // pcaddu12i $a0, %desc_pcadd_hi20(sym)
619 // addi.w $a0, $a0, %desc_pcadd_lo12(.Lpcadd_hi)
620 // ld.w $ra, $a0, %desc_ld(sym)
621 // jirl $ra, $ra, %desc_call(sym)
622 // add.w $dst, $a0, $tp
623 //
624 // for la32s and la64 expands to:
625 // pcalau12i $a0, %desc_pc_hi20(sym)
626 // addi.w/d $a0, $a0, %desc_pc_lo12(sym)
627 // ld.w/d $ra, $a0, %desc_ld(sym)
628 // jirl $ra, $ra, %desc_call(sym)
629 // add.w/d $dst, $a0, $tp
630 if (Has32S) {
631 BuildMI(MBB, MBBI, DL, TII->get(ADDI), LoongArch::R4)
632 .addReg(Tmp1Reg)
633 .addDisp(Symbol, 0,
635 EnableRelax));
636 } else {
637 MCSymbol *PCASymbol = MF->getContext().createNamedTempSymbol("pcadd_hi");
638 PCAMI->setPreInstrSymbol(*MF, PCASymbol);
639 BuildMI(MBB, MBBI, DL, TII->get(ADDI), LoongArch::R4)
640 .addReg(Tmp1Reg)
642 LoongArchII::MO_DESC_PCADD_LO, EnableRelax));
643 }
644 }
645
646 BuildMI(MBB, MBBI, DL, TII->get(LD), LoongArch::R1)
647 .addReg(LoongArch::R4)
648 .addDisp(Symbol, 0,
650 EnableRelax && !Large));
651 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PseudoDESC_CALL), LoongArch::R1)
652 .addReg(LoongArch::R1)
653 .addDisp(Symbol, 0,
655 EnableRelax && !Large))
656 .setOperandDead(0); // $r1
657 BuildMI(MBB, MBBI, DL, TII->get(ADD), DestReg)
658 .addReg(LoongArch::R4)
659 .addReg(LoongArch::R2);
660
661 MI.eraseFromParent();
662 return true;
663}
664
665bool LoongArchPreRAExpandPseudo::expandFunctionCALL(
667 MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {
668 MachineFunction *MF = MBB.getParent();
669 MachineInstr &MI = *MBBI;
670
671 switch (MF->getTarget().getCodeModel()) {
672 default:
673 report_fatal_error("Unexpected code model");
674 break;
675 case CodeModel::Small: {
676 // CALL:
677 // bl func
678 // TAIL:
679 // b func
680 unsigned Opcode = IsTailCall ? LoongArch::PseudoB_TAIL : LoongArch::BL;
681 MI.setDesc(TII->get(Opcode));
682 return true;
683 }
684 case CodeModel::Large: {
685 // Emit the 5-insn large address load sequence, either directly or
686 // indirectly in case of going through the GOT, then JIRL_TAIL or
687 // JIRL_CALL to $addr.
688 const MachineOperand &Func = MI.getOperand(0);
689 unsigned Opcode =
690 IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
691 Register AddrReg =
692 IsTailCall
693 ? MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass)
694 : LoongArch::R1;
695
696 bool UseGOT = Func.getTargetFlags() == LoongArchII::MO_CALL_PLT;
698 unsigned LAOpcode = UseGOT ? LoongArch::LDX_D : LoongArch::ADD_D;
699 expandLargeAddressLoad(MBB, MBBI, NextMBBI, LAOpcode, MO, Func, AddrReg,
700 false);
701
702 // Mutate the pseudo into the JIRL in place, keeping its implicit operands.
703 // Operand 0 becomes the address register; operand 1 is the jump offset.
704 MI.setDesc(TII->get(Opcode));
705 MI.getOperand(0).ChangeToRegister(AddrReg, /*isDef=*/false);
706 MI.insert(std::next(MI.operands_begin()), MachineOperand::CreateImm(0));
707 return true;
708 }
709 }
710 llvm_unreachable("Unexpected code model");
711}
712
713void LoongArchPreRAExpandPseudo::annotateTableJump(
715 MachineFunction *MF = MBB.getParent();
716 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
717
718 bool IsFound = false;
719
720 std::function<void(MachineInstr *, int)> FindJTIMI = [&](MachineInstr *MInst,
721 int FindDepth) {
722 if (FindDepth < 0)
723 return;
724 for (auto &MO : MInst->all_uses()) {
725 if (IsFound)
726 return;
727 Register Reg = MO.getReg();
728 if (!Reg.isVirtual())
729 continue;
730 MachineInstr *DefMI = MRI.getVRegDef(Reg);
731 if (!DefMI)
732 continue;
733 for (unsigned Idx = 0; Idx < DefMI->getNumOperands(); ++Idx) {
734 MachineOperand &MO = DefMI->getOperand(Idx);
735 if (MO.isJTI()) {
736 MBBI->setPreInstrSymbol(
737 *MF, MF->getContext().createNamedTempSymbol("jrtb_"));
738 MF->getInfo<LoongArchMachineFunctionInfo>()->setJumpInfo(
739 &*MBBI, MO.getIndex());
740 IsFound = true;
741 return;
742 }
743 }
744 FindJTIMI(DefMI, --FindDepth);
745 }
746 };
747
748 // FindDepth = 4, probably sufficient.
749 FindJTIMI(&*MBBI, /*FindDepth=*/4);
750}
751
752class LoongArchExpandPseudo : public MachineFunctionPass {
753public:
754 const LoongArchInstrInfo *TII;
755 static char ID;
756
757 LoongArchExpandPseudo() : MachineFunctionPass(ID) {}
758
759 bool runOnMachineFunction(MachineFunction &MF) override;
760
761 StringRef getPassName() const override {
763 }
764
765private:
771 bool expandFunctionCALL(MachineBasicBlock &MBB,
774 bool IsTailCall);
775 bool expandAddUpperImm(MachineBasicBlock &MBB,
777};
778
779char LoongArchExpandPseudo::ID = 0;
780
781bool LoongArchExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
782 TII =
783 static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo());
784
785 bool Modified = false;
786 for (auto &MBB : MF)
788
789 return Modified;
790}
791
792bool LoongArchExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
793 bool Modified = false;
794
795 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
796 while (MBBI != E) {
797 MachineBasicBlock::iterator NMBBI = std::next(MBBI);
798 Modified |= expandMI(MBB, MBBI, NMBBI);
799 MBBI = NMBBI;
800 }
801
802 return Modified;
803}
804
805bool LoongArchExpandPseudo::expandMI(MachineBasicBlock &MBB,
807 MachineBasicBlock::iterator &NextMBBI) {
808 switch (MBBI->getOpcode()) {
809 case LoongArch::PseudoCopyCFR:
810 return expandCopyCFR(MBB, MBBI, NextMBBI);
811 case LoongArch::PseudoCALL_MEDIUM:
812 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
813 case LoongArch::PseudoTAIL_MEDIUM:
814 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
815 case LoongArch::PseudoAddUpperImm:
816 return expandAddUpperImm(MBB, MBBI);
817 }
818
819 return false;
820}
821
822bool LoongArchExpandPseudo::expandCopyCFR(
824 MachineBasicBlock::iterator &NextMBBI) {
825 MachineFunction *MF = MBB.getParent();
826 MachineInstr &MI = *MBBI;
827 DebugLoc DL = MI.getDebugLoc();
828
829 // Expand:
830 // MBB:
831 // fcmp.caf.s $dst, $fa0, $fa0 # set $dst 0(false)
832 // bceqz $src, SinkBB
833 // FalseBB:
834 // fcmp.cueq.s $dst, $fa0, $fa0 # set $dst 1(true)
835 // SinkBB:
836 // fallthrough
837
838 const BasicBlock *LLVM_BB = MBB.getBasicBlock();
839 auto *FalseBB = MF->CreateMachineBasicBlock(LLVM_BB);
840 auto *SinkBB = MF->CreateMachineBasicBlock(LLVM_BB);
841
842 MF->insert(++MBB.getIterator(), FalseBB);
843 MF->insert(++FalseBB->getIterator(), SinkBB);
844
845 Register DestReg = MI.getOperand(0).getReg();
846 Register SrcReg = MI.getOperand(1).getReg();
847 // DestReg = 0
848 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::SET_CFR_FALSE), DestReg);
849 // Insert branch instruction.
850 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::BCEQZ))
851 .addReg(SrcReg)
852 .addMBB(SinkBB);
853 // DestReg = 1
854 BuildMI(FalseBB, DL, TII->get(LoongArch::SET_CFR_TRUE), DestReg);
855
856 FalseBB->addSuccessor(SinkBB);
857
858 SinkBB->splice(SinkBB->end(), &MBB, MI, MBB.end());
859 SinkBB->transferSuccessors(&MBB);
860
861 MBB.addSuccessor(FalseBB);
862 MBB.addSuccessor(SinkBB);
863
864 NextMBBI = MBB.end();
865 MI.eraseFromParent();
866
867 // Make sure live-ins are correctly attached to this new basic block.
871
872 return true;
873}
874
875bool LoongArchExpandPseudo::expandFunctionCALL(
877 MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {
878 MachineFunction *MF = MBB.getParent();
879 MachineInstr &MI = *MBBI;
880 DebugLoc DL = MI.getDebugLoc();
881 const MachineOperand &Func = MI.getOperand(0);
882
883 switch (MF->getTarget().getCodeModel()) {
884 default:
885 report_fatal_error("Unexpected code model");
886 break;
887 case CodeModel::Medium: {
888 // for la32 expands to:
889 // CALL:
890 // pcaddu12i $ra, %call30(func)
891 // jirl $ra, $ra, 0
892 // TAIL:
893 // pcaddu12i $t8, %call30(func)
894 // jirl $r0, $t8, 0
895 //
896 // for la64 expands to:
897 // CALL:
898 // pcaddu18i $ra, %call36(func)
899 // jirl $ra, $ra, 0
900 // TAIL:
901 // pcaddu18i $t8, %call36(func)
902 // jirl $r0, $t8, 0
903 unsigned Opcode =
904 IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
905 Register ScratchReg = IsTailCall ? LoongArch::R20 : LoongArch::R1;
906 bool Is64Bit = MF->getSubtarget<LoongArchSubtarget>().is64Bit();
907 unsigned PC = Is64Bit ? LoongArch::PCADDU18I : LoongArch::PCADDU12I;
908 unsigned MO = Is64Bit ? LoongArchII::MO_CALL36 : LoongArchII::MO_CALL30;
909 MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(PC), ScratchReg);
910
911 if (Func.isSymbol())
912 MIB.addExternalSymbol(Func.getSymbolName(), MO);
913 else
914 MIB.addDisp(Func, 0, MO);
915
916 // Mutate the pseudo into the JIRL in place, keeping its implicit operands.
917 // Operand 0 becomes the address register; operand 1 is the jump offset.
918 MI.setDesc(TII->get(Opcode));
919 MI.getOperand(0).ChangeToRegister(ScratchReg, /*isDef=*/false);
920 MI.insert(std::next(MI.operands_begin()), MachineOperand::CreateImm(0));
921 return true;
922 }
923 }
924 llvm_unreachable("Unexpected code model");
925}
926
927bool LoongArchExpandPseudo::expandAddUpperImm(
929 DebugLoc DL = MBBI->getDebugLoc();
930 MachineFunction *MF = MBB.getParent();
931 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
932
933 Register DstReg = MBBI->getOperand(0).getReg();
934 bool DstIsDead = MBBI->getOperand(0).isDead();
935 bool Renamable = MBBI->getOperand(0).isRenamable();
936 Register BaseReg = MBBI->getOperand(1).getReg();
937 int64_t Hi = MBBI->getOperand(2).getImm();
938 bool IsLA64 = STI.is64Bit();
939
940 // Expand to LU12I_W + ADD_W/D: the immediate is upper 20-bit.
941 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W))
943 .addImm(Hi);
944 BuildMI(MBB, MBBI, DL, TII->get(IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W))
945 .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead) |
947 .addReg(BaseReg)
949
950 MBBI->eraseFromParent();
951 return true;
952}
953
954bool LoongArchPreRAExpandPseudo::expandMOVCF2GRViaFR(
956 MachineBasicBlock::iterator &NextMBBI) {
957 MachineFunction *MF = MBB.getParent();
958 MachineInstr &MI = *MBBI;
959 DebugLoc DL = MI.getDebugLoc();
960
961 Register TmpReg =
962 MF->getRegInfo().createVirtualRegister(&LoongArch::FPR32RegClass);
963 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::MOVCF2FR_xS), TmpReg)
964 .addReg(MI.getOperand(1).getReg());
965 BuildMI(MBB, MBBI, DL, TII->get(LoongArch::MOVFR2GR_S),
966 MI.getOperand(0).getReg())
967 .addReg(TmpReg);
968 MI.eraseFromParent();
969 return true;
970}
971
972} // end namespace
973
974INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "loongarch-prera-expand-pseudo",
976
977INITIALIZE_PASS(LoongArchExpandPseudo, "loongarch-expand-pseudo",
979
980namespace llvm {
981
983 return new LoongArchPreRAExpandPseudo();
984}
986 return new LoongArchExpandPseudo();
987}
988
989} // end namespace llvm
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
cl::opt< bool > LArchAnnotateTableJump("loongarch-annotate-tablejump", cl::Hidden, cl::desc("Annotate table jump instruction to correlate it with the jump table."), cl::init(false))
#define LOONGARCH_PRERA_EXPAND_PSEUDO_NAME
#define LOONGARCH_EXPAND_PSEUDO_NAME
Register Reg
static bool expandMBB(MachineBasicBlock &MBB, const MipsSubtarget *STI, const MipsInstrInfo *TII)
static bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NMBB, const MipsSubtarget *STI, const MipsInstrInfo *TII)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
MachineRegisterInfo & MRI
static bool is64Bit(const char *name)
Represent the analysis usage information of a pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:280
LLVM Basic Block Representation.
Definition BasicBlock.h:62
A debug info location.
Definition DebugLoc.h:126
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
A set of physical registers with utility functions to track liveness when walking backward/forward th...
LoongArchMachineFunctionInfo - This class is derived from MachineFunctionInfo and contains private Lo...
LLVM_ABI MCSymbol * createNamedTempSymbol()
Create a temporary symbol with a unique name whose name cannot be omitted in the symbol table.
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
MachineInstrBundleIterator< MachineInstr > iterator
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.
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)
CreateMachineInstr - Allocate a new MachineInstr.
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 & setOperandDead(unsigned OpIdx) const
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addDisp(const MachineOperand &Disp, int64_t off, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
LLVM_ABI void setPreInstrSymbol(MachineFunction &MF, MCSymbol *Symbol)
Set a symbol that will be emitted just prior to the instruction itself.
filtered_mop_range all_uses()
Returns an iterator range over all operands that are (explicit or implicit) register uses.
LLVM_ABI 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.
static MachineOperand CreateImm(int64_t Val)
@ MO_ExternalSymbol
Name of external global symbol.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
CodeModel::Model getCodeModel() const
Returns the code model.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
TargetPassConfig.
static unsigned encodeFlags(unsigned Flags, bool Relax)
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
@ Kill
The last use of a register.
@ Define
Register definition.
@ Renamable
Register that may be renamed.
constexpr RegState getDeadRegState(bool B)
constexpr RegState getRenamableRegState(bool B)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
FunctionPass * createLoongArchPreRAExpandPseudoPass()
FunctionPass * createLoongArchExpandPseudoPass()
LLVM_ABI void computeAndAddLiveIns(LivePhysRegs &LiveRegs, MachineBasicBlock &MBB)
Convenience function combining computeLiveIns() and addLiveIns().