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 "LoongArchMachineFunctionInfo.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
30extern cl::opt<bool> LArchAnnotateTableJump;
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:
41 const LoongArchInstrInfo *TII;
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();
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 expandPcaxxu12iInstPair(MachineBasicBlock &MBB,
61 MachineBasicBlock::iterator MBBI,
62 MachineBasicBlock::iterator &NextMBBI,
63 unsigned OpcodeHi, unsigned OpcodeLo,
64 unsigned FlagsHi, unsigned FlagsLo);
65 bool expandLargeAddressLoad(MachineBasicBlock &MBB,
66 MachineBasicBlock::iterator MBBI,
67 MachineBasicBlock::iterator &NextMBBI,
68 unsigned LastOpcode, unsigned IdentifyingMO);
69 bool expandLargeAddressLoad(MachineBasicBlock &MBB,
70 MachineBasicBlock::iterator MBBI,
71 MachineBasicBlock::iterator &NextMBBI,
72 unsigned LastOpcode, unsigned IdentifyingMO,
73 const MachineOperand &Symbol, Register DestReg,
74 bool EraseFromParent);
75 bool expandLoadAddressPcrel(MachineBasicBlock &MBB,
76 MachineBasicBlock::iterator MBBI,
77 MachineBasicBlock::iterator &NextMBBI,
78 bool Large = false);
79 bool expandLoadAddressGot(MachineBasicBlock &MBB,
80 MachineBasicBlock::iterator MBBI,
81 MachineBasicBlock::iterator &NextMBBI,
82 bool Large = false);
83 bool expandLoadAddressTLSLE(MachineBasicBlock &MBB,
84 MachineBasicBlock::iterator MBBI,
85 MachineBasicBlock::iterator &NextMBBI);
86 bool expandLoadAddressTLSIE(MachineBasicBlock &MBB,
87 MachineBasicBlock::iterator MBBI,
88 MachineBasicBlock::iterator &NextMBBI,
89 bool Large = false);
90 bool expandLoadAddressTLSLD(MachineBasicBlock &MBB,
91 MachineBasicBlock::iterator MBBI,
92 MachineBasicBlock::iterator &NextMBBI,
93 bool Large = false);
94 bool expandLoadAddressTLSGD(MachineBasicBlock &MBB,
95 MachineBasicBlock::iterator MBBI,
96 MachineBasicBlock::iterator &NextMBBI,
97 bool Large = false);
98 bool expandLoadAddressTLSDesc(MachineBasicBlock &MBB,
99 MachineBasicBlock::iterator MBBI,
100 MachineBasicBlock::iterator &NextMBBI,
101 bool Large = false);
102 bool expandFunctionCALL(MachineBasicBlock &MBB,
103 MachineBasicBlock::iterator MBBI,
104 MachineBasicBlock::iterator &NextMBBI,
105 bool IsTailCall);
106 void annotateTableJump(MachineBasicBlock &MBB,
107 MachineBasicBlock::iterator MBBI);
108};
109
110char LoongArchPreRAExpandPseudo::ID = 0;
111
112bool LoongArchPreRAExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
113 TII =
114 static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo());
115 bool Modified = false;
116 for (auto &MBB : MF)
117 Modified |= expandMBB(MBB);
118 return Modified;
119}
120
121bool LoongArchPreRAExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
122 bool Modified = false;
123
124 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
125 while (MBBI != E) {
126 MachineBasicBlock::iterator NMBBI = std::next(x: MBBI);
127 Modified |= expandMI(MBB, MBBI, NextMBBI&: NMBBI);
128 MBBI = NMBBI;
129 }
130
131 return Modified;
132}
133
134bool LoongArchPreRAExpandPseudo::expandMI(
135 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
136 MachineBasicBlock::iterator &NextMBBI) {
137 switch (MBBI->getOpcode()) {
138 case LoongArch::PseudoLA_PCREL:
139 return expandLoadAddressPcrel(MBB, MBBI, NextMBBI);
140 case LoongArch::PseudoLA_PCREL_LARGE:
141 return expandLoadAddressPcrel(MBB, MBBI, NextMBBI, /*Large=*/true);
142 case LoongArch::PseudoLA_GOT:
143 return expandLoadAddressGot(MBB, MBBI, NextMBBI);
144 case LoongArch::PseudoLA_GOT_LARGE:
145 return expandLoadAddressGot(MBB, MBBI, NextMBBI, /*Large=*/true);
146 case LoongArch::PseudoLA_TLS_LE:
147 return expandLoadAddressTLSLE(MBB, MBBI, NextMBBI);
148 case LoongArch::PseudoLA_TLS_IE:
149 return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI);
150 case LoongArch::PseudoLA_TLS_IE_LARGE:
151 return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI, /*Large=*/true);
152 case LoongArch::PseudoLA_TLS_LD:
153 return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI);
154 case LoongArch::PseudoLA_TLS_LD_LARGE:
155 return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI, /*Large=*/true);
156 case LoongArch::PseudoLA_TLS_GD:
157 return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI);
158 case LoongArch::PseudoLA_TLS_GD_LARGE:
159 return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI, /*Large=*/true);
160 case LoongArch::PseudoLA_TLS_DESC:
161 return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI);
162 case LoongArch::PseudoLA_TLS_DESC_LARGE:
163 return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI, /*Large=*/true);
164 case LoongArch::PseudoCALL_SMALL:
165 case LoongArch::PseudoCALL_LARGE:
166 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
167 case LoongArch::PseudoTAIL_SMALL:
168 case LoongArch::PseudoTAIL_LARGE:
169 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
170 case LoongArch::PseudoBRIND:
171 // If the PseudoBRIND is used to table jump, then emit a label to annotate
172 // the `jr` instruction, and save the instructions.
173 if (LArchAnnotateTableJump)
174 annotateTableJump(MBB, MBBI);
175 break;
176 }
177 return false;
178}
179
180bool LoongArchPreRAExpandPseudo::expandPcaxxu12iInstPair(
181 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
182 MachineBasicBlock::iterator &NextMBBI, unsigned OpcodeHi, unsigned OpcodeLo,
183 unsigned FlagsHi, unsigned FlagsLo) {
184 MachineFunction *MF = MBB.getParent();
185 MachineInstr &MI = *MBBI;
186 DebugLoc DL = MI.getDebugLoc();
187
188 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
189 bool EnableRelax = STI.hasFeature(Feature: LoongArch::FeatureRelax);
190
191 Register DestReg = MI.getOperand(i: 0).getReg();
192 Register ScratchReg =
193 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
194 MachineOperand &Symbol = MI.getOperand(i: 1);
195
196 MachineInstr *FirstMI =
197 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: OpcodeHi), DestReg: ScratchReg)
198 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::encodeFlags(Flags: FlagsHi, Relax: EnableRelax));
199
200 MachineInstr *SecondMI = nullptr;
201 FlagsLo = LoongArchII::encodeFlags(Flags: FlagsLo, Relax: EnableRelax);
202
203 if (OpcodeHi == LoongArch::PCALAU12I) {
204 SecondMI = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: OpcodeLo), DestReg)
205 .addReg(RegNo: ScratchReg)
206 .addDisp(Disp: Symbol, off: 0, TargetFlags: FlagsLo);
207 } else {
208 MCSymbol *PCAddSymbol = MF->getContext().createNamedTempSymbol(Name: "pcadd_hi");
209 FirstMI->setPreInstrSymbol(MF&: *MF, Symbol: PCAddSymbol);
210 SecondMI = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: OpcodeLo), DestReg)
211 .addReg(RegNo: ScratchReg)
212 .addSym(Sym: PCAddSymbol, TargetFlags: FlagsLo);
213 }
214
215 if (MI.hasOneMemOperand())
216 SecondMI->addMemOperand(MF&: *MF, MO: *MI.memoperands_begin());
217
218 MI.eraseFromParent();
219 return true;
220}
221
222bool LoongArchPreRAExpandPseudo::expandLargeAddressLoad(
223 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
224 MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode,
225 unsigned IdentifyingMO) {
226 MachineInstr &MI = *MBBI;
227 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode, IdentifyingMO,
228 Symbol: MI.getOperand(i: 2), DestReg: MI.getOperand(i: 0).getReg(),
229 EraseFromParent: true);
230}
231
232bool LoongArchPreRAExpandPseudo::expandLargeAddressLoad(
233 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
234 MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode,
235 unsigned IdentifyingMO, const MachineOperand &Symbol, Register DestReg,
236 bool EraseFromParent) {
237 // Code Sequence:
238 //
239 // Part1: pcalau12i $scratch, %MO1(sym)
240 // Part0: addi.d $dest, $zero, %MO0(sym)
241 // Part2: lu32i.d $dest, %MO2(sym)
242 // Part3: lu52i.d $dest, $dest, %MO3(sym)
243 // Fin: LastOpcode $dest, $dest, $scratch
244
245 unsigned MO0, MO1, MO2, MO3;
246 switch (IdentifyingMO) {
247 default:
248 llvm_unreachable("unsupported identifying MO");
249 case LoongArchII::MO_PCREL_LO:
250 MO0 = IdentifyingMO;
251 MO1 = LoongArchII::MO_PCREL_HI;
252 MO2 = LoongArchII::MO_PCREL64_LO;
253 MO3 = LoongArchII::MO_PCREL64_HI;
254 break;
255 case LoongArchII::MO_GOT_PC_HI:
256 case LoongArchII::MO_LD_PC_HI:
257 case LoongArchII::MO_GD_PC_HI:
258 // These cases relocate just like the GOT case, except for Part1.
259 MO0 = LoongArchII::MO_GOT_PC_LO;
260 MO1 = IdentifyingMO;
261 MO2 = LoongArchII::MO_GOT_PC64_LO;
262 MO3 = LoongArchII::MO_GOT_PC64_HI;
263 break;
264 case LoongArchII::MO_IE_PC_LO:
265 MO0 = IdentifyingMO;
266 MO1 = LoongArchII::MO_IE_PC_HI;
267 MO2 = LoongArchII::MO_IE_PC64_LO;
268 MO3 = LoongArchII::MO_IE_PC64_HI;
269 break;
270 }
271
272 MachineFunction *MF = MBB.getParent();
273 MachineInstr &MI = *MBBI;
274 DebugLoc DL = MI.getDebugLoc();
275
276 assert(MF->getSubtarget<LoongArchSubtarget>().is64Bit() &&
277 "Large code model requires LA64");
278
279 Register TmpPart1 =
280 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
281 Register TmpPart0 =
282 DestReg.isVirtual()
283 ? MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass)
284 : DestReg;
285 Register TmpParts02 =
286 DestReg.isVirtual()
287 ? MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass)
288 : DestReg;
289 Register TmpParts023 =
290 DestReg.isVirtual()
291 ? MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass)
292 : DestReg;
293
294 auto Part1 = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::PCALAU12I), DestReg: TmpPart1);
295 auto Part0 = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::ADDI_D), DestReg: TmpPart0)
296 .addReg(RegNo: LoongArch::R0);
297 auto Part2 = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU32I_D), DestReg: TmpParts02)
298 // "rj" is needed due to InstrInfo pattern requirement.
299 .addReg(RegNo: TmpPart0, Flags: RegState::Kill);
300 auto Part3 = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU52I_D), DestReg: TmpParts023)
301 .addReg(RegNo: TmpParts02, Flags: RegState::Kill);
302 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LastOpcode), DestReg)
303 .addReg(RegNo: TmpParts023)
304 .addReg(RegNo: TmpPart1, Flags: RegState::Kill);
305
306 if (Symbol.getType() == MachineOperand::MO_ExternalSymbol) {
307 const char *SymName = Symbol.getSymbolName();
308 Part0.addExternalSymbol(FnName: SymName, TargetFlags: MO0);
309 Part1.addExternalSymbol(FnName: SymName, TargetFlags: MO1);
310 Part2.addExternalSymbol(FnName: SymName, TargetFlags: MO2);
311 Part3.addExternalSymbol(FnName: SymName, TargetFlags: MO3);
312 } else {
313 Part0.addDisp(Disp: Symbol, off: 0, TargetFlags: MO0);
314 Part1.addDisp(Disp: Symbol, off: 0, TargetFlags: MO1);
315 Part2.addDisp(Disp: Symbol, off: 0, TargetFlags: MO2);
316 Part3.addDisp(Disp: Symbol, off: 0, TargetFlags: MO3);
317 }
318
319 if (EraseFromParent)
320 MI.eraseFromParent();
321
322 return true;
323}
324
325bool LoongArchPreRAExpandPseudo::expandLoadAddressPcrel(
326 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
327 MachineBasicBlock::iterator &NextMBBI, bool Large) {
328 if (Large)
329 // Emit the 5-insn large address load sequence with the `%pc` family of
330 // relocs.
331 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode: LoongArch::ADD_D,
332 IdentifyingMO: LoongArchII::MO_PCREL_LO);
333
334 // Code Sequence:
335 //
336 // for la32r expands to:
337 // .Lpcadd_hi:
338 // pcaddu12i $rd, %pcadd_hi20(sym)
339 // addi.w $rd, $rd, %pcadd_lo12(.Lpcadd_hi)
340 //
341 // for la32s and la64 expands to:
342 // pcalau12i $rd, %pc_hi20(sym)
343 // addi.w/d $rd, $rd, %pc_lo12(sym)
344 MachineFunction *MF = MBB.getParent();
345 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
346 bool Has32S = STI.hasFeature(Feature: LoongArch::Feature32S);
347 unsigned OpcodeHi = Has32S ? LoongArch::PCALAU12I : LoongArch::PCADDU12I;
348 unsigned OpcodeLo = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
349 unsigned FlagsHi =
350 Has32S ? LoongArchII::MO_PCREL_HI : LoongArchII::MO_PCADD_HI;
351 unsigned FlagsLo =
352 Has32S ? LoongArchII::MO_PCREL_LO : LoongArchII::MO_PCADD_LO;
353 return expandPcaxxu12iInstPair(MBB, MBBI, NextMBBI, OpcodeHi, OpcodeLo,
354 FlagsHi, FlagsLo);
355}
356
357bool LoongArchPreRAExpandPseudo::expandLoadAddressGot(
358 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
359 MachineBasicBlock::iterator &NextMBBI, bool Large) {
360 if (Large)
361 // Emit the 5-insn large address load sequence with the `%got_pc` family
362 // of relocs, loading the result from GOT with `ldx.d` in the end.
363 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode: LoongArch::LDX_D,
364 IdentifyingMO: LoongArchII::MO_GOT_PC_HI);
365
366 // Code Sequence:
367 //
368 // for la32r expands to:
369 // .Lpcadd_hi:
370 // pcaddu12i $rd, %got_pcadd_hi20(sym)
371 // ld.w $rd, $rd, %got_pcadd_lo12(.Lpcadd_hi)
372 //
373 // for la32s and la64 expands to:
374 // pcalau12i $rd, %got_pc_hi20(sym)
375 // ld.w/d $rd, $rd, %got_pc_lo12(sym)
376 MachineFunction *MF = MBB.getParent();
377 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
378 bool Has32S = STI.hasFeature(Feature: LoongArch::Feature32S);
379 unsigned OpcodeHi = Has32S ? LoongArch::PCALAU12I : LoongArch::PCADDU12I;
380 unsigned OpcodeLo = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
381 unsigned FlagsHi =
382 Has32S ? LoongArchII::MO_GOT_PC_HI : LoongArchII::MO_GOT_PCADD_HI;
383 unsigned FlagsLo =
384 Has32S ? LoongArchII::MO_GOT_PC_LO : LoongArchII::MO_GOT_PCADD_LO;
385 return expandPcaxxu12iInstPair(MBB, MBBI, NextMBBI, OpcodeHi, OpcodeLo,
386 FlagsHi, FlagsLo);
387}
388
389bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLE(
390 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
391 MachineBasicBlock::iterator &NextMBBI) {
392 // Code Sequence:
393 // lu12i.w $rd, %le_hi20_r(sym)
394 // add.w/d $rd, $rd, $tp, %le_add_r(sym)
395 // addi.w/d $rd, $rd, %le_lo12_r(sym)
396 //
397 // Code Sequence while using the large code model:
398 // lu12i.w $rd, %le_hi20(sym)
399 // ori $rd, $rd, %le_lo12(sym)
400 // lu32i.d $rd, %le64_lo20(sym)
401 // lu52i.d $rd, $rd, %le64_hi12(sym)
402 MachineFunction *MF = MBB.getParent();
403 MachineInstr &MI = *MBBI;
404 DebugLoc DL = MI.getDebugLoc();
405
406 bool Large = MF->getTarget().getCodeModel() == CodeModel::Large;
407 Register DestReg = MI.getOperand(i: 0).getReg();
408 Register Parts01 =
409 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
410 Register Part1 =
411 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
412 MachineOperand &Symbol = MI.getOperand(i: 1);
413
414 if (!Large) {
415 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU12I_W), DestReg: Part1)
416 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_LE_HI_R);
417
418 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
419 unsigned AddOp = STI.is64Bit() ? LoongArch::PseudoAddTPRel_D
420 : LoongArch::PseudoAddTPRel_W;
421 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: AddOp), DestReg: Parts01)
422 .addReg(RegNo: Part1, Flags: RegState::Kill)
423 .addReg(RegNo: LoongArch::R2)
424 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_LE_ADD_R);
425
426 unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
427 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: AddiOp), DestReg)
428 .addReg(RegNo: Parts01, Flags: RegState::Kill)
429 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_LE_LO_R);
430 } else {
431 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU12I_W), DestReg: Part1)
432 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_LE_HI);
433
434 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::ORI), DestReg: Parts01)
435 .addReg(RegNo: Part1, Flags: RegState::Kill)
436 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_LE_LO);
437
438 Register Parts012 =
439 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
440
441 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU32I_D), DestReg: Parts012)
442 // "rj" is needed due to InstrInfo pattern requirement.
443 .addReg(RegNo: Parts01, Flags: RegState::Kill)
444 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_LE64_LO);
445 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU52I_D), DestReg)
446 .addReg(RegNo: Parts012, Flags: RegState::Kill)
447 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_LE64_HI);
448 }
449
450 MI.eraseFromParent();
451 return true;
452}
453
454bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSIE(
455 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
456 MachineBasicBlock::iterator &NextMBBI, bool Large) {
457 if (Large)
458 // Emit the 5-insn large address load sequence with the `%ie_pc` family
459 // of relocs, loading the result with `ldx.d` in the end.
460 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode: LoongArch::LDX_D,
461 IdentifyingMO: LoongArchII::MO_IE_PC_LO);
462
463 // Code Sequence:
464 //
465 // for la32r expands to:
466 // .Lpcadd_hi:
467 // pcaddu12i $rd, %ie_pcadd_hi20(sym)
468 // ld.w $rd, $rd, %ie_pcadd_lo12(.Lpcadd_hi)
469 //
470 // for la32s and la64 expands to:
471 // pcalau12i $rd, %ie_pc_hi20(sym)
472 // ld.w/d $rd, $rd, %ie_pc_lo12(sym)
473 MachineFunction *MF = MBB.getParent();
474 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
475 bool Has32S = STI.hasFeature(Feature: LoongArch::Feature32S);
476 unsigned OpcodeHi = Has32S ? LoongArch::PCALAU12I : LoongArch::PCADDU12I;
477 unsigned OpcodeLo = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
478 unsigned FlagsHi =
479 Has32S ? LoongArchII::MO_IE_PC_HI : LoongArchII::MO_IE_PCADD_HI;
480 unsigned FlagsLo =
481 Has32S ? LoongArchII::MO_IE_PC_LO : LoongArchII::MO_IE_PCADD_LO;
482 return expandPcaxxu12iInstPair(MBB, MBBI, NextMBBI, OpcodeHi, OpcodeLo,
483 FlagsHi, FlagsLo);
484}
485
486bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLD(
487 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
488 MachineBasicBlock::iterator &NextMBBI, bool Large) {
489 if (Large)
490 // Emit the 5-insn large address load sequence with the `%got_pc` family
491 // of relocs, with the `pcalau12i` insn relocated with `%ld_pc_hi20`.
492 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode: LoongArch::ADD_D,
493 IdentifyingMO: LoongArchII::MO_LD_PC_HI);
494
495 // Code Sequence:
496 //
497 // for la32r expands to:
498 // .Lpcadd_hi:
499 // pcaddu12i $rd, %ld_pcadd_hi20(sym)
500 // addi.w $rd, $rd, %ld_pcadd_lo12(.Lpcadd_hi)
501 //
502 // for la32s and la64 expands to:
503 // pcalau12i $rd, %ld_pc_hi20(sym)
504 // addi.w/d $rd, $rd, %got_pc_lo12(sym)
505 MachineFunction *MF = MBB.getParent();
506 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
507 bool Has32S = STI.hasFeature(Feature: LoongArch::Feature32S);
508 unsigned OpcodeHi = Has32S ? LoongArch::PCALAU12I : LoongArch::PCADDU12I;
509 unsigned OpcodeLo = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
510 unsigned FlagsHi =
511 Has32S ? LoongArchII::MO_LD_PC_HI : LoongArchII::MO_LD_PCADD_HI;
512 unsigned FlagsLo =
513 Has32S ? LoongArchII::MO_GOT_PC_LO : LoongArchII::MO_LD_PCADD_LO;
514 return expandPcaxxu12iInstPair(MBB, MBBI, NextMBBI, OpcodeHi, OpcodeLo,
515 FlagsHi, FlagsLo);
516}
517
518bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSGD(
519 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
520 MachineBasicBlock::iterator &NextMBBI, bool Large) {
521 if (Large)
522 // Emit the 5-insn large address load sequence with the `%got_pc` family
523 // of relocs, with the `pcalau12i` insn relocated with `%gd_pc_hi20`.
524 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode: LoongArch::ADD_D,
525 IdentifyingMO: LoongArchII::MO_GD_PC_HI);
526
527 // Code Sequence:
528 //
529 // for la32r expands to:
530 // .Lpcadd_hi:
531 // pcaddu12i $rd, %gd_pcadd_hi20(sym)
532 // addi.w $rd, $rd, %gd_pcadd_lo12(.Lpcadd_hi)
533 //
534 // for la32s and la64 expands to:
535 // pcalau12i $rd, %gd_pc_hi20(sym)
536 // addi.w/d $rd, $rd, %got_pc_lo12(sym)
537 MachineFunction *MF = MBB.getParent();
538 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
539 bool Has32S = STI.hasFeature(Feature: LoongArch::Feature32S);
540 unsigned OpcodeHi = Has32S ? LoongArch::PCALAU12I : LoongArch::PCADDU12I;
541 unsigned OpcodeLo = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
542 unsigned FlagsHi =
543 Has32S ? LoongArchII::MO_GD_PC_HI : LoongArchII::MO_GD_PCADD_HI;
544 unsigned FlagsLo =
545 Has32S ? LoongArchII::MO_GOT_PC_LO : LoongArchII::MO_GD_PCADD_LO;
546 return expandPcaxxu12iInstPair(MBB, MBBI, NextMBBI, OpcodeHi, OpcodeLo,
547 FlagsHi, FlagsLo);
548}
549
550bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc(
551 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
552 MachineBasicBlock::iterator &NextMBBI, bool Large) {
553 MachineFunction *MF = MBB.getParent();
554 MachineInstr &MI = *MBBI;
555 DebugLoc DL = MI.getDebugLoc();
556
557 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
558 bool Has32S = STI.hasFeature(Feature: LoongArch::Feature32S);
559 bool EnableRelax = STI.hasFeature(Feature: LoongArch::FeatureRelax);
560 unsigned PCA = Has32S ? LoongArch::PCALAU12I : LoongArch::PCADDU12I;
561 unsigned ADD = STI.is64Bit() ? LoongArch::ADD_D : LoongArch::ADD_W;
562 unsigned ADDI = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
563 unsigned LD = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
564 unsigned MO =
565 Has32S ? LoongArchII::MO_DESC_PC_HI : LoongArchII::MO_DESC_PCADD_HI;
566
567 Register DestReg = MI.getOperand(i: 0).getReg();
568 Register Tmp1Reg =
569 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
570 MachineOperand &Symbol = MI.getOperand(i: Large ? 2 : 1);
571
572 MachineInstr *PCAMI =
573 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: PCA), DestReg: Tmp1Reg)
574 .addDisp(Disp: Symbol, off: 0,
575 TargetFlags: LoongArchII::encodeFlags(Flags: MO, Relax: EnableRelax && !Large));
576
577 if (Large) {
578 // Code Sequence:
579 //
580 // pcalau12i $a0, %desc_pc_hi20(sym)
581 // addi.d $a1, $zero, %desc_pc_lo12(sym)
582 // lu32i.d $a1, %desc64_pc_lo20(sym)
583 // lu52i.d $a1, $a1, %desc64_pc_hi12(sym)
584 // add.d $a0, $a0, $a1
585 // ld.d $ra, $a0, %desc_ld(sym)
586 // jirl $ra, $ra, %desc_call(sym)
587 // add.d $dst, $a0, $tp
588 assert(MBB.getParent()->getSubtarget<LoongArchSubtarget>().is64Bit() &&
589 "Large code model requires LA64");
590 Register Tmp2Reg =
591 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
592 Register Tmp3Reg =
593 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
594 Register Tmp4Reg =
595 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
596 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::ADDI_D), DestReg: Tmp2Reg)
597 .addReg(RegNo: LoongArch::R0)
598 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_DESC_PC_LO);
599 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU32I_D), DestReg: Tmp3Reg)
600 .addReg(RegNo: Tmp2Reg, Flags: RegState::Kill)
601 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_DESC64_PC_LO);
602 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU52I_D), DestReg: Tmp4Reg)
603 .addReg(RegNo: Tmp3Reg)
604 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_DESC64_PC_HI);
605 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::ADD_D), DestReg: LoongArch::R4)
606 .addReg(RegNo: Tmp1Reg)
607 .addReg(RegNo: Tmp4Reg);
608 } else {
609 // Code Sequence:
610 //
611 // for la32r expands to:
612 // .Lpcadd_hi:
613 // pcaddu12i $a0, %desc_pcadd_hi20(sym)
614 // addi.w $a0, $a0, %desc_pcadd_lo12(.Lpcadd_hi)
615 // ld.w $ra, $a0, %desc_ld(sym)
616 // jirl $ra, $ra, %desc_call(sym)
617 // add.w $dst, $a0, $tp
618 //
619 // for la32s and la64 expands to:
620 // pcalau12i $a0, %desc_pc_hi20(sym)
621 // addi.w/d $a0, $a0, %desc_pc_lo12(sym)
622 // ld.w/d $ra, $a0, %desc_ld(sym)
623 // jirl $ra, $ra, %desc_call(sym)
624 // add.w/d $dst, $a0, $tp
625 if (Has32S) {
626 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: ADDI), DestReg: LoongArch::R4)
627 .addReg(RegNo: Tmp1Reg)
628 .addDisp(Disp: Symbol, off: 0,
629 TargetFlags: LoongArchII::encodeFlags(Flags: LoongArchII::MO_DESC_PC_LO,
630 Relax: EnableRelax));
631 } else {
632 MCSymbol *PCASymbol = MF->getContext().createNamedTempSymbol(Name: "pcadd_hi");
633 PCAMI->setPreInstrSymbol(MF&: *MF, Symbol: PCASymbol);
634 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: ADDI), DestReg: LoongArch::R4)
635 .addReg(RegNo: Tmp1Reg)
636 .addSym(Sym: PCASymbol, TargetFlags: LoongArchII::encodeFlags(
637 Flags: LoongArchII::MO_DESC_PCADD_LO, Relax: EnableRelax));
638 }
639 }
640
641 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LD), DestReg: LoongArch::R1)
642 .addReg(RegNo: LoongArch::R4)
643 .addDisp(Disp: Symbol, off: 0,
644 TargetFlags: LoongArchII::encodeFlags(Flags: LoongArchII::MO_DESC_LD,
645 Relax: EnableRelax && !Large));
646 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::PseudoDESC_CALL), DestReg: LoongArch::R1)
647 .addReg(RegNo: LoongArch::R1)
648 .addDisp(Disp: Symbol, off: 0,
649 TargetFlags: LoongArchII::encodeFlags(Flags: LoongArchII::MO_DESC_CALL,
650 Relax: EnableRelax && !Large));
651 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: ADD), DestReg)
652 .addReg(RegNo: LoongArch::R4)
653 .addReg(RegNo: LoongArch::R2);
654
655 MI.eraseFromParent();
656 return true;
657}
658
659bool LoongArchPreRAExpandPseudo::expandFunctionCALL(
660 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
661 MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {
662 MachineFunction *MF = MBB.getParent();
663 MachineInstr &MI = *MBBI;
664
665 switch (MF->getTarget().getCodeModel()) {
666 default:
667 report_fatal_error(reason: "Unexpected code model");
668 break;
669 case CodeModel::Small: {
670 // CALL:
671 // bl func
672 // TAIL:
673 // b func
674 unsigned Opcode = IsTailCall ? LoongArch::PseudoB_TAIL : LoongArch::BL;
675 MI.setDesc(TII->get(Opcode));
676 return true;
677 }
678 case CodeModel::Large: {
679 // Emit the 5-insn large address load sequence, either directly or
680 // indirectly in case of going through the GOT, then JIRL_TAIL or
681 // JIRL_CALL to $addr.
682 const MachineOperand &Func = MI.getOperand(i: 0);
683 unsigned Opcode =
684 IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
685 Register AddrReg =
686 IsTailCall
687 ? MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass)
688 : LoongArch::R1;
689
690 bool UseGOT = Func.getTargetFlags() == LoongArchII::MO_CALL_PLT;
691 unsigned MO = UseGOT ? LoongArchII::MO_GOT_PC_HI : LoongArchII::MO_PCREL_LO;
692 unsigned LAOpcode = UseGOT ? LoongArch::LDX_D : LoongArch::ADD_D;
693 expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode: LAOpcode, IdentifyingMO: MO, Symbol: Func, DestReg: AddrReg,
694 EraseFromParent: false);
695
696 // Mutate the pseudo into the JIRL in place, keeping its implicit operands.
697 // Operand 0 becomes the address register; operand 1 is the jump offset.
698 MI.setDesc(TII->get(Opcode));
699 MI.getOperand(i: 0).ChangeToRegister(Reg: AddrReg, /*isDef=*/false);
700 MI.insert(InsertBefore: std::next(x: MI.operands_begin()), Ops: MachineOperand::CreateImm(Val: 0));
701 return true;
702 }
703 }
704 llvm_unreachable("Unexpected code model");
705}
706
707void LoongArchPreRAExpandPseudo::annotateTableJump(
708 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) {
709 MachineFunction *MF = MBB.getParent();
710 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
711
712 bool IsFound = false;
713
714 std::function<void(MachineInstr *, int)> FindJTIMI = [&](MachineInstr *MInst,
715 int FindDepth) {
716 if (FindDepth < 0)
717 return;
718 for (auto &MO : MInst->all_uses()) {
719 if (IsFound)
720 return;
721 Register Reg = MO.getReg();
722 if (!Reg.isVirtual())
723 continue;
724 MachineInstr *DefMI = MRI.getVRegDef(Reg);
725 if (!DefMI)
726 continue;
727 for (unsigned Idx = 0; Idx < DefMI->getNumOperands(); ++Idx) {
728 MachineOperand &MO = DefMI->getOperand(i: Idx);
729 if (MO.isJTI()) {
730 MBBI->setPreInstrSymbol(
731 MF&: *MF, Symbol: MF->getContext().createNamedTempSymbol(Name: "jrtb_"));
732 MF->getInfo<LoongArchMachineFunctionInfo>()->setJumpInfo(
733 JrMI: &*MBBI, JTIIdx: MO.getIndex());
734 IsFound = true;
735 return;
736 }
737 }
738 FindJTIMI(DefMI, --FindDepth);
739 }
740 };
741
742 // FindDepth = 4, probably sufficient.
743 FindJTIMI(&*MBBI, /*FindDepth=*/4);
744}
745
746class LoongArchExpandPseudo : public MachineFunctionPass {
747public:
748 const LoongArchInstrInfo *TII;
749 static char ID;
750
751 LoongArchExpandPseudo() : MachineFunctionPass(ID) {}
752
753 bool runOnMachineFunction(MachineFunction &MF) override;
754
755 StringRef getPassName() const override {
756 return LOONGARCH_EXPAND_PSEUDO_NAME;
757 }
758
759private:
760 bool expandMBB(MachineBasicBlock &MBB);
761 bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
762 MachineBasicBlock::iterator &NextMBBI);
763 bool expandCopyCFR(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
764 MachineBasicBlock::iterator &NextMBBI);
765 bool expandFunctionCALL(MachineBasicBlock &MBB,
766 MachineBasicBlock::iterator MBBI,
767 MachineBasicBlock::iterator &NextMBBI,
768 bool IsTailCall);
769 bool expandAddUpperImm(MachineBasicBlock &MBB,
770 MachineBasicBlock::iterator MBBI);
771};
772
773char LoongArchExpandPseudo::ID = 0;
774
775bool LoongArchExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
776 TII =
777 static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo());
778
779 bool Modified = false;
780 for (auto &MBB : MF)
781 Modified |= expandMBB(MBB);
782
783 return Modified;
784}
785
786bool LoongArchExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
787 bool Modified = false;
788
789 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
790 while (MBBI != E) {
791 MachineBasicBlock::iterator NMBBI = std::next(x: MBBI);
792 Modified |= expandMI(MBB, MBBI, NextMBBI&: NMBBI);
793 MBBI = NMBBI;
794 }
795
796 return Modified;
797}
798
799bool LoongArchExpandPseudo::expandMI(MachineBasicBlock &MBB,
800 MachineBasicBlock::iterator MBBI,
801 MachineBasicBlock::iterator &NextMBBI) {
802 switch (MBBI->getOpcode()) {
803 case LoongArch::PseudoCopyCFR:
804 return expandCopyCFR(MBB, MBBI, NextMBBI);
805 case LoongArch::PseudoCALL_MEDIUM:
806 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
807 case LoongArch::PseudoTAIL_MEDIUM:
808 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
809 case LoongArch::PseudoAddUpperImm:
810 return expandAddUpperImm(MBB, MBBI);
811 }
812
813 return false;
814}
815
816bool LoongArchExpandPseudo::expandCopyCFR(
817 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
818 MachineBasicBlock::iterator &NextMBBI) {
819 MachineFunction *MF = MBB.getParent();
820 MachineInstr &MI = *MBBI;
821 DebugLoc DL = MI.getDebugLoc();
822
823 // Expand:
824 // MBB:
825 // fcmp.caf.s $dst, $fa0, $fa0 # set $dst 0(false)
826 // bceqz $src, SinkBB
827 // FalseBB:
828 // fcmp.cueq.s $dst, $fa0, $fa0 # set $dst 1(true)
829 // SinkBB:
830 // fallthrough
831
832 const BasicBlock *LLVM_BB = MBB.getBasicBlock();
833 auto *FalseBB = MF->CreateMachineBasicBlock(BB: LLVM_BB);
834 auto *SinkBB = MF->CreateMachineBasicBlock(BB: LLVM_BB);
835
836 MF->insert(MBBI: ++MBB.getIterator(), MBB: FalseBB);
837 MF->insert(MBBI: ++FalseBB->getIterator(), MBB: SinkBB);
838
839 Register DestReg = MI.getOperand(i: 0).getReg();
840 Register SrcReg = MI.getOperand(i: 1).getReg();
841 // DestReg = 0
842 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::SET_CFR_FALSE), DestReg);
843 // Insert branch instruction.
844 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::BCEQZ))
845 .addReg(RegNo: SrcReg)
846 .addMBB(MBB: SinkBB);
847 // DestReg = 1
848 BuildMI(BB: FalseBB, MIMD: DL, MCID: TII->get(Opcode: LoongArch::SET_CFR_TRUE), DestReg);
849
850 FalseBB->addSuccessor(Succ: SinkBB);
851
852 SinkBB->splice(Where: SinkBB->end(), Other: &MBB, From: MI, To: MBB.end());
853 SinkBB->transferSuccessors(FromMBB: &MBB);
854
855 MBB.addSuccessor(Succ: FalseBB);
856 MBB.addSuccessor(Succ: SinkBB);
857
858 NextMBBI = MBB.end();
859 MI.eraseFromParent();
860
861 // Make sure live-ins are correctly attached to this new basic block.
862 LivePhysRegs LiveRegs;
863 computeAndAddLiveIns(LiveRegs, MBB&: *FalseBB);
864 computeAndAddLiveIns(LiveRegs, MBB&: *SinkBB);
865
866 return true;
867}
868
869bool LoongArchExpandPseudo::expandFunctionCALL(
870 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
871 MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {
872 MachineFunction *MF = MBB.getParent();
873 MachineInstr &MI = *MBBI;
874 DebugLoc DL = MI.getDebugLoc();
875 const MachineOperand &Func = MI.getOperand(i: 0);
876
877 switch (MF->getTarget().getCodeModel()) {
878 default:
879 report_fatal_error(reason: "Unexpected code model");
880 break;
881 case CodeModel::Medium: {
882 // for la32 expands to:
883 // CALL:
884 // pcaddu12i $ra, %call30(func)
885 // jirl $ra, $ra, 0
886 // TAIL:
887 // pcaddu12i $t8, %call30(func)
888 // jirl $r0, $t8, 0
889 //
890 // for la64 expands to:
891 // CALL:
892 // pcaddu18i $ra, %call36(func)
893 // jirl $ra, $ra, 0
894 // TAIL:
895 // pcaddu18i $t8, %call36(func)
896 // jirl $r0, $t8, 0
897 unsigned Opcode =
898 IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
899 Register ScratchReg = IsTailCall ? LoongArch::R20 : LoongArch::R1;
900 bool Is64Bit = MF->getSubtarget<LoongArchSubtarget>().is64Bit();
901 unsigned PC = Is64Bit ? LoongArch::PCADDU18I : LoongArch::PCADDU12I;
902 unsigned MO = Is64Bit ? LoongArchII::MO_CALL36 : LoongArchII::MO_CALL30;
903 MachineInstrBuilder MIB = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: PC), DestReg: ScratchReg);
904
905 if (Func.isSymbol())
906 MIB.addExternalSymbol(FnName: Func.getSymbolName(), TargetFlags: MO);
907 else
908 MIB.addDisp(Disp: Func, off: 0, TargetFlags: MO);
909
910 // Mutate the pseudo into the JIRL in place, keeping its implicit operands.
911 // Operand 0 becomes the address register; operand 1 is the jump offset.
912 MI.setDesc(TII->get(Opcode));
913 MI.getOperand(i: 0).ChangeToRegister(Reg: ScratchReg, /*isDef=*/false);
914 MI.insert(InsertBefore: std::next(x: MI.operands_begin()), Ops: MachineOperand::CreateImm(Val: 0));
915 return true;
916 }
917 }
918 llvm_unreachable("Unexpected code model");
919}
920
921bool LoongArchExpandPseudo::expandAddUpperImm(
922 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) {
923 DebugLoc DL = MBBI->getDebugLoc();
924 MachineFunction *MF = MBB.getParent();
925 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
926
927 Register DstReg = MBBI->getOperand(i: 0).getReg();
928 bool DstIsDead = MBBI->getOperand(i: 0).isDead();
929 bool Renamable = MBBI->getOperand(i: 0).isRenamable();
930 Register BaseReg = MBBI->getOperand(i: 1).getReg();
931 int64_t Hi = MBBI->getOperand(i: 2).getImm();
932 bool IsLA64 = STI.is64Bit();
933
934 // Expand to LU12I_W + ADD_W/D: the immediate is upper 20-bit.
935 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU12I_W))
936 .addReg(RegNo: DstReg, Flags: RegState::Define | getRenamableRegState(B: Renamable))
937 .addImm(Val: Hi);
938 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W))
939 .addReg(RegNo: DstReg, Flags: RegState::Define | getDeadRegState(B: DstIsDead) |
940 getRenamableRegState(B: Renamable))
941 .addReg(RegNo: BaseReg)
942 .addReg(RegNo: DstReg, Flags: RegState::Kill | getRenamableRegState(B: Renamable));
943
944 MBBI->eraseFromParent();
945 return true;
946}
947
948} // end namespace
949
950INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "loongarch-prera-expand-pseudo",
951 LOONGARCH_PRERA_EXPAND_PSEUDO_NAME, false, false)
952
953INITIALIZE_PASS(LoongArchExpandPseudo, "loongarch-expand-pseudo",
954 LOONGARCH_EXPAND_PSEUDO_NAME, false, false)
955
956namespace llvm {
957
958FunctionPass *createLoongArchPreRAExpandPseudoPass() {
959 return new LoongArchPreRAExpandPseudo();
960}
961FunctionPass *createLoongArchExpandPseudoPass() {
962 return new LoongArchExpandPseudo();
963}
964
965} // end namespace llvm
966