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 expandPcalau12iInstPair(MachineBasicBlock &MBB,
61 MachineBasicBlock::iterator MBBI,
62 MachineBasicBlock::iterator &NextMBBI,
63 unsigned FlagsHi, unsigned SecondOpcode,
64 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:
165 case LoongArch::PseudoCALL_LARGE:
166 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
167 case LoongArch::PseudoTAIL:
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::expandPcalau12iInstPair(
181 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
182 MachineBasicBlock::iterator &NextMBBI, unsigned FlagsHi,
183 unsigned SecondOpcode, 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 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::PCALAU12I), DestReg: ScratchReg)
197 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::encodeFlags(Flags: FlagsHi, Relax: EnableRelax));
198
199 MachineInstr *SecondMI =
200 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: SecondOpcode), DestReg)
201 .addReg(RegNo: ScratchReg)
202 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::encodeFlags(Flags: FlagsLo, Relax: EnableRelax));
203
204 if (MI.hasOneMemOperand())
205 SecondMI->addMemOperand(MF&: *MF, MO: *MI.memoperands_begin());
206
207 MI.eraseFromParent();
208 return true;
209}
210
211bool LoongArchPreRAExpandPseudo::expandLargeAddressLoad(
212 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
213 MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode,
214 unsigned IdentifyingMO) {
215 MachineInstr &MI = *MBBI;
216 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode, IdentifyingMO,
217 Symbol: MI.getOperand(i: 2), DestReg: MI.getOperand(i: 0).getReg(),
218 EraseFromParent: true);
219}
220
221bool LoongArchPreRAExpandPseudo::expandLargeAddressLoad(
222 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
223 MachineBasicBlock::iterator &NextMBBI, unsigned LastOpcode,
224 unsigned IdentifyingMO, const MachineOperand &Symbol, Register DestReg,
225 bool EraseFromParent) {
226 // Code Sequence:
227 //
228 // Part1: pcalau12i $scratch, %MO1(sym)
229 // Part0: addi.d $dest, $zero, %MO0(sym)
230 // Part2: lu32i.d $dest, %MO2(sym)
231 // Part3: lu52i.d $dest, $dest, %MO3(sym)
232 // Fin: LastOpcode $dest, $dest, $scratch
233
234 unsigned MO0, MO1, MO2, MO3;
235 switch (IdentifyingMO) {
236 default:
237 llvm_unreachable("unsupported identifying MO");
238 case LoongArchII::MO_PCREL_LO:
239 MO0 = IdentifyingMO;
240 MO1 = LoongArchII::MO_PCREL_HI;
241 MO2 = LoongArchII::MO_PCREL64_LO;
242 MO3 = LoongArchII::MO_PCREL64_HI;
243 break;
244 case LoongArchII::MO_GOT_PC_HI:
245 case LoongArchII::MO_LD_PC_HI:
246 case LoongArchII::MO_GD_PC_HI:
247 // These cases relocate just like the GOT case, except for Part1.
248 MO0 = LoongArchII::MO_GOT_PC_LO;
249 MO1 = IdentifyingMO;
250 MO2 = LoongArchII::MO_GOT_PC64_LO;
251 MO3 = LoongArchII::MO_GOT_PC64_HI;
252 break;
253 case LoongArchII::MO_IE_PC_LO:
254 MO0 = IdentifyingMO;
255 MO1 = LoongArchII::MO_IE_PC_HI;
256 MO2 = LoongArchII::MO_IE_PC64_LO;
257 MO3 = LoongArchII::MO_IE_PC64_HI;
258 break;
259 }
260
261 MachineFunction *MF = MBB.getParent();
262 MachineInstr &MI = *MBBI;
263 DebugLoc DL = MI.getDebugLoc();
264
265 assert(MF->getSubtarget<LoongArchSubtarget>().is64Bit() &&
266 "Large code model requires LA64");
267
268 Register TmpPart1 =
269 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
270 Register TmpPart0 =
271 DestReg.isVirtual()
272 ? MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass)
273 : DestReg;
274 Register TmpParts02 =
275 DestReg.isVirtual()
276 ? MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass)
277 : DestReg;
278 Register TmpParts023 =
279 DestReg.isVirtual()
280 ? MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass)
281 : DestReg;
282
283 auto Part1 = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::PCALAU12I), DestReg: TmpPart1);
284 auto Part0 = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::ADDI_D), DestReg: TmpPart0)
285 .addReg(RegNo: LoongArch::R0);
286 auto Part2 = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU32I_D), DestReg: TmpParts02)
287 // "rj" is needed due to InstrInfo pattern requirement.
288 .addReg(RegNo: TmpPart0, flags: RegState::Kill);
289 auto Part3 = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU52I_D), DestReg: TmpParts023)
290 .addReg(RegNo: TmpParts02, flags: RegState::Kill);
291 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LastOpcode), DestReg)
292 .addReg(RegNo: TmpParts023)
293 .addReg(RegNo: TmpPart1, flags: RegState::Kill);
294
295 if (Symbol.getType() == MachineOperand::MO_ExternalSymbol) {
296 const char *SymName = Symbol.getSymbolName();
297 Part0.addExternalSymbol(FnName: SymName, TargetFlags: MO0);
298 Part1.addExternalSymbol(FnName: SymName, TargetFlags: MO1);
299 Part2.addExternalSymbol(FnName: SymName, TargetFlags: MO2);
300 Part3.addExternalSymbol(FnName: SymName, TargetFlags: MO3);
301 } else {
302 Part0.addDisp(Disp: Symbol, off: 0, TargetFlags: MO0);
303 Part1.addDisp(Disp: Symbol, off: 0, TargetFlags: MO1);
304 Part2.addDisp(Disp: Symbol, off: 0, TargetFlags: MO2);
305 Part3.addDisp(Disp: Symbol, off: 0, TargetFlags: MO3);
306 }
307
308 if (EraseFromParent)
309 MI.eraseFromParent();
310
311 return true;
312}
313
314bool LoongArchPreRAExpandPseudo::expandLoadAddressPcrel(
315 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
316 MachineBasicBlock::iterator &NextMBBI, bool Large) {
317 if (Large)
318 // Emit the 5-insn large address load sequence with the `%pc` family of
319 // relocs.
320 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode: LoongArch::ADD_D,
321 IdentifyingMO: LoongArchII::MO_PCREL_LO);
322
323 // Code Sequence:
324 // pcalau12i $rd, %pc_hi20(sym)
325 // addi.w/d $rd, $rd, %pc_lo12(sym)
326 MachineFunction *MF = MBB.getParent();
327 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
328 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
329 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, FlagsHi: LoongArchII::MO_PCREL_HI,
330 SecondOpcode, FlagsLo: LoongArchII::MO_PCREL_LO);
331}
332
333bool LoongArchPreRAExpandPseudo::expandLoadAddressGot(
334 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
335 MachineBasicBlock::iterator &NextMBBI, bool Large) {
336 if (Large)
337 // Emit the 5-insn large address load sequence with the `%got_pc` family
338 // of relocs, loading the result from GOT with `ldx.d` in the end.
339 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode: LoongArch::LDX_D,
340 IdentifyingMO: LoongArchII::MO_GOT_PC_HI);
341
342 // Code Sequence:
343 // pcalau12i $rd, %got_pc_hi20(sym)
344 // ld.w/d $rd, $rd, %got_pc_lo12(sym)
345 MachineFunction *MF = MBB.getParent();
346 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
347 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
348 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, FlagsHi: LoongArchII::MO_GOT_PC_HI,
349 SecondOpcode, FlagsLo: LoongArchII::MO_GOT_PC_LO);
350}
351
352bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLE(
353 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
354 MachineBasicBlock::iterator &NextMBBI) {
355 // Code Sequence:
356 // lu12i.w $rd, %le_hi20_r(sym)
357 // add.w/d $rd, $rd, $tp, %le_add_r(sym)
358 // addi.w/d $rd, $rd, %le_lo12_r(sym)
359 //
360 // Code Sequence while using the large code model:
361 // lu12i.w $rd, %le_hi20(sym)
362 // ori $rd, $rd, %le_lo12(sym)
363 // lu32i.d $rd, %le64_lo20(sym)
364 // lu52i.d $rd, $rd, %le64_hi12(sym)
365 MachineFunction *MF = MBB.getParent();
366 MachineInstr &MI = *MBBI;
367 DebugLoc DL = MI.getDebugLoc();
368
369 bool Large = MF->getTarget().getCodeModel() == CodeModel::Large;
370 Register DestReg = MI.getOperand(i: 0).getReg();
371 Register Parts01 =
372 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
373 Register Part1 =
374 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
375 MachineOperand &Symbol = MI.getOperand(i: 1);
376
377 if (!Large) {
378 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU12I_W), DestReg: Part1)
379 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_LE_HI_R);
380
381 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
382 unsigned AddOp = STI.is64Bit() ? LoongArch::PseudoAddTPRel_D
383 : LoongArch::PseudoAddTPRel_W;
384 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: AddOp), DestReg: Parts01)
385 .addReg(RegNo: Part1, flags: RegState::Kill)
386 .addReg(RegNo: LoongArch::R2)
387 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_LE_ADD_R);
388
389 unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
390 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: AddiOp), DestReg)
391 .addReg(RegNo: Parts01, flags: RegState::Kill)
392 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_LE_LO_R);
393 } else {
394 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU12I_W), DestReg: Part1)
395 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_LE_HI);
396
397 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::ORI), DestReg: Parts01)
398 .addReg(RegNo: Part1, flags: RegState::Kill)
399 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_LE_LO);
400
401 Register Parts012 =
402 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
403
404 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU32I_D), DestReg: Parts012)
405 // "rj" is needed due to InstrInfo pattern requirement.
406 .addReg(RegNo: Parts01, flags: RegState::Kill)
407 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_LE64_LO);
408 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU52I_D), DestReg)
409 .addReg(RegNo: Parts012, flags: RegState::Kill)
410 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_LE64_HI);
411 }
412
413 MI.eraseFromParent();
414 return true;
415}
416
417bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSIE(
418 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
419 MachineBasicBlock::iterator &NextMBBI, bool Large) {
420 if (Large)
421 // Emit the 5-insn large address load sequence with the `%ie_pc` family
422 // of relocs, loading the result with `ldx.d` in the end.
423 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode: LoongArch::LDX_D,
424 IdentifyingMO: LoongArchII::MO_IE_PC_LO);
425
426 // Code Sequence:
427 // pcalau12i $rd, %ie_pc_hi20(sym)
428 // ld.w/d $rd, $rd, %ie_pc_lo12(sym)
429 MachineFunction *MF = MBB.getParent();
430 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
431 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
432 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, FlagsHi: LoongArchII::MO_IE_PC_HI,
433 SecondOpcode, FlagsLo: LoongArchII::MO_IE_PC_LO);
434}
435
436bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLD(
437 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
438 MachineBasicBlock::iterator &NextMBBI, bool Large) {
439 if (Large)
440 // Emit the 5-insn large address load sequence with the `%got_pc` family
441 // of relocs, with the `pcalau12i` insn relocated with `%ld_pc_hi20`.
442 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode: LoongArch::ADD_D,
443 IdentifyingMO: LoongArchII::MO_LD_PC_HI);
444
445 // Code Sequence:
446 // pcalau12i $rd, %ld_pc_hi20(sym)
447 // addi.w/d $rd, $rd, %got_pc_lo12(sym)
448 MachineFunction *MF = MBB.getParent();
449 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
450 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
451 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, FlagsHi: LoongArchII::MO_LD_PC_HI,
452 SecondOpcode, FlagsLo: LoongArchII::MO_GOT_PC_LO);
453}
454
455bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSGD(
456 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
457 MachineBasicBlock::iterator &NextMBBI, bool Large) {
458 if (Large)
459 // Emit the 5-insn large address load sequence with the `%got_pc` family
460 // of relocs, with the `pcalau12i` insn relocated with `%gd_pc_hi20`.
461 return expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode: LoongArch::ADD_D,
462 IdentifyingMO: LoongArchII::MO_GD_PC_HI);
463
464 // Code Sequence:
465 // pcalau12i $rd, %gd_pc_hi20(sym)
466 // addi.w/d $rd, $rd, %got_pc_lo12(sym)
467 MachineFunction *MF = MBB.getParent();
468 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
469 unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
470 return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, FlagsHi: LoongArchII::MO_GD_PC_HI,
471 SecondOpcode, FlagsLo: LoongArchII::MO_GOT_PC_LO);
472}
473
474bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc(
475 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
476 MachineBasicBlock::iterator &NextMBBI, bool Large) {
477 MachineFunction *MF = MBB.getParent();
478 MachineInstr &MI = *MBBI;
479 DebugLoc DL = MI.getDebugLoc();
480
481 const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
482 unsigned ADD = STI.is64Bit() ? LoongArch::ADD_D : LoongArch::ADD_W;
483 unsigned ADDI = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
484 unsigned LD = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
485 bool EnableRelax = STI.hasFeature(Feature: LoongArch::FeatureRelax);
486
487 Register DestReg = MI.getOperand(i: 0).getReg();
488 Register Tmp1Reg =
489 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
490 MachineOperand &Symbol = MI.getOperand(i: Large ? 2 : 1);
491
492 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::PCALAU12I), DestReg: Tmp1Reg)
493 .addDisp(Disp: Symbol, off: 0,
494 TargetFlags: LoongArchII::encodeFlags(Flags: LoongArchII::MO_DESC_PC_HI,
495 Relax: EnableRelax && !Large));
496
497 if (Large) {
498 // Code Sequence:
499 //
500 // pcalau12i $a0, %desc_pc_hi20(sym)
501 // addi.d $a1, $zero, %desc_pc_lo12(sym)
502 // lu32i.d $a1, %desc64_pc_lo20(sym)
503 // lu52i.d $a1, $a1, %desc64_pc_hi12(sym)
504 // add.d $a0, $a0, $a1
505 // ld.d $ra, $a0, %desc_ld(sym)
506 // jirl $ra, $ra, %desc_call(sym)
507 // add.d $dst, $a0, $tp
508 assert(MBB.getParent()->getSubtarget<LoongArchSubtarget>().is64Bit() &&
509 "Large code model requires LA64");
510 Register Tmp2Reg =
511 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
512 Register Tmp3Reg =
513 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
514 Register Tmp4Reg =
515 MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
516 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::ADDI_D), DestReg: Tmp2Reg)
517 .addReg(RegNo: LoongArch::R0)
518 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_DESC_PC_LO);
519 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU32I_D), DestReg: Tmp3Reg)
520 .addReg(RegNo: Tmp2Reg, flags: RegState::Kill)
521 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_DESC64_PC_LO);
522 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::LU52I_D), DestReg: Tmp4Reg)
523 .addReg(RegNo: Tmp3Reg)
524 .addDisp(Disp: Symbol, off: 0, TargetFlags: LoongArchII::MO_DESC64_PC_HI);
525 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::ADD_D), DestReg: LoongArch::R4)
526 .addReg(RegNo: Tmp1Reg)
527 .addReg(RegNo: Tmp4Reg);
528 } else {
529 // Code Sequence:
530 // pcalau12i $a0, %desc_pc_hi20(sym)
531 // addi.w/d $a0, $a0, %desc_pc_lo12(sym)
532 // ld.w/d $ra, $a0, %desc_ld(sym)
533 // jirl $ra, $ra, %desc_call(sym)
534 // add.w/d $dst, $a0, $tp
535 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: ADDI), DestReg: LoongArch::R4)
536 .addReg(RegNo: Tmp1Reg)
537 .addDisp(
538 Disp: Symbol, off: 0,
539 TargetFlags: LoongArchII::encodeFlags(Flags: LoongArchII::MO_DESC_PC_LO, Relax: EnableRelax));
540 }
541
542 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LD), DestReg: LoongArch::R1)
543 .addReg(RegNo: LoongArch::R4)
544 .addDisp(Disp: Symbol, off: 0,
545 TargetFlags: LoongArchII::encodeFlags(Flags: LoongArchII::MO_DESC_LD,
546 Relax: EnableRelax && !Large));
547 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::PseudoDESC_CALL), DestReg: LoongArch::R1)
548 .addReg(RegNo: LoongArch::R1)
549 .addDisp(Disp: Symbol, off: 0,
550 TargetFlags: LoongArchII::encodeFlags(Flags: LoongArchII::MO_DESC_CALL,
551 Relax: EnableRelax && !Large));
552 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: ADD), DestReg)
553 .addReg(RegNo: LoongArch::R4)
554 .addReg(RegNo: LoongArch::R2);
555
556 MI.eraseFromParent();
557 return true;
558}
559
560bool LoongArchPreRAExpandPseudo::expandFunctionCALL(
561 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
562 MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {
563 MachineFunction *MF = MBB.getParent();
564 MachineInstr &MI = *MBBI;
565 DebugLoc DL = MI.getDebugLoc();
566 const MachineOperand &Func = MI.getOperand(i: 0);
567 MachineInstrBuilder CALL;
568 unsigned Opcode;
569
570 switch (MF->getTarget().getCodeModel()) {
571 default:
572 report_fatal_error(reason: "Unexpected code model");
573 break;
574 case CodeModel::Small: {
575 // CALL:
576 // bl func
577 // TAIL:
578 // b func
579 Opcode = IsTailCall ? LoongArch::PseudoB_TAIL : LoongArch::BL;
580 CALL = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode)).add(MO: Func);
581 break;
582 }
583 case CodeModel::Large: {
584 // Emit the 5-insn large address load sequence, either directly or
585 // indirectly in case of going through the GOT, then JIRL_TAIL or
586 // JIRL_CALL to $addr.
587 Opcode =
588 IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
589 Register AddrReg =
590 IsTailCall
591 ? MF->getRegInfo().createVirtualRegister(RegClass: &LoongArch::GPRRegClass)
592 : LoongArch::R1;
593
594 bool UseGOT = Func.getTargetFlags() == LoongArchII::MO_CALL_PLT;
595 unsigned MO = UseGOT ? LoongArchII::MO_GOT_PC_HI : LoongArchII::MO_PCREL_LO;
596 unsigned LAOpcode = UseGOT ? LoongArch::LDX_D : LoongArch::ADD_D;
597 expandLargeAddressLoad(MBB, MBBI, NextMBBI, LastOpcode: LAOpcode, IdentifyingMO: MO, Symbol: Func, DestReg: AddrReg,
598 EraseFromParent: false);
599 CALL = BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode)).addReg(RegNo: AddrReg).addImm(Val: 0);
600 break;
601 }
602 }
603
604 // Transfer implicit operands.
605 CALL.copyImplicitOps(OtherMI: MI);
606
607 // Transfer MI flags.
608 CALL.setMIFlags(MI.getFlags());
609
610 MI.eraseFromParent();
611 return true;
612}
613
614void LoongArchPreRAExpandPseudo::annotateTableJump(
615 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) {
616 MachineFunction *MF = MBB.getParent();
617 MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
618
619 bool IsFound = false;
620
621 std::function<void(MachineInstr *, int)> FindJTIMI = [&](MachineInstr *MInst,
622 int FindDepth) {
623 if (FindDepth < 0)
624 return;
625 for (auto &MO : MInst->all_uses()) {
626 if (IsFound)
627 return;
628 Register Reg = MO.getReg();
629 if (!Reg.isVirtual())
630 continue;
631 MachineInstr *DefMI = MRI.getVRegDef(Reg);
632 if (!DefMI)
633 continue;
634 for (unsigned Idx = 0; Idx < DefMI->getNumOperands(); ++Idx) {
635 MachineOperand &MO = DefMI->getOperand(i: Idx);
636 if (MO.isJTI()) {
637 MBBI->setPreInstrSymbol(
638 MF&: *MF, Symbol: MF->getContext().createNamedTempSymbol(Name: "jrtb_"));
639 MF->getInfo<LoongArchMachineFunctionInfo>()->setJumpInfo(
640 JrMI: &*MBBI, JTIIdx: MO.getIndex());
641 IsFound = true;
642 return;
643 }
644 }
645 FindJTIMI(DefMI, --FindDepth);
646 }
647 };
648
649 // FindDepth = 3, probably sufficient.
650 FindJTIMI(&*MBBI, /*FindDepth=*/3);
651}
652
653class LoongArchExpandPseudo : public MachineFunctionPass {
654public:
655 const LoongArchInstrInfo *TII;
656 static char ID;
657
658 LoongArchExpandPseudo() : MachineFunctionPass(ID) {}
659
660 bool runOnMachineFunction(MachineFunction &MF) override;
661
662 StringRef getPassName() const override {
663 return LOONGARCH_EXPAND_PSEUDO_NAME;
664 }
665
666private:
667 bool expandMBB(MachineBasicBlock &MBB);
668 bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
669 MachineBasicBlock::iterator &NextMBBI);
670 bool expandCopyCFR(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
671 MachineBasicBlock::iterator &NextMBBI);
672 bool expandFunctionCALL(MachineBasicBlock &MBB,
673 MachineBasicBlock::iterator MBBI,
674 MachineBasicBlock::iterator &NextMBBI,
675 bool IsTailCall);
676};
677
678char LoongArchExpandPseudo::ID = 0;
679
680bool LoongArchExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
681 TII =
682 static_cast<const LoongArchInstrInfo *>(MF.getSubtarget().getInstrInfo());
683
684 bool Modified = false;
685 for (auto &MBB : MF)
686 Modified |= expandMBB(MBB);
687
688 return Modified;
689}
690
691bool LoongArchExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
692 bool Modified = false;
693
694 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
695 while (MBBI != E) {
696 MachineBasicBlock::iterator NMBBI = std::next(x: MBBI);
697 Modified |= expandMI(MBB, MBBI, NextMBBI&: NMBBI);
698 MBBI = NMBBI;
699 }
700
701 return Modified;
702}
703
704bool LoongArchExpandPseudo::expandMI(MachineBasicBlock &MBB,
705 MachineBasicBlock::iterator MBBI,
706 MachineBasicBlock::iterator &NextMBBI) {
707 switch (MBBI->getOpcode()) {
708 case LoongArch::PseudoCopyCFR:
709 return expandCopyCFR(MBB, MBBI, NextMBBI);
710 case LoongArch::PseudoCALL_MEDIUM:
711 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
712 case LoongArch::PseudoTAIL_MEDIUM:
713 return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
714 }
715
716 return false;
717}
718
719bool LoongArchExpandPseudo::expandCopyCFR(
720 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
721 MachineBasicBlock::iterator &NextMBBI) {
722 MachineFunction *MF = MBB.getParent();
723 MachineInstr &MI = *MBBI;
724 DebugLoc DL = MI.getDebugLoc();
725
726 // Expand:
727 // MBB:
728 // fcmp.caf.s $dst, $fa0, $fa0 # set $dst 0(false)
729 // bceqz $src, SinkBB
730 // FalseBB:
731 // fcmp.cueq.s $dst, $fa0, $fa0 # set $dst 1(true)
732 // SinkBB:
733 // fallthrough
734
735 const BasicBlock *LLVM_BB = MBB.getBasicBlock();
736 auto *FalseBB = MF->CreateMachineBasicBlock(BB: LLVM_BB);
737 auto *SinkBB = MF->CreateMachineBasicBlock(BB: LLVM_BB);
738
739 MF->insert(MBBI: ++MBB.getIterator(), MBB: FalseBB);
740 MF->insert(MBBI: ++FalseBB->getIterator(), MBB: SinkBB);
741
742 Register DestReg = MI.getOperand(i: 0).getReg();
743 Register SrcReg = MI.getOperand(i: 1).getReg();
744 // DestReg = 0
745 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::SET_CFR_FALSE), DestReg);
746 // Insert branch instruction.
747 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::BCEQZ))
748 .addReg(RegNo: SrcReg)
749 .addMBB(MBB: SinkBB);
750 // DestReg = 1
751 BuildMI(BB: FalseBB, MIMD: DL, MCID: TII->get(Opcode: LoongArch::SET_CFR_TRUE), DestReg);
752
753 FalseBB->addSuccessor(Succ: SinkBB);
754
755 SinkBB->splice(Where: SinkBB->end(), Other: &MBB, From: MI, To: MBB.end());
756 SinkBB->transferSuccessors(FromMBB: &MBB);
757
758 MBB.addSuccessor(Succ: FalseBB);
759 MBB.addSuccessor(Succ: SinkBB);
760
761 NextMBBI = MBB.end();
762 MI.eraseFromParent();
763
764 // Make sure live-ins are correctly attached to this new basic block.
765 LivePhysRegs LiveRegs;
766 computeAndAddLiveIns(LiveRegs, MBB&: *FalseBB);
767 computeAndAddLiveIns(LiveRegs, MBB&: *SinkBB);
768
769 return true;
770}
771
772bool LoongArchExpandPseudo::expandFunctionCALL(
773 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
774 MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {
775 MachineFunction *MF = MBB.getParent();
776 MachineInstr &MI = *MBBI;
777 DebugLoc DL = MI.getDebugLoc();
778 const MachineOperand &Func = MI.getOperand(i: 0);
779 MachineInstrBuilder CALL;
780 unsigned Opcode;
781
782 switch (MF->getTarget().getCodeModel()) {
783 default:
784 report_fatal_error(reason: "Unexpected code model");
785 break;
786 case CodeModel::Medium: {
787 // CALL:
788 // pcaddu18i $ra, %call36(func)
789 // jirl $ra, $ra, 0
790 // TAIL:
791 // pcaddu18i $t8, %call36(func)
792 // jirl $r0, $t8, 0
793 Opcode =
794 IsTailCall ? LoongArch::PseudoJIRL_TAIL : LoongArch::PseudoJIRL_CALL;
795 Register ScratchReg = IsTailCall ? LoongArch::R20 : LoongArch::R1;
796 MachineInstrBuilder MIB =
797 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: LoongArch::PCADDU18I), DestReg: ScratchReg);
798
799 CALL =
800 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode)).addReg(RegNo: ScratchReg).addImm(Val: 0);
801
802 if (Func.isSymbol())
803 MIB.addExternalSymbol(FnName: Func.getSymbolName(), TargetFlags: LoongArchII::MO_CALL36);
804 else
805 MIB.addDisp(Disp: Func, off: 0, TargetFlags: LoongArchII::MO_CALL36);
806 break;
807 }
808 }
809
810 // Transfer implicit operands.
811 CALL.copyImplicitOps(OtherMI: MI);
812
813 // Transfer MI flags.
814 CALL.setMIFlags(MI.getFlags());
815
816 MI.eraseFromParent();
817 return true;
818}
819
820} // end namespace
821
822INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "loongarch-prera-expand-pseudo",
823 LOONGARCH_PRERA_EXPAND_PSEUDO_NAME, false, false)
824
825INITIALIZE_PASS(LoongArchExpandPseudo, "loongarch-expand-pseudo",
826 LOONGARCH_EXPAND_PSEUDO_NAME, false, false)
827
828namespace llvm {
829
830FunctionPass *createLoongArchPreRAExpandPseudoPass() {
831 return new LoongArchPreRAExpandPseudo();
832}
833FunctionPass *createLoongArchExpandPseudoPass() {
834 return new LoongArchExpandPseudo();
835}
836
837} // end namespace llvm
838