1//=- LoongArchInstrInfo.cpp - LoongArch Instruction Information -*- C++ -*-===//
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 the LoongArch implementation of the TargetInstrInfo class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "LoongArchInstrInfo.h"
14#include "LoongArch.h"
15#include "LoongArchMachineFunctionInfo.h"
16#include "LoongArchRegisterInfo.h"
17#include "MCTargetDesc/LoongArchMCTargetDesc.h"
18#include "MCTargetDesc/LoongArchMatInt.h"
19#include "llvm/CodeGen/RegisterScavenging.h"
20#include "llvm/CodeGen/StackMaps.h"
21#include "llvm/MC/MCContext.h"
22#include "llvm/MC/MCInstBuilder.h"
23#include "llvm/Support/CommandLine.h"
24
25using namespace llvm;
26
27static cl::opt<bool> DisableRelocSched(
28 "loongarch-disable-reloc-sched",
29 cl::desc("Disable scheduling of instructions with target flags"),
30 cl::init(Val: false), cl::Hidden);
31
32#define GET_INSTRINFO_CTOR_DTOR
33#include "LoongArchGenInstrInfo.inc"
34
35LoongArchInstrInfo::LoongArchInstrInfo(const LoongArchSubtarget &STI)
36 : LoongArchGenInstrInfo(STI, RegInfo, LoongArch::ADJCALLSTACKDOWN,
37 LoongArch::ADJCALLSTACKUP),
38 RegInfo(STI.getHwMode()), STI(STI) {}
39
40MCInst LoongArchInstrInfo::getNop() const {
41 return MCInstBuilder(LoongArch::ANDI)
42 .addReg(Reg: LoongArch::R0)
43 .addReg(Reg: LoongArch::R0)
44 .addImm(Val: 0);
45}
46
47void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
48 MachineBasicBlock::iterator MBBI,
49 const DebugLoc &DL, Register DstReg,
50 Register SrcReg, bool KillSrc,
51 bool RenamableDest,
52 bool RenamableSrc) const {
53 if (LoongArch::GPRRegClass.contains(Reg1: DstReg, Reg2: SrcReg)) {
54 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: LoongArch::OR), DestReg: DstReg)
55 .addReg(RegNo: SrcReg, Flags: getKillRegState(B: KillSrc))
56 .addReg(RegNo: LoongArch::R0);
57 return;
58 }
59
60 // VR->VR copies.
61 if (LoongArch::LSX128RegClass.contains(Reg1: DstReg, Reg2: SrcReg)) {
62 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: LoongArch::VORI_B), DestReg: DstReg)
63 .addReg(RegNo: SrcReg, Flags: getKillRegState(B: KillSrc))
64 .addImm(Val: 0);
65 return;
66 }
67
68 // XR->XR copies.
69 if (LoongArch::LASX256RegClass.contains(Reg1: DstReg, Reg2: SrcReg)) {
70 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: LoongArch::XVORI_B), DestReg: DstReg)
71 .addReg(RegNo: SrcReg, Flags: getKillRegState(B: KillSrc))
72 .addImm(Val: 0);
73 return;
74 }
75
76 // GPR->CFR copy.
77 if (LoongArch::CFRRegClass.contains(Reg: DstReg) &&
78 LoongArch::GPRRegClass.contains(Reg: SrcReg)) {
79 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: LoongArch::MOVGR2CF), DestReg: DstReg)
80 .addReg(RegNo: SrcReg, Flags: getKillRegState(B: KillSrc));
81 return;
82 }
83 // CFR->GPR copy.
84 if (LoongArch::GPRRegClass.contains(Reg: DstReg) &&
85 LoongArch::CFRRegClass.contains(Reg: SrcReg)) {
86 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: LoongArch::MOVCF2GR), DestReg: DstReg)
87 .addReg(RegNo: SrcReg, Flags: getKillRegState(B: KillSrc));
88 return;
89 }
90 // CFR->CFR copy.
91 if (LoongArch::CFRRegClass.contains(Reg1: DstReg, Reg2: SrcReg)) {
92 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: LoongArch::PseudoCopyCFR), DestReg: DstReg)
93 .addReg(RegNo: SrcReg, Flags: getKillRegState(B: KillSrc));
94 return;
95 }
96
97 // FPR->FPR copies.
98 unsigned Opc;
99 if (LoongArch::FPR32RegClass.contains(Reg1: DstReg, Reg2: SrcReg)) {
100 Opc = LoongArch::FMOV_S;
101 } else if (LoongArch::FPR64RegClass.contains(Reg1: DstReg, Reg2: SrcReg)) {
102 Opc = LoongArch::FMOV_D;
103 } else if (LoongArch::GPRRegClass.contains(Reg: DstReg) &&
104 LoongArch::FPR32RegClass.contains(Reg: SrcReg)) {
105 // FPR32 -> GPR copies
106 Opc = LoongArch::MOVFR2GR_S;
107 } else if (LoongArch::GPRRegClass.contains(Reg: DstReg) &&
108 LoongArch::FPR64RegClass.contains(Reg: SrcReg)) {
109 // FPR64 -> GPR copies
110 Opc = LoongArch::MOVFR2GR_D;
111 } else {
112 // TODO: support other copies.
113 llvm_unreachable("Impossible reg-to-reg copy");
114 }
115
116 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: Opc), DestReg: DstReg)
117 .addReg(RegNo: SrcReg, Flags: getKillRegState(B: KillSrc));
118}
119
120void LoongArchInstrInfo::storeRegToStackSlot(
121 MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register SrcReg,
122 bool IsKill, int FI, const TargetRegisterClass *RC,
123
124 Register VReg, MachineInstr::MIFlag Flags) const {
125 MachineFunction *MF = MBB.getParent();
126 MachineFrameInfo &MFI = MF->getFrameInfo();
127
128 unsigned Opcode;
129 if (LoongArch::GPRRegClass.hasSubClassEq(RC))
130 Opcode = TRI.getRegSizeInBits(RC: LoongArch::GPRRegClass) == 32
131 ? LoongArch::ST_W
132 : LoongArch::ST_D;
133 else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))
134 Opcode = LoongArch::FST_S;
135 else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))
136 Opcode = LoongArch::FST_D;
137 else if (LoongArch::LSX128RegClass.hasSubClassEq(RC))
138 Opcode = LoongArch::VST;
139 else if (LoongArch::LASX256RegClass.hasSubClassEq(RC))
140 Opcode = LoongArch::XVST;
141 else if (LoongArch::CFRRegClass.hasSubClassEq(RC))
142 Opcode = LoongArch::PseudoST_CFR;
143 else
144 llvm_unreachable("Can't store this register to stack slot");
145
146 MachineMemOperand *MMO = MF->getMachineMemOperand(
147 PtrInfo: MachinePointerInfo::getFixedStack(MF&: *MF, FI), F: MachineMemOperand::MOStore,
148 Size: MFI.getObjectSize(ObjectIdx: FI), BaseAlignment: MFI.getObjectAlign(ObjectIdx: FI));
149
150 BuildMI(BB&: MBB, I, MIMD: DebugLoc(), MCID: get(Opcode))
151 .addReg(RegNo: SrcReg, Flags: getKillRegState(B: IsKill))
152 .addFrameIndex(Idx: FI)
153 .addImm(Val: 0)
154 .addMemOperand(MMO);
155}
156
157void LoongArchInstrInfo::loadRegFromStackSlot(
158 MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register DstReg,
159 int FI, const TargetRegisterClass *RC, Register VReg, unsigned SubReg,
160 MachineInstr::MIFlag Flags) const {
161 MachineFunction *MF = MBB.getParent();
162 MachineFrameInfo &MFI = MF->getFrameInfo();
163 DebugLoc DL;
164 if (I != MBB.end())
165 DL = I->getDebugLoc();
166
167 unsigned Opcode;
168 if (LoongArch::GPRRegClass.hasSubClassEq(RC))
169 Opcode = RegInfo.getRegSizeInBits(RC: LoongArch::GPRRegClass) == 32
170 ? LoongArch::LD_W
171 : LoongArch::LD_D;
172 else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))
173 Opcode = LoongArch::FLD_S;
174 else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))
175 Opcode = LoongArch::FLD_D;
176 else if (LoongArch::LSX128RegClass.hasSubClassEq(RC))
177 Opcode = LoongArch::VLD;
178 else if (LoongArch::LASX256RegClass.hasSubClassEq(RC))
179 Opcode = LoongArch::XVLD;
180 else if (LoongArch::CFRRegClass.hasSubClassEq(RC))
181 Opcode = LoongArch::PseudoLD_CFR;
182 else
183 llvm_unreachable("Can't load this register from stack slot");
184
185 MachineMemOperand *MMO = MF->getMachineMemOperand(
186 PtrInfo: MachinePointerInfo::getFixedStack(MF&: *MF, FI), F: MachineMemOperand::MOLoad,
187 Size: MFI.getObjectSize(ObjectIdx: FI), BaseAlignment: MFI.getObjectAlign(ObjectIdx: FI));
188
189 BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode), DestReg: DstReg)
190 .addFrameIndex(Idx: FI)
191 .addImm(Val: 0)
192 .addMemOperand(MMO);
193}
194
195void LoongArchInstrInfo::movImm(MachineBasicBlock &MBB,
196 MachineBasicBlock::iterator MBBI,
197 const DebugLoc &DL, Register DstReg,
198 uint64_t Val, MachineInstr::MIFlag Flag) const {
199 Register SrcReg = LoongArch::R0;
200
201 if (!STI.is64Bit() && !isInt<32>(x: Val))
202 report_fatal_error(reason: "Should only materialize 32-bit constants for LA32");
203
204 auto Seq = LoongArchMatInt::generateInstSeq(Val);
205 assert(!Seq.empty());
206
207 for (auto &Inst : Seq) {
208 switch (Inst.Opc) {
209 case LoongArch::LU12I_W:
210 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: Inst.Opc), DestReg: DstReg)
211 .addImm(Val: Inst.Imm)
212 .setMIFlag(Flag);
213 break;
214 case LoongArch::ADDI_W:
215 case LoongArch::ORI:
216 case LoongArch::LU32I_D: // "rj" is needed due to InstrInfo pattern
217 case LoongArch::LU52I_D:
218 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: Inst.Opc), DestReg: DstReg)
219 .addReg(RegNo: SrcReg, Flags: RegState::Kill)
220 .addImm(Val: Inst.Imm)
221 .setMIFlag(Flag);
222 break;
223 case LoongArch::BSTRINS_D:
224 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: Inst.Opc), DestReg: DstReg)
225 .addReg(RegNo: SrcReg, Flags: RegState::Kill)
226 .addReg(RegNo: SrcReg, Flags: RegState::Kill)
227 .addImm(Val: Inst.Imm >> 32)
228 .addImm(Val: Inst.Imm & 0xFF)
229 .setMIFlag(Flag);
230 break;
231 default:
232 assert(false && "Unknown insn emitted by LoongArchMatInt");
233 }
234
235 // Only the first instruction has $zero as its source.
236 SrcReg = DstReg;
237 }
238}
239
240unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
241 unsigned Opcode = MI.getOpcode();
242
243 if (Opcode == TargetOpcode::INLINEASM ||
244 Opcode == TargetOpcode::INLINEASM_BR) {
245 const MachineFunction *MF = MI.getParent()->getParent();
246 const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
247 return getInlineAsmLength(Str: MI.getOperand(i: 0).getSymbolName(), MAI: *MAI);
248 }
249
250 unsigned NumBytes = 0;
251 const MCInstrDesc &Desc = MI.getDesc();
252
253 // Size should be preferably set in
254 // llvm/lib/Target/LoongArch/LoongArch*InstrInfo.td (default case).
255 // Specific cases handle instructions of variable sizes.
256 switch (Desc.getOpcode()) {
257 default:
258 return Desc.getSize();
259 case TargetOpcode::STATEPOINT:
260 NumBytes = StatepointOpers(&MI).getNumPatchBytes();
261 assert(NumBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
262 // No patch bytes means a normal call inst (i.e. `bl`) is emitted.
263 if (NumBytes == 0)
264 NumBytes = 4;
265 break;
266 case TargetOpcode::PATCHABLE_FUNCTION_ENTER: {
267 const MachineFunction *MF = MI.getParent()->getParent();
268 const Function &F = MF->getFunction();
269 if (F.hasFnAttribute(Kind: "patchable-function-entry")) {
270 unsigned Num;
271 if (F.getFnAttribute(Kind: "patchable-function-entry")
272 .getValueAsString()
273 .getAsInteger(Radix: 10, Result&: Num))
274 return 0;
275 return Num * 4;
276 }
277 [[fallthrough]];
278 }
279 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
280 case TargetOpcode::PATCHABLE_TAIL_CALL:
281 // Size of xray sled (branch + 11 nops).
282 return 12 * 4;
283 }
284 return NumBytes;
285}
286
287bool LoongArchInstrInfo::isAsCheapAsAMove(const MachineInstr &MI) const {
288 const unsigned Opcode = MI.getOpcode();
289 switch (Opcode) {
290 default:
291 break;
292 case LoongArch::ADDI_D:
293 case LoongArch::ORI:
294 case LoongArch::XORI:
295 return (MI.getOperand(i: 1).isReg() &&
296 MI.getOperand(i: 1).getReg() == LoongArch::R0) ||
297 (MI.getOperand(i: 2).isImm() && MI.getOperand(i: 2).getImm() == 0);
298 }
299 return MI.isAsCheapAsAMove();
300}
301
302MachineBasicBlock *
303LoongArchInstrInfo::getBranchDestBlock(const MachineInstr &MI) const {
304 assert(MI.getDesc().isBranch() && "Unexpected opcode!");
305 // The branch target is always the last operand.
306 return MI.getOperand(i: MI.getNumExplicitOperands() - 1).getMBB();
307}
308
309static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target,
310 SmallVectorImpl<MachineOperand> &Cond) {
311 // Block ends with fall-through condbranch.
312 assert(LastInst.getDesc().isConditionalBranch() &&
313 "Unknown conditional branch");
314 int NumOp = LastInst.getNumExplicitOperands();
315 Target = LastInst.getOperand(i: NumOp - 1).getMBB();
316
317 Cond.push_back(Elt: MachineOperand::CreateImm(Val: LastInst.getOpcode()));
318 for (int i = 0; i < NumOp - 1; i++)
319 Cond.push_back(Elt: LastInst.getOperand(i));
320}
321
322bool LoongArchInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
323 MachineBasicBlock *&TBB,
324 MachineBasicBlock *&FBB,
325 SmallVectorImpl<MachineOperand> &Cond,
326 bool AllowModify) const {
327 TBB = FBB = nullptr;
328 Cond.clear();
329
330 // If the block has no terminators, it just falls into the block after it.
331 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
332 if (I == MBB.end() || !isUnpredicatedTerminator(MI: *I))
333 return false;
334
335 // Count the number of terminators and find the first unconditional or
336 // indirect branch.
337 MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end();
338 int NumTerminators = 0;
339 for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(MI: *J);
340 J++) {
341 NumTerminators++;
342 if (J->getDesc().isUnconditionalBranch() ||
343 J->getDesc().isIndirectBranch()) {
344 FirstUncondOrIndirectBr = J.getReverse();
345 }
346 }
347
348 // If AllowModify is true, we can erase any terminators after
349 // FirstUncondOrIndirectBR.
350 if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) {
351 while (std::next(x: FirstUncondOrIndirectBr) != MBB.end()) {
352 std::next(x: FirstUncondOrIndirectBr)->eraseFromParent();
353 NumTerminators--;
354 }
355 I = FirstUncondOrIndirectBr;
356 }
357
358 // Handle a single unconditional branch.
359 if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) {
360 TBB = getBranchDestBlock(MI: *I);
361 return false;
362 }
363
364 // Handle a single conditional branch.
365 if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) {
366 parseCondBranch(LastInst&: *I, Target&: TBB, Cond);
367 return false;
368 }
369
370 // Handle a conditional branch followed by an unconditional branch.
371 if (NumTerminators == 2 && std::prev(x: I)->getDesc().isConditionalBranch() &&
372 I->getDesc().isUnconditionalBranch()) {
373 parseCondBranch(LastInst&: *std::prev(x: I), Target&: TBB, Cond);
374 FBB = getBranchDestBlock(MI: *I);
375 return false;
376 }
377
378 // Otherwise, we can't handle this.
379 return true;
380}
381
382bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
383 int64_t BrOffset) const {
384 switch (BranchOp) {
385 default:
386 llvm_unreachable("Unknown branch instruction!");
387 case LoongArch::BEQ:
388 case LoongArch::BNE:
389 case LoongArch::BLT:
390 case LoongArch::BGE:
391 case LoongArch::BLTU:
392 case LoongArch::BGEU:
393 return isInt<18>(x: BrOffset);
394 case LoongArch::BEQZ:
395 case LoongArch::BNEZ:
396 case LoongArch::BCEQZ:
397 case LoongArch::BCNEZ:
398 return isInt<23>(x: BrOffset);
399 case LoongArch::B:
400 case LoongArch::PseudoBR:
401 return isInt<28>(x: BrOffset);
402 }
403}
404
405bool LoongArchInstrInfo::isSafeToMove(const MachineInstr &MI,
406 const MachineBasicBlock *MBB,
407 const MachineFunction &MF) const {
408 if (DisableRelocSched) {
409 for (const MachineOperand &MO : MI.operands())
410 if (MO.getTargetFlags())
411 return false;
412 }
413
414 auto MII = MI.getIterator();
415 auto MIE = MBB->end();
416
417 // According to psABI v2.30:
418 //
419 // https://github.com/loongson/la-abi-specs/releases/tag/v2.30
420 //
421 // The following instruction patterns are prohibited from being reordered:
422 //
423 // * pcalau12i $a0, %pc_hi20(s)
424 // addi.d $a1, $zero, %pc_lo12(s)
425 // lu32i.d $a1, %pc64_lo20(s)
426 // lu52i.d $a1, $a1, %pc64_hi12(s)
427 //
428 // * pcalau12i $a0, %got_pc_hi20(s) | %ld_pc_hi20(s) | %gd_pc_hi20(s)
429 // addi.d $a1, $zero, %got_pc_lo12(s)
430 // lu32i.d $a1, %got64_pc_lo20(s)
431 // lu52i.d $a1, $a1, %got64_pc_hi12(s)
432 //
433 // * pcalau12i $a0, %ie_pc_hi20(s)
434 // addi.d $a1, $zero, %ie_pc_lo12(s)
435 // lu32i.d $a1, %ie64_pc_lo20(s)
436 // lu52i.d $a1, $a1, %ie64_pc_hi12(s)
437 //
438 // * pcalau12i $a0, %desc_pc_hi20(s)
439 // addi.d $a1, $zero, %desc_pc_lo12(s)
440 // lu32i.d $a1, %desc64_pc_lo20(s)
441 // lu52i.d $a1, $a1, %desc64_pc_hi12(s)
442 //
443 // For simplicity, only pcalau12i and lu52i.d are marked as scheduling
444 // boundaries, and the instructions between them are guaranteed to be
445 // ordered according to data dependencies.
446 switch (MI.getOpcode()) {
447 case LoongArch::PCALAU12I: {
448 auto AddI = std::next(x: MII);
449 if (AddI == MIE || AddI->getOpcode() != LoongArch::ADDI_D)
450 break;
451 auto Lu32I = std::next(x: AddI);
452 if (Lu32I == MIE || Lu32I->getOpcode() != LoongArch::LU32I_D)
453 break;
454 auto MO0 = MI.getOperand(i: 1).getTargetFlags();
455 auto MO1 = AddI->getOperand(i: 2).getTargetFlags();
456 auto MO2 = Lu32I->getOperand(i: 2).getTargetFlags();
457 if (MO0 == LoongArchII::MO_PCREL_HI && MO1 == LoongArchII::MO_PCREL_LO &&
458 MO2 == LoongArchII::MO_PCREL64_LO)
459 return false;
460 if ((MO0 == LoongArchII::MO_GOT_PC_HI || MO0 == LoongArchII::MO_LD_PC_HI ||
461 MO0 == LoongArchII::MO_GD_PC_HI) &&
462 MO1 == LoongArchII::MO_GOT_PC_LO && MO2 == LoongArchII::MO_GOT_PC64_LO)
463 return false;
464 if (MO0 == LoongArchII::MO_IE_PC_HI && MO1 == LoongArchII::MO_IE_PC_LO &&
465 MO2 == LoongArchII::MO_IE_PC64_LO)
466 return false;
467 if (MO0 == LoongArchII::MO_DESC_PC_HI &&
468 MO1 == LoongArchII::MO_DESC_PC_LO &&
469 MO2 == LoongArchII::MO_DESC64_PC_LO)
470 return false;
471 break;
472 }
473 case LoongArch::LU52I_D: {
474 auto MO = MI.getOperand(i: 2).getTargetFlags();
475 if (MO == LoongArchII::MO_PCREL64_HI || MO == LoongArchII::MO_GOT_PC64_HI ||
476 MO == LoongArchII::MO_IE_PC64_HI || MO == LoongArchII::MO_DESC64_PC_HI)
477 return false;
478 break;
479 }
480 default:
481 break;
482 }
483
484 const auto &STI = MF.getSubtarget<LoongArchSubtarget>();
485 if (STI.hasFeature(Feature: LoongArch::FeatureRelax)) {
486 // When linker relaxation enabled, the following instruction patterns are
487 // prohibited from being reordered:
488 //
489 // * pcalau12i $a0, %pc_hi20(s)
490 // addi.w/d $a0, $a0, %pc_lo12(s)
491 //
492 // * pcalau12i $a0, %got_pc_hi20(s)
493 // ld.w/d $a0, $a0, %got_pc_lo12(s)
494 //
495 // * pcalau12i $a0, %ld_pc_hi20(s) | %gd_pc_hi20(s)
496 // addi.w/d $a0, $a0, %got_pc_lo12(s)
497 //
498 // * pcalau12i $a0, %desc_pc_hi20(s)
499 // addi.w/d $a0, $a0, %desc_pc_lo12(s)
500 // ld.w/d $ra, $a0, %desc_ld(s)
501 // jirl $ra, $ra, %desc_call(s)
502 unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
503 unsigned LdOp = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
504 switch (MI.getOpcode()) {
505 case LoongArch::PCALAU12I: {
506 auto MO0 = LoongArchII::getDirectFlags(MO: MI.getOperand(i: 1));
507 auto SecondOp = std::next(x: MII);
508 if (MO0 == LoongArchII::MO_DESC_PC_HI) {
509 if (SecondOp == MIE || SecondOp->getOpcode() != AddiOp)
510 break;
511 auto Ld = std::next(x: SecondOp);
512 if (Ld == MIE || Ld->getOpcode() != LdOp)
513 break;
514 auto MO1 = LoongArchII::getDirectFlags(MO: SecondOp->getOperand(i: 2));
515 auto MO2 = LoongArchII::getDirectFlags(MO: Ld->getOperand(i: 2));
516 if (MO1 == LoongArchII::MO_DESC_PC_LO && MO2 == LoongArchII::MO_DESC_LD)
517 return false;
518 break;
519 }
520 if (SecondOp == MIE ||
521 (SecondOp->getOpcode() != AddiOp && SecondOp->getOpcode() != LdOp))
522 break;
523 auto MO1 = LoongArchII::getDirectFlags(MO: SecondOp->getOperand(i: 2));
524 if (MO0 == LoongArchII::MO_PCREL_HI && SecondOp->getOpcode() == AddiOp &&
525 MO1 == LoongArchII::MO_PCREL_LO)
526 return false;
527 if (MO0 == LoongArchII::MO_GOT_PC_HI && SecondOp->getOpcode() == LdOp &&
528 MO1 == LoongArchII::MO_GOT_PC_LO)
529 return false;
530 if ((MO0 == LoongArchII::MO_LD_PC_HI ||
531 MO0 == LoongArchII::MO_GD_PC_HI) &&
532 SecondOp->getOpcode() == AddiOp && MO1 == LoongArchII::MO_GOT_PC_LO)
533 return false;
534 break;
535 }
536 case LoongArch::ADDI_W:
537 case LoongArch::ADDI_D: {
538 auto MO = LoongArchII::getDirectFlags(MO: MI.getOperand(i: 2));
539 if (MO == LoongArchII::MO_PCREL_LO || MO == LoongArchII::MO_GOT_PC_LO)
540 return false;
541 break;
542 }
543 case LoongArch::LD_W:
544 case LoongArch::LD_D: {
545 auto MO = LoongArchII::getDirectFlags(MO: MI.getOperand(i: 2));
546 if (MO == LoongArchII::MO_GOT_PC_LO)
547 return false;
548 break;
549 }
550 case LoongArch::PseudoDESC_CALL: {
551 auto MO = LoongArchII::getDirectFlags(MO: MI.getOperand(i: 2));
552 if (MO == LoongArchII::MO_DESC_CALL)
553 return false;
554 break;
555 }
556 default:
557 break;
558 }
559 }
560
561 return true;
562}
563
564bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
565 const MachineBasicBlock *MBB,
566 const MachineFunction &MF) const {
567 if (TargetInstrInfo::isSchedulingBoundary(MI, MBB, MF))
568 return true;
569
570 if (!isSafeToMove(MI, MBB, MF))
571 return true;
572
573 return false;
574}
575
576unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB,
577 int *BytesRemoved) const {
578 if (BytesRemoved)
579 *BytesRemoved = 0;
580 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
581 if (I == MBB.end())
582 return 0;
583
584 if (!I->getDesc().isBranch())
585 return 0;
586
587 // Remove the branch.
588 if (BytesRemoved)
589 *BytesRemoved += getInstSizeInBytes(MI: *I);
590 I->eraseFromParent();
591
592 I = MBB.end();
593
594 if (I == MBB.begin())
595 return 1;
596 --I;
597 if (!I->getDesc().isConditionalBranch())
598 return 1;
599
600 // Remove the branch.
601 if (BytesRemoved)
602 *BytesRemoved += getInstSizeInBytes(MI: *I);
603 I->eraseFromParent();
604 return 2;
605}
606
607// Inserts a branch into the end of the specific MachineBasicBlock, returning
608// the number of instructions inserted.
609unsigned LoongArchInstrInfo::insertBranch(
610 MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
611 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
612 if (BytesAdded)
613 *BytesAdded = 0;
614
615 // Shouldn't be a fall through.
616 assert(TBB && "insertBranch must not be told to insert a fallthrough");
617 assert(Cond.size() <= 3 && Cond.size() != 1 &&
618 "LoongArch branch conditions have at most two components!");
619
620 // Unconditional branch.
621 if (Cond.empty()) {
622 MachineInstr &MI = *BuildMI(BB: &MBB, MIMD: DL, MCID: get(Opcode: LoongArch::PseudoBR)).addMBB(MBB: TBB);
623 if (BytesAdded)
624 *BytesAdded += getInstSizeInBytes(MI);
625 return 1;
626 }
627
628 // Either a one or two-way conditional branch.
629 MachineInstrBuilder MIB = BuildMI(BB: &MBB, MIMD: DL, MCID: get(Opcode: Cond[0].getImm()));
630 for (unsigned i = 1; i < Cond.size(); ++i)
631 MIB.add(MO: Cond[i]);
632 MIB.addMBB(MBB: TBB);
633 if (BytesAdded)
634 *BytesAdded += getInstSizeInBytes(MI: *MIB);
635
636 // One-way conditional branch.
637 if (!FBB)
638 return 1;
639
640 // Two-way conditional branch.
641 MachineInstr &MI = *BuildMI(BB: &MBB, MIMD: DL, MCID: get(Opcode: LoongArch::PseudoBR)).addMBB(MBB: FBB);
642 if (BytesAdded)
643 *BytesAdded += getInstSizeInBytes(MI);
644 return 2;
645}
646
647void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,
648 MachineBasicBlock &DestBB,
649 MachineBasicBlock &RestoreBB,
650 const DebugLoc &DL,
651 int64_t BrOffset,
652 RegScavenger *RS) const {
653 assert(RS && "RegScavenger required for long branching");
654 assert(MBB.empty() &&
655 "new block should be inserted for expanding unconditional branch");
656 assert(MBB.pred_size() == 1);
657
658 MachineFunction *MF = MBB.getParent();
659 MachineRegisterInfo &MRI = MF->getRegInfo();
660 const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
661 LoongArchMachineFunctionInfo *LAFI =
662 MF->getInfo<LoongArchMachineFunctionInfo>();
663 bool Has32S = STI.hasFeature(Feature: LoongArch::Feature32S);
664
665 if (!isInt<32>(x: BrOffset))
666 report_fatal_error(
667 reason: "Branch offsets outside of the signed 32-bit range not supported");
668
669 Register ScratchReg = MRI.createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
670 MachineInstr *PCAI = nullptr;
671 MachineInstr *ADDI = nullptr;
672 auto II = MBB.end();
673 unsigned ADDIOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
674
675 if (Has32S) {
676 PCAI = BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: LoongArch::PCALAU12I), DestReg: ScratchReg)
677 .addMBB(MBB: &DestBB, TargetFlags: LoongArchII::MO_PCREL_HI);
678 ADDI = BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: ADDIOp), DestReg: ScratchReg)
679 .addReg(RegNo: ScratchReg)
680 .addMBB(MBB: &DestBB, TargetFlags: LoongArchII::MO_PCREL_LO);
681 } else {
682 MCSymbol *PCAddSymbol = MF->getContext().createNamedTempSymbol(Name: "pcadd_hi");
683 PCAI = BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: LoongArch::PCADDU12I), DestReg: ScratchReg)
684 .addMBB(MBB: &DestBB, TargetFlags: LoongArchII::MO_PCADD_HI);
685 PCAI->setPreInstrSymbol(MF&: *MF, Symbol: PCAddSymbol);
686 ADDI = BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: ADDIOp), DestReg: ScratchReg)
687 .addReg(RegNo: ScratchReg)
688 .addSym(Sym: PCAddSymbol, TargetFlags: LoongArchII::MO_PCADD_LO);
689 }
690 BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: LoongArch::PseudoBRIND))
691 .addReg(RegNo: ScratchReg, Flags: RegState::Kill)
692 .addImm(Val: 0);
693
694 RS->enterBasicBlockEnd(MBB);
695 Register Scav = RS->scavengeRegisterBackwards(
696 RC: LoongArch::GPRRegClass, To: PCAI->getIterator(), /*RestoreAfter=*/false,
697 /*SPAdj=*/0, /*AllowSpill=*/false);
698 if (Scav != LoongArch::NoRegister)
699 RS->setRegUsed(Reg: Scav);
700 else {
701 // When there is no scavenged register, it needs to specify a register.
702 // Specify t8 register because it won't be used too often.
703 Scav = LoongArch::R20;
704 int FrameIndex = LAFI->getBranchRelaxationSpillFrameIndex();
705 if (FrameIndex == -1)
706 report_fatal_error(reason: "The function size is incorrectly estimated.");
707 storeRegToStackSlot(MBB, I: PCAI, SrcReg: Scav, /*IsKill=*/true, FI: FrameIndex,
708 RC: &LoongArch::GPRRegClass, VReg: Register());
709 TRI->eliminateFrameIndex(MI: std::prev(x: PCAI->getIterator()),
710 /*SpAdj=*/SPAdj: 0, /*FIOperandNum=*/1);
711 PCAI->getOperand(i: 1).setMBB(&RestoreBB);
712 if (Has32S)
713 ADDI->getOperand(i: 2).setMBB(&RestoreBB);
714 loadRegFromStackSlot(MBB&: RestoreBB, I: RestoreBB.end(), DstReg: Scav, FI: FrameIndex,
715 RC: &LoongArch::GPRRegClass, VReg: Register());
716 TRI->eliminateFrameIndex(MI: RestoreBB.back(),
717 /*SpAdj=*/SPAdj: 0, /*FIOperandNum=*/1);
718 }
719 MRI.replaceRegWith(FromReg: ScratchReg, ToReg: Scav);
720 MRI.clearVirtRegs();
721}
722
723static unsigned getOppositeBranchOpc(unsigned Opc) {
724 switch (Opc) {
725 default:
726 llvm_unreachable("Unrecognized conditional branch");
727 case LoongArch::BEQ:
728 return LoongArch::BNE;
729 case LoongArch::BNE:
730 return LoongArch::BEQ;
731 case LoongArch::BEQZ:
732 return LoongArch::BNEZ;
733 case LoongArch::BNEZ:
734 return LoongArch::BEQZ;
735 case LoongArch::BCEQZ:
736 return LoongArch::BCNEZ;
737 case LoongArch::BCNEZ:
738 return LoongArch::BCEQZ;
739 case LoongArch::BLT:
740 return LoongArch::BGE;
741 case LoongArch::BGE:
742 return LoongArch::BLT;
743 case LoongArch::BLTU:
744 return LoongArch::BGEU;
745 case LoongArch::BGEU:
746 return LoongArch::BLTU;
747 }
748}
749
750bool LoongArchInstrInfo::reverseBranchCondition(
751 SmallVectorImpl<MachineOperand> &Cond) const {
752 assert((Cond.size() && Cond.size() <= 3) && "Invalid branch condition!");
753 Cond[0].setImm(getOppositeBranchOpc(Opc: Cond[0].getImm()));
754 return false;
755}
756
757std::pair<unsigned, unsigned>
758LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
759 const unsigned Mask = LoongArchII::MO_DIRECT_FLAG_MASK;
760 return std::make_pair(x: TF & Mask, y: TF & ~Mask);
761}
762
763ArrayRef<std::pair<unsigned, const char *>>
764LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
765 using namespace LoongArchII;
766 // TODO: Add more target flags.
767 static const std::pair<unsigned, const char *> TargetFlags[] = {
768 {MO_CALL, "loongarch-call"},
769 {MO_CALL_PLT, "loongarch-call-plt"},
770 {MO_PCREL_HI, "loongarch-pcrel-hi"},
771 {MO_PCREL_LO, "loongarch-pcrel-lo"},
772 {MO_PCREL64_LO, "loongarch-pcrel64-lo"},
773 {MO_PCREL64_HI, "loongarch-pcrel64-hi"},
774 {MO_GOT_PC_HI, "loongarch-got-pc-hi"},
775 {MO_GOT_PC_LO, "loongarch-got-pc-lo"},
776 {MO_GOT_PC64_LO, "loongarch-got-pc64-lo"},
777 {MO_GOT_PC64_HI, "loongarch-got-pc64-hi"},
778 {MO_LE_HI, "loongarch-le-hi"},
779 {MO_LE_LO, "loongarch-le-lo"},
780 {MO_LE64_LO, "loongarch-le64-lo"},
781 {MO_LE64_HI, "loongarch-le64-hi"},
782 {MO_IE_PC_HI, "loongarch-ie-pc-hi"},
783 {MO_IE_PC_LO, "loongarch-ie-pc-lo"},
784 {MO_IE_PC64_LO, "loongarch-ie-pc64-lo"},
785 {MO_IE_PC64_HI, "loongarch-ie-pc64-hi"},
786 {MO_LD_PC_HI, "loongarch-ld-pc-hi"},
787 {MO_GD_PC_HI, "loongarch-gd-pc-hi"},
788 {MO_CALL30, "loongarch-call30"},
789 {MO_CALL36, "loongarch-call36"},
790 {MO_DESC_PC_HI, "loongarch-desc-pc-hi"},
791 {MO_DESC_PC_LO, "loongarch-desc-pc-lo"},
792 {MO_DESC64_PC_LO, "loongarch-desc64-pc-lo"},
793 {MO_DESC64_PC_HI, "loongarch-desc64-pc-hi"},
794 {MO_DESC_LD, "loongarch-desc-ld"},
795 {MO_DESC_CALL, "loongarch-desc-call"},
796 {MO_LE_HI_R, "loongarch-le-hi-r"},
797 {MO_LE_ADD_R, "loongarch-le-add-r"},
798 {MO_LE_LO_R, "loongarch-le-lo-r"},
799 {MO_PCADD_HI, "loongarch-pcadd-hi"},
800 {MO_PCADD_LO, "loongarch-pcadd-lo"},
801 {MO_GOT_PCADD_HI, "loongarch-got-pcadd-hi"},
802 {MO_GOT_PCADD_LO, "loongarch-got-pcadd-lo"},
803 {MO_IE_PCADD_HI, "loongarch-ie-pcadd-hi"},
804 {MO_IE_PCADD_LO, "loongarch-ie-pcadd-lo"},
805 {MO_LD_PCADD_HI, "loongarch-ld-pcadd-hi"},
806 {MO_LD_PCADD_LO, "loongarch-ld-pcadd-lo"},
807 {MO_GD_PCADD_HI, "loongarch-gd-pcadd-hi"},
808 {MO_GD_PCADD_LO, "loongarch-gd-pcadd-lo"},
809 {MO_DESC_PCADD_HI, "loongarch-pcadd-desc-hi"},
810 {MO_DESC_PCADD_LO, "loongarch-pcadd-desc-lo"}};
811 return ArrayRef(TargetFlags);
812}
813
814ArrayRef<std::pair<unsigned, const char *>>
815LoongArchInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
816 using namespace LoongArchII;
817 static const std::pair<unsigned, const char *> TargetFlags[] = {
818 {MO_RELAX, "loongarch-relax"}};
819 return ArrayRef(TargetFlags);
820}
821
822bool LoongArchInstrInfo::canFoldIntoAddrMode(const MachineInstr &MemI,
823 Register Reg,
824 const MachineInstr &AddrI,
825 ExtAddrMode &AM) const {
826 enum MemIOffsetType {
827 Imm14Shift2,
828 Imm12,
829 Imm11Shift1,
830 Imm10Shift2,
831 Imm9Shift3,
832 Imm8,
833 Imm8Shift1,
834 Imm8Shift2,
835 Imm8Shift3
836 };
837
838 MemIOffsetType OT;
839 switch (MemI.getOpcode()) {
840 default:
841 return false;
842 case LoongArch::LDPTR_W:
843 case LoongArch::LDPTR_D:
844 case LoongArch::STPTR_W:
845 case LoongArch::STPTR_D:
846 OT = Imm14Shift2;
847 break;
848 case LoongArch::LD_B:
849 case LoongArch::LD_H:
850 case LoongArch::LD_W:
851 case LoongArch::LD_D:
852 case LoongArch::LD_BU:
853 case LoongArch::LD_HU:
854 case LoongArch::LD_WU:
855 case LoongArch::ST_B:
856 case LoongArch::ST_H:
857 case LoongArch::ST_W:
858 case LoongArch::ST_D:
859 case LoongArch::FLD_S:
860 case LoongArch::FLD_D:
861 case LoongArch::FST_S:
862 case LoongArch::FST_D:
863 case LoongArch::VLD:
864 case LoongArch::VST:
865 case LoongArch::XVLD:
866 case LoongArch::XVST:
867 case LoongArch::VLDREPL_B:
868 case LoongArch::XVLDREPL_B:
869 OT = Imm12;
870 break;
871 case LoongArch::VLDREPL_H:
872 case LoongArch::XVLDREPL_H:
873 OT = Imm11Shift1;
874 break;
875 case LoongArch::VLDREPL_W:
876 case LoongArch::XVLDREPL_W:
877 OT = Imm10Shift2;
878 break;
879 case LoongArch::VLDREPL_D:
880 case LoongArch::XVLDREPL_D:
881 OT = Imm9Shift3;
882 break;
883 case LoongArch::VSTELM_B:
884 case LoongArch::XVSTELM_B:
885 OT = Imm8;
886 break;
887 case LoongArch::VSTELM_H:
888 case LoongArch::XVSTELM_H:
889 OT = Imm8Shift1;
890 break;
891 case LoongArch::VSTELM_W:
892 case LoongArch::XVSTELM_W:
893 OT = Imm8Shift2;
894 break;
895 case LoongArch::VSTELM_D:
896 case LoongArch::XVSTELM_D:
897 OT = Imm8Shift3;
898 break;
899 }
900
901 if (MemI.getOperand(i: 0).getReg() == Reg)
902 return false;
903
904 if ((AddrI.getOpcode() != LoongArch::ADDI_W &&
905 AddrI.getOpcode() != LoongArch::ADDI_D) ||
906 !AddrI.getOperand(i: 1).isReg() || !AddrI.getOperand(i: 2).isImm())
907 return false;
908
909 int64_t OldOffset = MemI.getOperand(i: 2).getImm();
910 int64_t Disp = AddrI.getOperand(i: 2).getImm();
911 int64_t NewOffset = OldOffset + Disp;
912 if (!STI.is64Bit())
913 NewOffset = SignExtend64<32>(x: NewOffset);
914
915 if (!(OT == Imm14Shift2 && isShiftedInt<14, 2>(x: NewOffset) && STI.hasUAL()) &&
916 !(OT == Imm12 && isInt<12>(x: NewOffset)) &&
917 !(OT == Imm11Shift1 && isShiftedInt<11, 1>(x: NewOffset)) &&
918 !(OT == Imm10Shift2 && isShiftedInt<10, 2>(x: NewOffset)) &&
919 !(OT == Imm9Shift3 && isShiftedInt<9, 3>(x: NewOffset)) &&
920 !(OT == Imm8 && isInt<8>(x: NewOffset)) &&
921 !(OT == Imm8Shift1 && isShiftedInt<8, 1>(x: NewOffset)) &&
922 !(OT == Imm8Shift2 && isShiftedInt<8, 2>(x: NewOffset)) &&
923 !(OT == Imm8Shift3 && isShiftedInt<8, 3>(x: NewOffset)))
924 return false;
925
926 AM.BaseReg = AddrI.getOperand(i: 1).getReg();
927 AM.ScaledReg = 0;
928 AM.Scale = 0;
929 AM.Displacement = NewOffset;
930 AM.Form = ExtAddrMode::Formula::Basic;
931 return true;
932}
933
934MachineInstr *
935LoongArchInstrInfo::emitLdStWithAddr(MachineInstr &MemI,
936 const ExtAddrMode &AM) const {
937 const DebugLoc &DL = MemI.getDebugLoc();
938 MachineBasicBlock &MBB = *MemI.getParent();
939
940 assert(AM.ScaledReg == 0 && AM.Scale == 0 &&
941 "Addressing mode not supported for folding");
942
943 unsigned MemIOp = MemI.getOpcode();
944 switch (MemIOp) {
945 default:
946 return BuildMI(BB&: MBB, I&: MemI, MIMD: DL, MCID: get(Opcode: MemIOp))
947 .addReg(RegNo: MemI.getOperand(i: 0).getReg(), Flags: getDefRegState(B: MemI.mayLoad()))
948 .addReg(RegNo: AM.BaseReg)
949 .addImm(Val: AM.Displacement)
950 .setMemRefs(MemI.memoperands())
951 .setMIFlags(MemI.getFlags());
952 case LoongArch::VSTELM_B:
953 case LoongArch::VSTELM_H:
954 case LoongArch::VSTELM_W:
955 case LoongArch::VSTELM_D:
956 case LoongArch::XVSTELM_B:
957 case LoongArch::XVSTELM_H:
958 case LoongArch::XVSTELM_W:
959 case LoongArch::XVSTELM_D:
960 return BuildMI(BB&: MBB, I&: MemI, MIMD: DL, MCID: get(Opcode: MemIOp))
961 .addReg(RegNo: MemI.getOperand(i: 0).getReg())
962 .addReg(RegNo: AM.BaseReg)
963 .addImm(Val: AM.Displacement)
964 .addImm(Val: MemI.getOperand(i: 3).getImm())
965 .setMemRefs(MemI.memoperands())
966 .setMIFlags(MemI.getFlags());
967 }
968}
969
970// Returns true if this is the sext.w pattern, addi.w rd, rs, 0.
971bool LoongArch::isSEXT_W(const MachineInstr &MI) {
972 return MI.getOpcode() == LoongArch::ADDI_W && MI.getOperand(i: 1).isReg() &&
973 MI.getOperand(i: 2).isImm() && MI.getOperand(i: 2).getImm() == 0;
974}
975