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
195Register LoongArchInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
196 int &FrameIndex) const {
197 TypeSize Dummy = TypeSize::getZero();
198 return isLoadFromStackSlot(MI, FrameIndex, MemBytes&: Dummy);
199}
200
201Register LoongArchInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
202 int &FrameIndex,
203 TypeSize &MemBytes) const {
204 switch (MI.getOpcode()) {
205 default:
206 return Register();
207 case LoongArch::LD_W:
208 case LoongArch::FLD_S:
209 MemBytes = TypeSize::getFixed(ExactSize: 4);
210 break;
211 case LoongArch::LD_D:
212 case LoongArch::FLD_D:
213 MemBytes = TypeSize::getFixed(ExactSize: 8);
214 break;
215 case LoongArch::VLD:
216 MemBytes = TypeSize::getFixed(ExactSize: 16);
217 break;
218 case LoongArch::XVLD:
219 MemBytes = TypeSize::getFixed(ExactSize: 32);
220 break;
221 }
222
223 if ((MI.getOperand(i: 1).isFI()) && // is a stack slot
224 (MI.getOperand(i: 2).isImm()) && // the imm is zero
225 (MI.getOperand(i: 2).getImm() == 0)) {
226 FrameIndex = MI.getOperand(i: 1).getIndex();
227 return MI.getOperand(i: 0).getReg();
228 }
229
230 return Register();
231}
232
233Register LoongArchInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
234 int &FrameIndex) const {
235 TypeSize Dummy = TypeSize::getZero();
236 return isStoreToStackSlot(MI, FrameIndex, MemBytes&: Dummy);
237}
238
239Register LoongArchInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
240 int &FrameIndex,
241 TypeSize &MemBytes) const {
242 switch (MI.getOpcode()) {
243 default:
244 return Register();
245 case LoongArch::ST_W:
246 case LoongArch::FST_S:
247 MemBytes = TypeSize::getFixed(ExactSize: 4);
248 break;
249 case LoongArch::ST_D:
250 case LoongArch::FST_D:
251 MemBytes = TypeSize::getFixed(ExactSize: 8);
252 break;
253 case LoongArch::VST:
254 MemBytes = TypeSize::getFixed(ExactSize: 16);
255 break;
256 case LoongArch::XVST:
257 MemBytes = TypeSize::getFixed(ExactSize: 32);
258 break;
259 }
260
261 if ((MI.getOperand(i: 1).isFI()) && // is a stack slot
262 (MI.getOperand(i: 2).isImm()) && // the imm is zero
263 (MI.getOperand(i: 2).getImm() == 0)) {
264 FrameIndex = MI.getOperand(i: 1).getIndex();
265 return MI.getOperand(i: 0).getReg();
266 }
267
268 return Register();
269}
270
271void LoongArchInstrInfo::movImm(MachineBasicBlock &MBB,
272 MachineBasicBlock::iterator MBBI,
273 const DebugLoc &DL, Register DstReg,
274 uint64_t Val, MachineInstr::MIFlag Flag) const {
275 Register SrcReg = LoongArch::R0;
276
277 if (!STI.is64Bit() && !isInt<32>(x: Val))
278 report_fatal_error(reason: "Should only materialize 32-bit constants for LA32");
279
280 auto Seq = LoongArchMatInt::generateInstSeq(Val);
281 assert(!Seq.empty());
282
283 for (auto &Inst : Seq) {
284 switch (Inst.Opc) {
285 case LoongArch::LU12I_W:
286 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: Inst.Opc), DestReg: DstReg)
287 .addImm(Val: Inst.Imm)
288 .setMIFlag(Flag);
289 break;
290 case LoongArch::ADDI_W:
291 case LoongArch::ORI:
292 case LoongArch::LU32I_D: // "rj" is needed due to InstrInfo pattern
293 case LoongArch::LU52I_D:
294 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: Inst.Opc), DestReg: DstReg)
295 .addReg(RegNo: SrcReg, Flags: RegState::Kill)
296 .addImm(Val: Inst.Imm)
297 .setMIFlag(Flag);
298 break;
299 case LoongArch::BSTRINS_D:
300 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: Inst.Opc), DestReg: DstReg)
301 .addReg(RegNo: SrcReg, Flags: RegState::Kill)
302 .addReg(RegNo: SrcReg, Flags: RegState::Kill)
303 .addImm(Val: Inst.Imm >> 32)
304 .addImm(Val: Inst.Imm & 0xFF)
305 .setMIFlag(Flag);
306 break;
307 default:
308 assert(false && "Unknown insn emitted by LoongArchMatInt");
309 }
310
311 // Only the first instruction has $zero as its source.
312 SrcReg = DstReg;
313 }
314}
315
316unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
317 unsigned Opcode = MI.getOpcode();
318
319 if (Opcode == TargetOpcode::INLINEASM ||
320 Opcode == TargetOpcode::INLINEASM_BR) {
321 const MachineFunction *MF = MI.getParent()->getParent();
322 const MCAsmInfo &MAI = MF->getTarget().getMCAsmInfo();
323 return getInlineAsmLength(Str: MI.getOperand(i: 0).getSymbolName(), MAI);
324 }
325
326 unsigned NumBytes = 0;
327 const MCInstrDesc &Desc = MI.getDesc();
328
329 // Size should be preferably set in
330 // llvm/lib/Target/LoongArch/LoongArch*InstrInfo.td (default case).
331 // Specific cases handle instructions of variable sizes.
332 switch (Desc.getOpcode()) {
333 default:
334 return Desc.getSize();
335 case TargetOpcode::STATEPOINT:
336 NumBytes = StatepointOpers(&MI).getNumPatchBytes();
337 assert(NumBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
338 // No patch bytes means a normal call inst (i.e. `bl`) is emitted.
339 if (NumBytes == 0)
340 NumBytes = 4;
341 break;
342 case TargetOpcode::PATCHABLE_FUNCTION_ENTER: {
343 const MachineFunction *MF = MI.getParent()->getParent();
344 const Function &F = MF->getFunction();
345 if (F.hasFnAttribute(Kind: "patchable-function-entry")) {
346 unsigned Num =
347 F.getFnAttributeAsParsedInteger(Kind: "patchable-function-entry");
348 return Num * 4;
349 }
350 [[fallthrough]];
351 }
352 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
353 case TargetOpcode::PATCHABLE_TAIL_CALL:
354 // Size of xray sled (branch + 11 nops).
355 return 12 * 4;
356 case TargetOpcode::BUNDLE:
357 return getInstBundleSize(MI);
358 }
359 return NumBytes;
360}
361
362bool LoongArchInstrInfo::isAsCheapAsAMove(const MachineInstr &MI) const {
363 const unsigned Opcode = MI.getOpcode();
364 switch (Opcode) {
365 default:
366 break;
367 case LoongArch::ADDI_D:
368 case LoongArch::ORI:
369 case LoongArch::XORI:
370 return (MI.getOperand(i: 1).isReg() &&
371 MI.getOperand(i: 1).getReg() == LoongArch::R0) ||
372 (MI.getOperand(i: 2).isImm() && MI.getOperand(i: 2).getImm() == 0);
373 }
374 return MI.isAsCheapAsAMove();
375}
376
377static bool isJumpTableLoad(const MachineInstr &MI) {
378 return any_of(Range: MI.memoperands(), P: [](const MachineMemOperand *MMO) {
379 const PseudoSourceValue *PSV = MMO->getPseudoValue();
380 return PSV && PSV->isJumpTable();
381 });
382}
383
384// Return the index of the jump table whose address
385// (or an entry loaded from it) is held in Reg, or -1.
386static int getJumpTableIndexFromReg(const MachineRegisterInfo &MRI,
387 Register Reg) {
388 if (!Reg.isVirtual())
389 return -1;
390 const MachineInstr *MI = MRI.getUniqueVRegDef(Reg);
391 if (!MI)
392 return -1;
393
394 int JTI;
395 switch (MI->getOpcode()) {
396 case LoongArch::ADDI_D:
397 case LoongArch::ADDI_W:
398 case LoongArch::PseudoLA_PCREL:
399 for (const MachineOperand &MO : MI->operands())
400 if (MO.isJTI())
401 return MO.getIndex();
402 return -1;
403 case LoongArch::LDX_D:
404 case LoongArch::LDX_W:
405 // Normally, NonFIBaseAddr is corresponding to register $rj.
406 JTI = getJumpTableIndexFromReg(MRI, Reg: MI->getOperand(i: 1).getReg());
407 if (JTI >= 0)
408 return JTI;
409 JTI = getJumpTableIndexFromReg(MRI, Reg: MI->getOperand(i: 2).getReg());
410 if (JTI >= 0)
411 return JTI;
412 break;
413 default:
414 return -1;
415 }
416
417 return -1;
418}
419
420// LA32 do not support register offset load instrunctions (LDX),
421// so add another layer to get jump table address.
422static int getJumpTableIndexFromLoadAddr(const MachineRegisterInfo &MRI,
423 Register Reg) {
424 if (!Reg.isVirtual())
425 return -1;
426 const MachineInstr *MI = MRI.getUniqueVRegDef(Reg);
427 if (!MI)
428 return -1;
429
430 int JTI;
431 switch (MI->getOpcode()) {
432 case LoongArch::ADD_W:
433 JTI = getJumpTableIndexFromReg(MRI, Reg: MI->getOperand(i: 1).getReg());
434 if (JTI >= 0)
435 return JTI;
436 JTI = getJumpTableIndexFromReg(MRI, Reg: MI->getOperand(i: 2).getReg());
437 if (JTI >= 0)
438 return JTI;
439 break;
440 case LoongArch::ALSL_W:
441 // For la32s, address could only stores in register $rk.
442 return getJumpTableIndexFromReg(MRI, Reg: MI->getOperand(i: 2).getReg());
443 }
444
445 return -1;
446}
447
448// Recursively search for %jump-table.N starting from PseudoBRIND,
449// and return the index of &jump-table.N
450//
451// One common jump table:
452//
453// %base = PseudoLA_PCREL %jump-table.N
454// %off = LDX_W %base, %index
455// %tgt = ADD_D %base, %off
456// %PseudoBRIND %tgt, 0
457//
458int LoongArchInstrInfo::getJumpTableIndex(const MachineInstr &MI) const {
459 if (MI.getOpcode() != LoongArch::PseudoBRIND)
460 return -1;
461
462 Register Reg = MI.getOperand(i: 0).getReg();
463 if (!Reg.isVirtual())
464 return -1;
465
466 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
467 MachineInstr *Def = MRI.getUniqueVRegDef(Reg);
468 if (!Def)
469 return -1;
470
471 int JTI;
472 switch (Def->getOpcode()) {
473 case LoongArch::LD_W:
474 if (!isJumpTableLoad(MI: *Def))
475 return -1;
476
477 JTI = getJumpTableIndexFromLoadAddr(MRI, Reg: Def->getOperand(i: 1).getReg());
478 if (JTI >= 0)
479 return JTI;
480 break;
481 case LoongArch::ADD_D:
482 case LoongArch::ADD_W:
483 JTI = getJumpTableIndexFromReg(MRI, Reg: Def->getOperand(i: 1).getReg());
484 if (JTI >= 0)
485 return JTI;
486 return getJumpTableIndexFromReg(MRI, Reg: Def->getOperand(i: 2).getReg());
487 }
488
489 return getJumpTableIndexFromReg(MRI, Reg);
490}
491
492MachineBasicBlock *
493LoongArchInstrInfo::getBranchDestBlock(const MachineInstr &MI) const {
494 assert(MI.getDesc().isBranch() && "Unexpected opcode!");
495 // The branch target is always the last operand.
496 return MI.getOperand(i: MI.getNumExplicitOperands() - 1).getMBB();
497}
498
499static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target,
500 SmallVectorImpl<MachineOperand> &Cond) {
501 // Block ends with fall-through condbranch.
502 assert(LastInst.getDesc().isConditionalBranch() &&
503 "Unknown conditional branch");
504 int NumOp = LastInst.getNumExplicitOperands();
505 Target = LastInst.getOperand(i: NumOp - 1).getMBB();
506
507 Cond.push_back(Elt: MachineOperand::CreateImm(Val: LastInst.getOpcode()));
508 for (int i = 0; i < NumOp - 1; i++)
509 Cond.push_back(Elt: LastInst.getOperand(i));
510}
511
512bool LoongArchInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
513 MachineBasicBlock *&TBB,
514 MachineBasicBlock *&FBB,
515 SmallVectorImpl<MachineOperand> &Cond,
516 bool AllowModify) const {
517 TBB = FBB = nullptr;
518 Cond.clear();
519
520 // If the block has no terminators, it just falls into the block after it.
521 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
522 if (I == MBB.end() || !isUnpredicatedTerminator(MI: *I))
523 return false;
524
525 // Count the number of terminators and find the first unconditional or
526 // indirect branch.
527 MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end();
528 int NumTerminators = 0;
529 for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(MI: *J);
530 J++) {
531 NumTerminators++;
532 if (J->getDesc().isUnconditionalBranch() ||
533 J->getDesc().isIndirectBranch()) {
534 FirstUncondOrIndirectBr = J.getReverse();
535 }
536 }
537
538 // If AllowModify is true, we can erase any terminators after
539 // FirstUncondOrIndirectBR.
540 if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) {
541 while (std::next(x: FirstUncondOrIndirectBr) != MBB.end()) {
542 std::next(x: FirstUncondOrIndirectBr)->eraseFromParent();
543 NumTerminators--;
544 }
545 I = FirstUncondOrIndirectBr;
546 }
547
548 // Handle a single unconditional branch.
549 if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) {
550 TBB = getBranchDestBlock(MI: *I);
551 return false;
552 }
553
554 // Handle a single conditional branch.
555 if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) {
556 parseCondBranch(LastInst&: *I, Target&: TBB, Cond);
557 return false;
558 }
559
560 // Handle a conditional branch followed by an unconditional branch.
561 if (NumTerminators == 2 && std::prev(x: I)->getDesc().isConditionalBranch() &&
562 I->getDesc().isUnconditionalBranch()) {
563 parseCondBranch(LastInst&: *std::prev(x: I), Target&: TBB, Cond);
564 FBB = getBranchDestBlock(MI: *I);
565 return false;
566 }
567
568 // Otherwise, we can't handle this.
569 return true;
570}
571
572bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
573 int64_t BrOffset) const {
574 switch (BranchOp) {
575 default:
576 llvm_unreachable("Unknown branch instruction!");
577 case LoongArch::BEQ:
578 case LoongArch::BNE:
579 case LoongArch::BLT:
580 case LoongArch::BGE:
581 case LoongArch::BLTU:
582 case LoongArch::BGEU:
583 return isInt<18>(x: BrOffset);
584 case LoongArch::BEQZ:
585 case LoongArch::BNEZ:
586 case LoongArch::BCEQZ:
587 case LoongArch::BCNEZ:
588 return isInt<23>(x: BrOffset);
589 case LoongArch::B:
590 case LoongArch::PseudoBR:
591 return isInt<28>(x: BrOffset);
592 }
593}
594
595bool LoongArchInstrInfo::isSafeToMove(const MachineInstr &MI,
596 const MachineBasicBlock *MBB,
597 const MachineFunction &MF) const {
598 if (DisableRelocSched) {
599 for (const MachineOperand &MO : MI.operands())
600 if (MO.getTargetFlags())
601 return false;
602 }
603
604 auto MII = MI.getIterator();
605 auto MIE = MBB->end();
606
607 // According to psABI v2.30:
608 //
609 // https://github.com/loongson/la-abi-specs/releases/tag/v2.30
610 //
611 // The following instruction patterns are prohibited from being reordered:
612 //
613 // * pcalau12i $a0, %pc_hi20(s)
614 // addi.d $a1, $zero, %pc_lo12(s)
615 // lu32i.d $a1, %pc64_lo20(s)
616 // lu52i.d $a1, $a1, %pc64_hi12(s)
617 //
618 // * pcalau12i $a0, %got_pc_hi20(s) | %ld_pc_hi20(s) | %gd_pc_hi20(s)
619 // addi.d $a1, $zero, %got_pc_lo12(s)
620 // lu32i.d $a1, %got64_pc_lo20(s)
621 // lu52i.d $a1, $a1, %got64_pc_hi12(s)
622 //
623 // * pcalau12i $a0, %ie_pc_hi20(s)
624 // addi.d $a1, $zero, %ie_pc_lo12(s)
625 // lu32i.d $a1, %ie64_pc_lo20(s)
626 // lu52i.d $a1, $a1, %ie64_pc_hi12(s)
627 //
628 // * pcalau12i $a0, %desc_pc_hi20(s)
629 // addi.d $a1, $zero, %desc_pc_lo12(s)
630 // lu32i.d $a1, %desc64_pc_lo20(s)
631 // lu52i.d $a1, $a1, %desc64_pc_hi12(s)
632 //
633 // For simplicity, only pcalau12i and lu52i.d are marked as scheduling
634 // boundaries, and the instructions between them are guaranteed to be
635 // ordered according to data dependencies.
636 switch (MI.getOpcode()) {
637 case LoongArch::PCALAU12I: {
638 auto AddI = std::next(x: MII);
639 if (AddI == MIE || AddI->getOpcode() != LoongArch::ADDI_D)
640 break;
641 auto Lu32I = std::next(x: AddI);
642 if (Lu32I == MIE || Lu32I->getOpcode() != LoongArch::LU32I_D)
643 break;
644 auto MO0 = MI.getOperand(i: 1).getTargetFlags();
645 auto MO1 = AddI->getOperand(i: 2).getTargetFlags();
646 auto MO2 = Lu32I->getOperand(i: 2).getTargetFlags();
647 if (MO0 == LoongArchII::MO_PCREL_HI && MO1 == LoongArchII::MO_PCREL_LO &&
648 MO2 == LoongArchII::MO_PCREL64_LO)
649 return false;
650 if ((MO0 == LoongArchII::MO_GOT_PC_HI || MO0 == LoongArchII::MO_LD_PC_HI ||
651 MO0 == LoongArchII::MO_GD_PC_HI) &&
652 MO1 == LoongArchII::MO_GOT_PC_LO && MO2 == LoongArchII::MO_GOT_PC64_LO)
653 return false;
654 if (MO0 == LoongArchII::MO_IE_PC_HI && MO1 == LoongArchII::MO_IE_PC_LO &&
655 MO2 == LoongArchII::MO_IE_PC64_LO)
656 return false;
657 if (MO0 == LoongArchII::MO_DESC_PC_HI &&
658 MO1 == LoongArchII::MO_DESC_PC_LO &&
659 MO2 == LoongArchII::MO_DESC64_PC_LO)
660 return false;
661 break;
662 }
663 case LoongArch::LU52I_D: {
664 auto MO = MI.getOperand(i: 2).getTargetFlags();
665 if (MO == LoongArchII::MO_PCREL64_HI || MO == LoongArchII::MO_GOT_PC64_HI ||
666 MO == LoongArchII::MO_IE_PC64_HI || MO == LoongArchII::MO_DESC64_PC_HI)
667 return false;
668 break;
669 }
670 default:
671 break;
672 }
673
674 const auto &STI = MF.getSubtarget<LoongArchSubtarget>();
675 if (STI.hasFeature(Feature: LoongArch::FeatureRelax)) {
676 // When linker relaxation enabled, the following instruction patterns are
677 // prohibited from being reordered:
678 //
679 // * pcalau12i $a0, %pc_hi20(s)
680 // addi.w/d $a0, $a0, %pc_lo12(s)
681 //
682 // * pcalau12i $a0, %got_pc_hi20(s)
683 // ld.w/d $a0, $a0, %got_pc_lo12(s)
684 //
685 // * pcalau12i $a0, %ld_pc_hi20(s) | %gd_pc_hi20(s)
686 // addi.w/d $a0, $a0, %got_pc_lo12(s)
687 //
688 // * pcalau12i $a0, %desc_pc_hi20(s)
689 // addi.w/d $a0, $a0, %desc_pc_lo12(s)
690 // ld.w/d $ra, $a0, %desc_ld(s)
691 // jirl $ra, $ra, %desc_call(s)
692 unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
693 unsigned LdOp = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
694 switch (MI.getOpcode()) {
695 case LoongArch::PCALAU12I: {
696 auto MO0 = LoongArchII::getDirectFlags(MO: MI.getOperand(i: 1));
697 auto SecondOp = std::next(x: MII);
698 if (MO0 == LoongArchII::MO_DESC_PC_HI) {
699 if (SecondOp == MIE || SecondOp->getOpcode() != AddiOp)
700 break;
701 auto Ld = std::next(x: SecondOp);
702 if (Ld == MIE || Ld->getOpcode() != LdOp)
703 break;
704 auto MO1 = LoongArchII::getDirectFlags(MO: SecondOp->getOperand(i: 2));
705 auto MO2 = LoongArchII::getDirectFlags(MO: Ld->getOperand(i: 2));
706 if (MO1 == LoongArchII::MO_DESC_PC_LO && MO2 == LoongArchII::MO_DESC_LD)
707 return false;
708 break;
709 }
710 if (SecondOp == MIE ||
711 (SecondOp->getOpcode() != AddiOp && SecondOp->getOpcode() != LdOp))
712 break;
713 auto MO1 = LoongArchII::getDirectFlags(MO: SecondOp->getOperand(i: 2));
714 if (MO0 == LoongArchII::MO_PCREL_HI && SecondOp->getOpcode() == AddiOp &&
715 MO1 == LoongArchII::MO_PCREL_LO)
716 return false;
717 if (MO0 == LoongArchII::MO_GOT_PC_HI && SecondOp->getOpcode() == LdOp &&
718 MO1 == LoongArchII::MO_GOT_PC_LO)
719 return false;
720 if ((MO0 == LoongArchII::MO_LD_PC_HI ||
721 MO0 == LoongArchII::MO_GD_PC_HI) &&
722 SecondOp->getOpcode() == AddiOp && MO1 == LoongArchII::MO_GOT_PC_LO)
723 return false;
724 break;
725 }
726 case LoongArch::ADDI_W:
727 case LoongArch::ADDI_D: {
728 auto MO = LoongArchII::getDirectFlags(MO: MI.getOperand(i: 2));
729 if (MO == LoongArchII::MO_PCREL_LO || MO == LoongArchII::MO_GOT_PC_LO)
730 return false;
731 break;
732 }
733 case LoongArch::LD_W:
734 case LoongArch::LD_D: {
735 auto MO = LoongArchII::getDirectFlags(MO: MI.getOperand(i: 2));
736 if (MO == LoongArchII::MO_GOT_PC_LO)
737 return false;
738 break;
739 }
740 case LoongArch::PseudoDESC_CALL: {
741 auto MO = LoongArchII::getDirectFlags(MO: MI.getOperand(i: 2));
742 if (MO == LoongArchII::MO_DESC_CALL)
743 return false;
744 break;
745 }
746 default:
747 break;
748 }
749 }
750
751 return true;
752}
753
754bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
755 const MachineBasicBlock *MBB,
756 const MachineFunction &MF) const {
757 if (TargetInstrInfo::isSchedulingBoundary(MI, MBB, MF))
758 return true;
759
760 if (!isSafeToMove(MI, MBB, MF))
761 return true;
762
763 return false;
764}
765
766unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB,
767 int *BytesRemoved) const {
768 if (BytesRemoved)
769 *BytesRemoved = 0;
770 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
771 if (I == MBB.end())
772 return 0;
773
774 if (!I->getDesc().isBranch())
775 return 0;
776
777 // Remove the branch.
778 if (BytesRemoved)
779 *BytesRemoved += getInstSizeInBytes(MI: *I);
780 I->eraseFromParent();
781
782 I = MBB.end();
783
784 if (I == MBB.begin())
785 return 1;
786 --I;
787 if (!I->getDesc().isConditionalBranch())
788 return 1;
789
790 // Remove the branch.
791 if (BytesRemoved)
792 *BytesRemoved += getInstSizeInBytes(MI: *I);
793 I->eraseFromParent();
794 return 2;
795}
796
797// Inserts a branch into the end of the specific MachineBasicBlock, returning
798// the number of instructions inserted.
799unsigned LoongArchInstrInfo::insertBranch(
800 MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
801 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
802 if (BytesAdded)
803 *BytesAdded = 0;
804
805 // Shouldn't be a fall through.
806 assert(TBB && "insertBranch must not be told to insert a fallthrough");
807 assert(Cond.size() <= 3 && Cond.size() != 1 &&
808 "LoongArch branch conditions have at most two components!");
809
810 // Unconditional branch.
811 if (Cond.empty()) {
812 MachineInstr &MI = *BuildMI(BB: &MBB, MIMD: DL, MCID: get(Opcode: LoongArch::PseudoBR)).addMBB(MBB: TBB);
813 if (BytesAdded)
814 *BytesAdded += getInstSizeInBytes(MI);
815 return 1;
816 }
817
818 // Either a one or two-way conditional branch.
819 MachineInstrBuilder MIB = BuildMI(BB: &MBB, MIMD: DL, MCID: get(Opcode: Cond[0].getImm()));
820 for (unsigned i = 1; i < Cond.size(); ++i)
821 MIB.add(MO: Cond[i]);
822 MIB.addMBB(MBB: TBB);
823 if (BytesAdded)
824 *BytesAdded += getInstSizeInBytes(MI: *MIB);
825
826 // One-way conditional branch.
827 if (!FBB)
828 return 1;
829
830 // Two-way conditional branch.
831 MachineInstr &MI = *BuildMI(BB: &MBB, MIMD: DL, MCID: get(Opcode: LoongArch::PseudoBR)).addMBB(MBB: FBB);
832 if (BytesAdded)
833 *BytesAdded += getInstSizeInBytes(MI);
834 return 2;
835}
836
837void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,
838 MachineBasicBlock &DestBB,
839 MachineBasicBlock &RestoreBB,
840 const DebugLoc &DL,
841 int64_t BrOffset,
842 RegScavenger *RS) const {
843 assert(RS && "RegScavenger required for long branching");
844 assert(MBB.empty() &&
845 "new block should be inserted for expanding unconditional branch");
846 assert(MBB.pred_size() == 1);
847
848 MachineFunction *MF = MBB.getParent();
849 MachineRegisterInfo &MRI = MF->getRegInfo();
850 const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
851 LoongArchMachineFunctionInfo *LAFI =
852 MF->getInfo<LoongArchMachineFunctionInfo>();
853 bool Has32S = STI.hasFeature(Feature: LoongArch::Feature32S);
854
855 if (!isInt<32>(x: BrOffset))
856 report_fatal_error(
857 reason: "Branch offsets outside of the signed 32-bit range not supported");
858
859 Register ScratchReg = MRI.createVirtualRegister(RegClass: &LoongArch::GPRRegClass);
860 MachineInstr *PCAI = nullptr;
861 MachineInstr *ADDI = nullptr;
862 auto II = MBB.end();
863 unsigned ADDIOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
864
865 if (Has32S) {
866 PCAI = BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: LoongArch::PCALAU12I), DestReg: ScratchReg)
867 .addMBB(MBB: &DestBB, TargetFlags: LoongArchII::MO_PCREL_HI);
868 ADDI = BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: ADDIOp), DestReg: ScratchReg)
869 .addReg(RegNo: ScratchReg)
870 .addMBB(MBB: &DestBB, TargetFlags: LoongArchII::MO_PCREL_LO);
871 } else {
872 MCSymbol *PCAddSymbol = MF->getContext().createNamedTempSymbol(Name: "pcadd_hi");
873 PCAI = BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: LoongArch::PCADDU12I), DestReg: ScratchReg)
874 .addMBB(MBB: &DestBB, TargetFlags: LoongArchII::MO_PCADD_HI);
875 PCAI->setPreInstrSymbol(MF&: *MF, Symbol: PCAddSymbol);
876 ADDI = BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: ADDIOp), DestReg: ScratchReg)
877 .addReg(RegNo: ScratchReg)
878 .addSym(Sym: PCAddSymbol, TargetFlags: LoongArchII::MO_PCADD_LO);
879 }
880 BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: LoongArch::PseudoBRIND))
881 .addReg(RegNo: ScratchReg, Flags: RegState::Kill)
882 .addImm(Val: 0);
883
884 RS->enterBasicBlockEnd(MBB);
885 Register Scav = RS->scavengeRegisterBackwards(
886 RC: LoongArch::GPRRegClass, To: PCAI->getIterator(), /*RestoreAfter=*/false,
887 /*SPAdj=*/0, /*AllowSpill=*/false);
888 if (Scav != LoongArch::NoRegister)
889 RS->setRegUsed(Reg: Scav);
890 else {
891 // When there is no scavenged register, it needs to specify a register.
892 // Specify t8 register because it won't be used too often.
893 Scav = LoongArch::R20;
894 int FrameIndex = LAFI->getBranchRelaxationSpillFrameIndex();
895 if (FrameIndex == -1)
896 report_fatal_error(reason: "The function size is incorrectly estimated.");
897 storeRegToStackSlot(MBB, I: PCAI, SrcReg: Scav, /*IsKill=*/true, FI: FrameIndex,
898 RC: &LoongArch::GPRRegClass, VReg: Register());
899 TRI->eliminateFrameIndex(MI: std::prev(x: PCAI->getIterator()),
900 /*SpAdj=*/SPAdj: 0, /*FIOperandNum=*/1);
901 PCAI->getOperand(i: 1).setMBB(&RestoreBB);
902 if (Has32S)
903 ADDI->getOperand(i: 2).setMBB(&RestoreBB);
904 loadRegFromStackSlot(MBB&: RestoreBB, I: RestoreBB.end(), DstReg: Scav, FI: FrameIndex,
905 RC: &LoongArch::GPRRegClass, VReg: Register());
906 TRI->eliminateFrameIndex(MI: RestoreBB.back(),
907 /*SpAdj=*/SPAdj: 0, /*FIOperandNum=*/1);
908 }
909 MRI.replaceRegWith(FromReg: ScratchReg, ToReg: Scav);
910 MRI.clearVirtRegs();
911}
912
913static unsigned getOppositeBranchOpc(unsigned Opc) {
914 switch (Opc) {
915 default:
916 llvm_unreachable("Unrecognized conditional branch");
917 case LoongArch::BEQ:
918 return LoongArch::BNE;
919 case LoongArch::BNE:
920 return LoongArch::BEQ;
921 case LoongArch::BEQZ:
922 return LoongArch::BNEZ;
923 case LoongArch::BNEZ:
924 return LoongArch::BEQZ;
925 case LoongArch::BCEQZ:
926 return LoongArch::BCNEZ;
927 case LoongArch::BCNEZ:
928 return LoongArch::BCEQZ;
929 case LoongArch::BLT:
930 return LoongArch::BGE;
931 case LoongArch::BGE:
932 return LoongArch::BLT;
933 case LoongArch::BLTU:
934 return LoongArch::BGEU;
935 case LoongArch::BGEU:
936 return LoongArch::BLTU;
937 }
938}
939
940bool LoongArchInstrInfo::reverseBranchCondition(
941 SmallVectorImpl<MachineOperand> &Cond) const {
942 assert((Cond.size() && Cond.size() <= 3) && "Invalid branch condition!");
943 Cond[0].setImm(getOppositeBranchOpc(Opc: Cond[0].getImm()));
944 return false;
945}
946
947std::pair<unsigned, unsigned>
948LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
949 const unsigned Mask = LoongArchII::MO_DIRECT_FLAG_MASK;
950 return std::make_pair(x: TF & Mask, y: TF & ~Mask);
951}
952
953ArrayRef<std::pair<unsigned, const char *>>
954LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
955 using namespace LoongArchII;
956 // TODO: Add more target flags.
957 static const std::pair<unsigned, const char *> TargetFlags[] = {
958 {MO_CALL, "loongarch-call"},
959 {MO_CALL_PLT, "loongarch-call-plt"},
960 {MO_PCREL_HI, "loongarch-pcrel-hi"},
961 {MO_PCREL_LO, "loongarch-pcrel-lo"},
962 {MO_PCREL64_LO, "loongarch-pcrel64-lo"},
963 {MO_PCREL64_HI, "loongarch-pcrel64-hi"},
964 {MO_GOT_PC_HI, "loongarch-got-pc-hi"},
965 {MO_GOT_PC_LO, "loongarch-got-pc-lo"},
966 {MO_GOT_PC64_LO, "loongarch-got-pc64-lo"},
967 {MO_GOT_PC64_HI, "loongarch-got-pc64-hi"},
968 {MO_LE_HI, "loongarch-le-hi"},
969 {MO_LE_LO, "loongarch-le-lo"},
970 {MO_LE64_LO, "loongarch-le64-lo"},
971 {MO_LE64_HI, "loongarch-le64-hi"},
972 {MO_IE_PC_HI, "loongarch-ie-pc-hi"},
973 {MO_IE_PC_LO, "loongarch-ie-pc-lo"},
974 {MO_IE_PC64_LO, "loongarch-ie-pc64-lo"},
975 {MO_IE_PC64_HI, "loongarch-ie-pc64-hi"},
976 {MO_LD_PC_HI, "loongarch-ld-pc-hi"},
977 {MO_GD_PC_HI, "loongarch-gd-pc-hi"},
978 {MO_CALL30, "loongarch-call30"},
979 {MO_CALL36, "loongarch-call36"},
980 {MO_DESC_PC_HI, "loongarch-desc-pc-hi"},
981 {MO_DESC_PC_LO, "loongarch-desc-pc-lo"},
982 {MO_DESC64_PC_LO, "loongarch-desc64-pc-lo"},
983 {MO_DESC64_PC_HI, "loongarch-desc64-pc-hi"},
984 {MO_DESC_LD, "loongarch-desc-ld"},
985 {MO_DESC_CALL, "loongarch-desc-call"},
986 {MO_LE_HI_R, "loongarch-le-hi-r"},
987 {MO_LE_ADD_R, "loongarch-le-add-r"},
988 {MO_LE_LO_R, "loongarch-le-lo-r"},
989 {MO_PCADD_HI, "loongarch-pcadd-hi"},
990 {MO_PCADD_LO, "loongarch-pcadd-lo"},
991 {MO_GOT_PCADD_HI, "loongarch-got-pcadd-hi"},
992 {MO_GOT_PCADD_LO, "loongarch-got-pcadd-lo"},
993 {MO_IE_PCADD_HI, "loongarch-ie-pcadd-hi"},
994 {MO_IE_PCADD_LO, "loongarch-ie-pcadd-lo"},
995 {MO_LD_PCADD_HI, "loongarch-ld-pcadd-hi"},
996 {MO_LD_PCADD_LO, "loongarch-ld-pcadd-lo"},
997 {MO_GD_PCADD_HI, "loongarch-gd-pcadd-hi"},
998 {MO_GD_PCADD_LO, "loongarch-gd-pcadd-lo"},
999 {MO_DESC_PCADD_HI, "loongarch-pcadd-desc-hi"},
1000 {MO_DESC_PCADD_LO, "loongarch-pcadd-desc-lo"}};
1001 return ArrayRef(TargetFlags);
1002}
1003
1004ArrayRef<std::pair<unsigned, const char *>>
1005LoongArchInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
1006 using namespace LoongArchII;
1007 static const std::pair<unsigned, const char *> TargetFlags[] = {
1008 {MO_RELAX, "loongarch-relax"}};
1009 return ArrayRef(TargetFlags);
1010}
1011
1012bool LoongArchInstrInfo::canFoldIntoAddrMode(const MachineInstr &MemI,
1013 Register Reg,
1014 const MachineInstr &AddrI,
1015 ExtAddrMode &AM) const {
1016 enum MemIOffsetType {
1017 Imm14Shift2,
1018 Imm12,
1019 Imm11Shift1,
1020 Imm10Shift2,
1021 Imm9Shift3,
1022 Imm8,
1023 Imm8Shift1,
1024 Imm8Shift2,
1025 Imm8Shift3
1026 };
1027
1028 MemIOffsetType OT;
1029 switch (MemI.getOpcode()) {
1030 default:
1031 return false;
1032 case LoongArch::LDPTR_W:
1033 case LoongArch::LDPTR_D:
1034 case LoongArch::STPTR_W:
1035 case LoongArch::STPTR_D:
1036 OT = Imm14Shift2;
1037 break;
1038 case LoongArch::LD_B:
1039 case LoongArch::LD_H:
1040 case LoongArch::LD_W:
1041 case LoongArch::LD_D:
1042 case LoongArch::LD_BU:
1043 case LoongArch::LD_HU:
1044 case LoongArch::LD_WU:
1045 case LoongArch::ST_B:
1046 case LoongArch::ST_H:
1047 case LoongArch::ST_W:
1048 case LoongArch::ST_D:
1049 case LoongArch::FLD_S:
1050 case LoongArch::FLD_D:
1051 case LoongArch::FST_S:
1052 case LoongArch::FST_D:
1053 case LoongArch::VLD:
1054 case LoongArch::VST:
1055 case LoongArch::XVLD:
1056 case LoongArch::XVST:
1057 case LoongArch::VLDREPL_B:
1058 case LoongArch::XVLDREPL_B:
1059 OT = Imm12;
1060 break;
1061 case LoongArch::VLDREPL_H:
1062 case LoongArch::XVLDREPL_H:
1063 OT = Imm11Shift1;
1064 break;
1065 case LoongArch::VLDREPL_W:
1066 case LoongArch::XVLDREPL_W:
1067 OT = Imm10Shift2;
1068 break;
1069 case LoongArch::VLDREPL_D:
1070 case LoongArch::XVLDREPL_D:
1071 OT = Imm9Shift3;
1072 break;
1073 case LoongArch::VSTELM_B:
1074 case LoongArch::XVSTELM_B:
1075 OT = Imm8;
1076 break;
1077 case LoongArch::VSTELM_H:
1078 case LoongArch::XVSTELM_H:
1079 OT = Imm8Shift1;
1080 break;
1081 case LoongArch::VSTELM_W:
1082 case LoongArch::XVSTELM_W:
1083 OT = Imm8Shift2;
1084 break;
1085 case LoongArch::VSTELM_D:
1086 case LoongArch::XVSTELM_D:
1087 OT = Imm8Shift3;
1088 break;
1089 }
1090
1091 if (MemI.getOperand(i: 0).getReg() == Reg)
1092 return false;
1093
1094 if ((AddrI.getOpcode() != LoongArch::ADDI_W &&
1095 AddrI.getOpcode() != LoongArch::ADDI_D) ||
1096 !AddrI.getOperand(i: 1).isReg() || !AddrI.getOperand(i: 2).isImm())
1097 return false;
1098
1099 int64_t OldOffset = MemI.getOperand(i: 2).getImm();
1100 int64_t Disp = AddrI.getOperand(i: 2).getImm();
1101 int64_t NewOffset = OldOffset + Disp;
1102 if (!STI.is64Bit())
1103 NewOffset = SignExtend64<32>(x: NewOffset);
1104
1105 if (!(OT == Imm14Shift2 && isShiftedInt<14, 2>(x: NewOffset) && STI.hasUAL()) &&
1106 !(OT == Imm12 && isInt<12>(x: NewOffset)) &&
1107 !(OT == Imm11Shift1 && isShiftedInt<11, 1>(x: NewOffset)) &&
1108 !(OT == Imm10Shift2 && isShiftedInt<10, 2>(x: NewOffset)) &&
1109 !(OT == Imm9Shift3 && isShiftedInt<9, 3>(x: NewOffset)) &&
1110 !(OT == Imm8 && isInt<8>(x: NewOffset)) &&
1111 !(OT == Imm8Shift1 && isShiftedInt<8, 1>(x: NewOffset)) &&
1112 !(OT == Imm8Shift2 && isShiftedInt<8, 2>(x: NewOffset)) &&
1113 !(OT == Imm8Shift3 && isShiftedInt<8, 3>(x: NewOffset)))
1114 return false;
1115
1116 AM.BaseReg = AddrI.getOperand(i: 1).getReg();
1117 AM.ScaledReg = 0;
1118 AM.Scale = 0;
1119 AM.Displacement = NewOffset;
1120 AM.Form = ExtAddrMode::Formula::Basic;
1121 return true;
1122}
1123
1124MachineInstr *
1125LoongArchInstrInfo::emitLdStWithAddr(MachineInstr &MemI,
1126 const ExtAddrMode &AM) const {
1127 const DebugLoc &DL = MemI.getDebugLoc();
1128 MachineBasicBlock &MBB = *MemI.getParent();
1129
1130 assert(AM.ScaledReg == 0 && AM.Scale == 0 &&
1131 "Addressing mode not supported for folding");
1132
1133 unsigned MemIOp = MemI.getOpcode();
1134 switch (MemIOp) {
1135 default:
1136 return BuildMI(BB&: MBB, I&: MemI, MIMD: DL, MCID: get(Opcode: MemIOp))
1137 .addReg(RegNo: MemI.getOperand(i: 0).getReg(), Flags: getDefRegState(B: MemI.mayLoad()))
1138 .addReg(RegNo: AM.BaseReg)
1139 .addImm(Val: AM.Displacement)
1140 .setMemRefs(MemI.memoperands())
1141 .setMIFlags(MemI.getFlags());
1142 case LoongArch::VSTELM_B:
1143 case LoongArch::VSTELM_H:
1144 case LoongArch::VSTELM_W:
1145 case LoongArch::VSTELM_D:
1146 case LoongArch::XVSTELM_B:
1147 case LoongArch::XVSTELM_H:
1148 case LoongArch::XVSTELM_W:
1149 case LoongArch::XVSTELM_D:
1150 return BuildMI(BB&: MBB, I&: MemI, MIMD: DL, MCID: get(Opcode: MemIOp))
1151 .addReg(RegNo: MemI.getOperand(i: 0).getReg())
1152 .addReg(RegNo: AM.BaseReg)
1153 .addImm(Val: AM.Displacement)
1154 .addImm(Val: MemI.getOperand(i: 3).getImm())
1155 .setMemRefs(MemI.memoperands())
1156 .setMIFlags(MemI.getFlags());
1157 }
1158}
1159
1160// Returns true if this is the sext.w pattern, addi.w rd, rs, 0.
1161bool LoongArch::isSEXT_W(const MachineInstr &MI) {
1162 return MI.getOpcode() == LoongArch::ADDI_W && MI.getOperand(i: 1).isReg() &&
1163 MI.getOperand(i: 2).isImm() && MI.getOperand(i: 2).getImm() == 0;
1164}
1165