LLVM 22.0.0git
LoongArchInstrInfo.cpp
Go to the documentation of this file.
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"
22
23using namespace llvm;
24
25#define GET_INSTRINFO_CTOR_DTOR
26#include "LoongArchGenInstrInfo.inc"
27
32
34 return MCInstBuilder(LoongArch::ANDI)
35 .addReg(LoongArch::R0)
36 .addReg(LoongArch::R0)
37 .addImm(0);
38}
39
42 const DebugLoc &DL, Register DstReg,
43 Register SrcReg, bool KillSrc,
44 bool RenamableDest,
45 bool RenamableSrc) const {
46 if (LoongArch::GPRRegClass.contains(DstReg, SrcReg)) {
47 BuildMI(MBB, MBBI, DL, get(LoongArch::OR), DstReg)
48 .addReg(SrcReg, getKillRegState(KillSrc))
49 .addReg(LoongArch::R0);
50 return;
51 }
52
53 // VR->VR copies.
54 if (LoongArch::LSX128RegClass.contains(DstReg, SrcReg)) {
55 BuildMI(MBB, MBBI, DL, get(LoongArch::VORI_B), DstReg)
56 .addReg(SrcReg, getKillRegState(KillSrc))
57 .addImm(0);
58 return;
59 }
60
61 // XR->XR copies.
62 if (LoongArch::LASX256RegClass.contains(DstReg, SrcReg)) {
63 BuildMI(MBB, MBBI, DL, get(LoongArch::XVORI_B), DstReg)
64 .addReg(SrcReg, getKillRegState(KillSrc))
65 .addImm(0);
66 return;
67 }
68
69 // GPR->CFR copy.
70 if (LoongArch::CFRRegClass.contains(DstReg) &&
71 LoongArch::GPRRegClass.contains(SrcReg)) {
72 BuildMI(MBB, MBBI, DL, get(LoongArch::MOVGR2CF), DstReg)
73 .addReg(SrcReg, getKillRegState(KillSrc));
74 return;
75 }
76 // CFR->GPR copy.
77 if (LoongArch::GPRRegClass.contains(DstReg) &&
78 LoongArch::CFRRegClass.contains(SrcReg)) {
79 BuildMI(MBB, MBBI, DL, get(LoongArch::MOVCF2GR), DstReg)
80 .addReg(SrcReg, getKillRegState(KillSrc));
81 return;
82 }
83 // CFR->CFR copy.
84 if (LoongArch::CFRRegClass.contains(DstReg, SrcReg)) {
85 BuildMI(MBB, MBBI, DL, get(LoongArch::PseudoCopyCFR), DstReg)
86 .addReg(SrcReg, getKillRegState(KillSrc));
87 return;
88 }
89
90 // FPR->FPR copies.
91 unsigned Opc;
92 if (LoongArch::FPR32RegClass.contains(DstReg, SrcReg)) {
93 Opc = LoongArch::FMOV_S;
94 } else if (LoongArch::FPR64RegClass.contains(DstReg, SrcReg)) {
95 Opc = LoongArch::FMOV_D;
96 } else if (LoongArch::GPRRegClass.contains(DstReg) &&
97 LoongArch::FPR32RegClass.contains(SrcReg)) {
98 // FPR32 -> GPR copies
99 Opc = LoongArch::MOVFR2GR_S;
100 } else if (LoongArch::GPRRegClass.contains(DstReg) &&
101 LoongArch::FPR64RegClass.contains(SrcReg)) {
102 // FPR64 -> GPR copies
103 Opc = LoongArch::MOVFR2GR_D;
104 } else {
105 // TODO: support other copies.
106 llvm_unreachable("Impossible reg-to-reg copy");
107 }
108
109 BuildMI(MBB, MBBI, DL, get(Opc), DstReg)
110 .addReg(SrcReg, getKillRegState(KillSrc));
111}
112
115 bool IsKill, int FI, const TargetRegisterClass *RC,
116 const TargetRegisterInfo *TRI, Register VReg,
117 MachineInstr::MIFlag Flags) const {
118 MachineFunction *MF = MBB.getParent();
119 MachineFrameInfo &MFI = MF->getFrameInfo();
120
121 unsigned Opcode;
122 if (LoongArch::GPRRegClass.hasSubClassEq(RC))
123 Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32
124 ? LoongArch::ST_W
125 : LoongArch::ST_D;
126 else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))
127 Opcode = LoongArch::FST_S;
128 else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))
129 Opcode = LoongArch::FST_D;
130 else if (LoongArch::LSX128RegClass.hasSubClassEq(RC))
131 Opcode = LoongArch::VST;
132 else if (LoongArch::LASX256RegClass.hasSubClassEq(RC))
133 Opcode = LoongArch::XVST;
134 else if (LoongArch::CFRRegClass.hasSubClassEq(RC))
135 Opcode = LoongArch::PseudoST_CFR;
136 else
137 llvm_unreachable("Can't store this register to stack slot");
138
141 MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
142
143 BuildMI(MBB, I, DebugLoc(), get(Opcode))
144 .addReg(SrcReg, getKillRegState(IsKill))
145 .addFrameIndex(FI)
146 .addImm(0)
147 .addMemOperand(MMO);
148}
149
152 int FI, const TargetRegisterClass *RC, const TargetRegisterInfo *TRI,
153 Register VReg, MachineInstr::MIFlag Flags) const {
154 MachineFunction *MF = MBB.getParent();
155 MachineFrameInfo &MFI = MF->getFrameInfo();
156 DebugLoc DL;
157 if (I != MBB.end())
158 DL = I->getDebugLoc();
159
160 unsigned Opcode;
161 if (LoongArch::GPRRegClass.hasSubClassEq(RC))
162 Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32
163 ? LoongArch::LD_W
164 : LoongArch::LD_D;
165 else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))
166 Opcode = LoongArch::FLD_S;
167 else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))
168 Opcode = LoongArch::FLD_D;
169 else if (LoongArch::LSX128RegClass.hasSubClassEq(RC))
170 Opcode = LoongArch::VLD;
171 else if (LoongArch::LASX256RegClass.hasSubClassEq(RC))
172 Opcode = LoongArch::XVLD;
173 else if (LoongArch::CFRRegClass.hasSubClassEq(RC))
174 Opcode = LoongArch::PseudoLD_CFR;
175 else
176 llvm_unreachable("Can't load this register from stack slot");
177
180 MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
181
182 BuildMI(MBB, I, DL, get(Opcode), DstReg)
183 .addFrameIndex(FI)
184 .addImm(0)
185 .addMemOperand(MMO);
186}
187
190 const DebugLoc &DL, Register DstReg,
191 uint64_t Val, MachineInstr::MIFlag Flag) const {
192 Register SrcReg = LoongArch::R0;
193
194 if (!STI.is64Bit() && !isInt<32>(Val))
195 report_fatal_error("Should only materialize 32-bit constants for LA32");
196
197 auto Seq = LoongArchMatInt::generateInstSeq(Val);
198 assert(!Seq.empty());
199
200 for (auto &Inst : Seq) {
201 switch (Inst.Opc) {
202 case LoongArch::LU12I_W:
203 BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)
204 .addImm(Inst.Imm)
205 .setMIFlag(Flag);
206 break;
207 case LoongArch::ADDI_W:
208 case LoongArch::ORI:
209 case LoongArch::LU32I_D: // "rj" is needed due to InstrInfo pattern
210 case LoongArch::LU52I_D:
211 BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)
212 .addReg(SrcReg, RegState::Kill)
213 .addImm(Inst.Imm)
214 .setMIFlag(Flag);
215 break;
216 case LoongArch::BSTRINS_D:
217 BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)
218 .addReg(SrcReg, RegState::Kill)
219 .addReg(SrcReg, RegState::Kill)
220 .addImm(Inst.Imm >> 32)
221 .addImm(Inst.Imm & 0xFF)
222 .setMIFlag(Flag);
223 break;
224 default:
225 assert(false && "Unknown insn emitted by LoongArchMatInt");
226 }
227
228 // Only the first instruction has $zero as its source.
229 SrcReg = DstReg;
230 }
231}
232
234 unsigned Opcode = MI.getOpcode();
235
236 if (Opcode == TargetOpcode::INLINEASM ||
237 Opcode == TargetOpcode::INLINEASM_BR) {
238 const MachineFunction *MF = MI.getParent()->getParent();
239 const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
240 return getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI);
241 }
242
243 unsigned NumBytes = 0;
244 const MCInstrDesc &Desc = MI.getDesc();
245
246 // Size should be preferably set in
247 // llvm/lib/Target/LoongArch/LoongArch*InstrInfo.td (default case).
248 // Specific cases handle instructions of variable sizes.
249 switch (Desc.getOpcode()) {
250 default:
251 return Desc.getSize();
252 case TargetOpcode::STATEPOINT:
253 NumBytes = StatepointOpers(&MI).getNumPatchBytes();
254 assert(NumBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
255 // No patch bytes means a normal call inst (i.e. `bl`) is emitted.
256 if (NumBytes == 0)
257 NumBytes = 4;
258 break;
259 }
260 return NumBytes;
261}
262
264 const unsigned Opcode = MI.getOpcode();
265 switch (Opcode) {
266 default:
267 break;
268 case LoongArch::ADDI_D:
269 case LoongArch::ORI:
270 case LoongArch::XORI:
271 return (MI.getOperand(1).isReg() &&
272 MI.getOperand(1).getReg() == LoongArch::R0) ||
273 (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0);
274 }
275 return MI.isAsCheapAsAMove();
276}
277
280 assert(MI.getDesc().isBranch() && "Unexpected opcode!");
281 // The branch target is always the last operand.
282 return MI.getOperand(MI.getNumExplicitOperands() - 1).getMBB();
283}
284
287 // Block ends with fall-through condbranch.
288 assert(LastInst.getDesc().isConditionalBranch() &&
289 "Unknown conditional branch");
290 int NumOp = LastInst.getNumExplicitOperands();
291 Target = LastInst.getOperand(NumOp - 1).getMBB();
292
293 Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode()));
294 for (int i = 0; i < NumOp - 1; i++)
295 Cond.push_back(LastInst.getOperand(i));
296}
297
300 MachineBasicBlock *&FBB,
302 bool AllowModify) const {
303 TBB = FBB = nullptr;
304 Cond.clear();
305
306 // If the block has no terminators, it just falls into the block after it.
307 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
308 if (I == MBB.end() || !isUnpredicatedTerminator(*I))
309 return false;
310
311 // Count the number of terminators and find the first unconditional or
312 // indirect branch.
313 MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end();
314 int NumTerminators = 0;
315 for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(*J);
316 J++) {
317 NumTerminators++;
318 if (J->getDesc().isUnconditionalBranch() ||
319 J->getDesc().isIndirectBranch()) {
320 FirstUncondOrIndirectBr = J.getReverse();
321 }
322 }
323
324 // If AllowModify is true, we can erase any terminators after
325 // FirstUncondOrIndirectBR.
326 if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) {
327 while (std::next(FirstUncondOrIndirectBr) != MBB.end()) {
328 std::next(FirstUncondOrIndirectBr)->eraseFromParent();
329 NumTerminators--;
330 }
331 I = FirstUncondOrIndirectBr;
332 }
333
334 // Handle a single unconditional branch.
335 if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) {
337 return false;
338 }
339
340 // Handle a single conditional branch.
341 if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) {
343 return false;
344 }
345
346 // Handle a conditional branch followed by an unconditional branch.
347 if (NumTerminators == 2 && std::prev(I)->getDesc().isConditionalBranch() &&
348 I->getDesc().isUnconditionalBranch()) {
349 parseCondBranch(*std::prev(I), TBB, Cond);
350 FBB = getBranchDestBlock(*I);
351 return false;
352 }
353
354 // Otherwise, we can't handle this.
355 return true;
356}
357
359 int64_t BrOffset) const {
360 switch (BranchOp) {
361 default:
362 llvm_unreachable("Unknown branch instruction!");
363 case LoongArch::BEQ:
364 case LoongArch::BNE:
365 case LoongArch::BLT:
366 case LoongArch::BGE:
367 case LoongArch::BLTU:
368 case LoongArch::BGEU:
369 return isInt<18>(BrOffset);
370 case LoongArch::BEQZ:
371 case LoongArch::BNEZ:
372 case LoongArch::BCEQZ:
373 case LoongArch::BCNEZ:
374 return isInt<23>(BrOffset);
375 case LoongArch::B:
376 case LoongArch::PseudoBR:
377 return isInt<28>(BrOffset);
378 }
379}
380
382 const MachineBasicBlock *MBB,
383 const MachineFunction &MF) const {
384 auto MII = MI.getIterator();
385 auto MIE = MBB->end();
386
387 // According to psABI v2.30:
388 //
389 // https://github.com/loongson/la-abi-specs/releases/tag/v2.30
390 //
391 // The following instruction patterns are prohibited from being reordered:
392 //
393 // * pcalau12i $a0, %pc_hi20(s)
394 // addi.d $a1, $zero, %pc_lo12(s)
395 // lu32i.d $a1, %pc64_lo20(s)
396 // lu52i.d $a1, $a1, %pc64_hi12(s)
397 //
398 // * pcalau12i $a0, %got_pc_hi20(s) | %ld_pc_hi20(s) | %gd_pc_hi20(s)
399 // addi.d $a1, $zero, %got_pc_lo12(s)
400 // lu32i.d $a1, %got64_pc_lo20(s)
401 // lu52i.d $a1, $a1, %got64_pc_hi12(s)
402 //
403 // * pcalau12i $a0, %ie_pc_hi20(s)
404 // addi.d $a1, $zero, %ie_pc_lo12(s)
405 // lu32i.d $a1, %ie64_pc_lo20(s)
406 // lu52i.d $a1, $a1, %ie64_pc_hi12(s)
407 //
408 // * pcalau12i $a0, %desc_pc_hi20(s)
409 // addi.d $a1, $zero, %desc_pc_lo12(s)
410 // lu32i.d $a1, %desc64_pc_lo20(s)
411 // lu52i.d $a1, $a1, %desc64_pc_hi12(s)
412 //
413 // For simplicity, only pcalau12i and lu52i.d are marked as scheduling
414 // boundaries, and the instructions between them are guaranteed to be
415 // ordered according to data dependencies.
416 switch (MI.getOpcode()) {
417 case LoongArch::PCALAU12I: {
418 auto AddI = std::next(MII);
419 if (AddI == MIE || AddI->getOpcode() != LoongArch::ADDI_D)
420 break;
421 auto Lu32I = std::next(AddI);
422 if (Lu32I == MIE || Lu32I->getOpcode() != LoongArch::LU32I_D)
423 break;
424 auto MO0 = MI.getOperand(1).getTargetFlags();
425 auto MO1 = AddI->getOperand(2).getTargetFlags();
426 auto MO2 = Lu32I->getOperand(2).getTargetFlags();
429 return false;
431 MO0 == LoongArchII::MO_GD_PC_HI) &&
433 return false;
436 return false;
437 if (MO0 == LoongArchII::MO_DESC_PC_HI &&
440 return false;
441 break;
442 }
443 case LoongArch::LU52I_D: {
444 auto MO = MI.getOperand(2).getTargetFlags();
447 return false;
448 break;
449 }
450 default:
451 break;
452 }
453
454 const auto &STI = MF.getSubtarget<LoongArchSubtarget>();
455 if (STI.hasFeature(LoongArch::FeatureRelax)) {
456 // When linker relaxation enabled, the following instruction patterns are
457 // prohibited from being reordered:
458 //
459 // * pcalau12i $a0, %pc_hi20(s)
460 // addi.w/d $a0, $a0, %pc_lo12(s)
461 //
462 // * pcalau12i $a0, %got_pc_hi20(s)
463 // ld.w/d $a0, $a0, %got_pc_lo12(s)
464 //
465 // * pcalau12i $a0, %ld_pc_hi20(s) | %gd_pc_hi20(s)
466 // addi.w/d $a0, $a0, %got_pc_lo12(s)
467 //
468 // * pcalau12i $a0, %desc_pc_hi20(s)
469 // addi.w/d $a0, $a0, %desc_pc_lo12(s)
470 // ld.w/d $ra, $a0, %desc_ld(s)
471 // jirl $ra, $ra, %desc_call(s)
472 unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
473 unsigned LdOp = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
474 switch (MI.getOpcode()) {
475 case LoongArch::PCALAU12I: {
476 auto MO0 = LoongArchII::getDirectFlags(MI.getOperand(1));
477 auto SecondOp = std::next(MII);
478 if (MO0 == LoongArchII::MO_DESC_PC_HI) {
479 if (SecondOp == MIE || SecondOp->getOpcode() != AddiOp)
480 break;
481 auto Ld = std::next(SecondOp);
482 if (Ld == MIE || Ld->getOpcode() != LdOp)
483 break;
484 auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));
485 auto MO2 = LoongArchII::getDirectFlags(Ld->getOperand(2));
487 return false;
488 break;
489 }
490 if (SecondOp == MIE ||
491 (SecondOp->getOpcode() != AddiOp && SecondOp->getOpcode() != LdOp))
492 break;
493 auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));
494 if (MO0 == LoongArchII::MO_PCREL_HI && SecondOp->getOpcode() == AddiOp &&
496 return false;
497 if (MO0 == LoongArchII::MO_GOT_PC_HI && SecondOp->getOpcode() == LdOp &&
499 return false;
500 if ((MO0 == LoongArchII::MO_LD_PC_HI ||
501 MO0 == LoongArchII::MO_GD_PC_HI) &&
502 SecondOp->getOpcode() == AddiOp && MO1 == LoongArchII::MO_GOT_PC_LO)
503 return false;
504 break;
505 }
506 case LoongArch::ADDI_W:
507 case LoongArch::ADDI_D: {
508 auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
510 return false;
511 break;
512 }
513 case LoongArch::LD_W:
514 case LoongArch::LD_D: {
515 auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
517 return false;
518 break;
519 }
520 case LoongArch::PseudoDESC_CALL: {
521 auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
523 return false;
524 break;
525 }
526 default:
527 break;
528 }
529 }
530
531 return true;
532}
533
535 const MachineBasicBlock *MBB,
536 const MachineFunction &MF) const {
538 return true;
539
540 if (!isSafeToMove(MI, MBB, MF))
541 return true;
542
543 return false;
544}
545
547 int *BytesRemoved) const {
548 if (BytesRemoved)
549 *BytesRemoved = 0;
550 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
551 if (I == MBB.end())
552 return 0;
553
554 if (!I->getDesc().isBranch())
555 return 0;
556
557 // Remove the branch.
558 if (BytesRemoved)
559 *BytesRemoved += getInstSizeInBytes(*I);
560 I->eraseFromParent();
561
562 I = MBB.end();
563
564 if (I == MBB.begin())
565 return 1;
566 --I;
567 if (!I->getDesc().isConditionalBranch())
568 return 1;
569
570 // Remove the branch.
571 if (BytesRemoved)
572 *BytesRemoved += getInstSizeInBytes(*I);
573 I->eraseFromParent();
574 return 2;
575}
576
577// Inserts a branch into the end of the specific MachineBasicBlock, returning
578// the number of instructions inserted.
581 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
582 if (BytesAdded)
583 *BytesAdded = 0;
584
585 // Shouldn't be a fall through.
586 assert(TBB && "insertBranch must not be told to insert a fallthrough");
587 assert(Cond.size() <= 3 && Cond.size() != 1 &&
588 "LoongArch branch conditions have at most two components!");
589
590 // Unconditional branch.
591 if (Cond.empty()) {
592 MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(TBB);
593 if (BytesAdded)
594 *BytesAdded += getInstSizeInBytes(MI);
595 return 1;
596 }
597
598 // Either a one or two-way conditional branch.
600 for (unsigned i = 1; i < Cond.size(); ++i)
601 MIB.add(Cond[i]);
602 MIB.addMBB(TBB);
603 if (BytesAdded)
604 *BytesAdded += getInstSizeInBytes(*MIB);
605
606 // One-way conditional branch.
607 if (!FBB)
608 return 1;
609
610 // Two-way conditional branch.
611 MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(FBB);
612 if (BytesAdded)
613 *BytesAdded += getInstSizeInBytes(MI);
614 return 2;
615}
616
618 MachineBasicBlock &DestBB,
619 MachineBasicBlock &RestoreBB,
620 const DebugLoc &DL,
621 int64_t BrOffset,
622 RegScavenger *RS) const {
623 assert(RS && "RegScavenger required for long branching");
624 assert(MBB.empty() &&
625 "new block should be inserted for expanding unconditional branch");
626 assert(MBB.pred_size() == 1);
627
628 MachineFunction *MF = MBB.getParent();
633
634 if (!isInt<32>(BrOffset))
636 "Branch offsets outside of the signed 32-bit range not supported");
637
638 Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
639 auto II = MBB.end();
640
641 MachineInstr &PCALAU12I =
642 *BuildMI(MBB, II, DL, get(LoongArch::PCALAU12I), ScratchReg)
644 MachineInstr &ADDI =
645 *BuildMI(MBB, II, DL,
646 get(STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W),
647 ScratchReg)
648 .addReg(ScratchReg)
650 BuildMI(MBB, II, DL, get(LoongArch::PseudoBRIND))
651 .addReg(ScratchReg, RegState::Kill)
652 .addImm(0);
653
654 RS->enterBasicBlockEnd(MBB);
655 Register Scav = RS->scavengeRegisterBackwards(
656 LoongArch::GPRRegClass, PCALAU12I.getIterator(), /*RestoreAfter=*/false,
657 /*SPAdj=*/0, /*AllowSpill=*/false);
658 if (Scav != LoongArch::NoRegister)
659 RS->setRegUsed(Scav);
660 else {
661 // When there is no scavenged register, it needs to specify a register.
662 // Specify t8 register because it won't be used too often.
663 Scav = LoongArch::R20;
664 int FrameIndex = LAFI->getBranchRelaxationSpillFrameIndex();
665 if (FrameIndex == -1)
666 report_fatal_error("The function size is incorrectly estimated.");
667 storeRegToStackSlot(MBB, PCALAU12I, Scav, /*IsKill=*/true, FrameIndex,
668 &LoongArch::GPRRegClass, TRI, Register());
669 TRI->eliminateFrameIndex(std::prev(PCALAU12I.getIterator()),
670 /*SpAdj=*/0, /*FIOperandNum=*/1);
671 PCALAU12I.getOperand(1).setMBB(&RestoreBB);
672 ADDI.getOperand(2).setMBB(&RestoreBB);
673 loadRegFromStackSlot(RestoreBB, RestoreBB.end(), Scav, FrameIndex,
674 &LoongArch::GPRRegClass, TRI, Register());
675 TRI->eliminateFrameIndex(RestoreBB.back(),
676 /*SpAdj=*/0, /*FIOperandNum=*/1);
677 }
678 MRI.replaceRegWith(ScratchReg, Scav);
679 MRI.clearVirtRegs();
680}
681
682static unsigned getOppositeBranchOpc(unsigned Opc) {
683 switch (Opc) {
684 default:
685 llvm_unreachable("Unrecognized conditional branch");
686 case LoongArch::BEQ:
687 return LoongArch::BNE;
688 case LoongArch::BNE:
689 return LoongArch::BEQ;
690 case LoongArch::BEQZ:
691 return LoongArch::BNEZ;
692 case LoongArch::BNEZ:
693 return LoongArch::BEQZ;
694 case LoongArch::BCEQZ:
695 return LoongArch::BCNEZ;
696 case LoongArch::BCNEZ:
697 return LoongArch::BCEQZ;
698 case LoongArch::BLT:
699 return LoongArch::BGE;
700 case LoongArch::BGE:
701 return LoongArch::BLT;
702 case LoongArch::BLTU:
703 return LoongArch::BGEU;
704 case LoongArch::BGEU:
705 return LoongArch::BLTU;
706 }
707}
708
711 assert((Cond.size() && Cond.size() <= 3) && "Invalid branch condition!");
712 Cond[0].setImm(getOppositeBranchOpc(Cond[0].getImm()));
713 return false;
714}
715
716std::pair<unsigned, unsigned>
718 const unsigned Mask = LoongArchII::MO_DIRECT_FLAG_MASK;
719 return std::make_pair(TF & Mask, TF & ~Mask);
720}
721
724 using namespace LoongArchII;
725 // TODO: Add more target flags.
726 static const std::pair<unsigned, const char *> TargetFlags[] = {
727 {MO_CALL, "loongarch-call"},
728 {MO_CALL_PLT, "loongarch-call-plt"},
729 {MO_PCREL_HI, "loongarch-pcrel-hi"},
730 {MO_PCREL_LO, "loongarch-pcrel-lo"},
731 {MO_PCREL64_LO, "loongarch-pcrel64-lo"},
732 {MO_PCREL64_HI, "loongarch-pcrel64-hi"},
733 {MO_GOT_PC_HI, "loongarch-got-pc-hi"},
734 {MO_GOT_PC_LO, "loongarch-got-pc-lo"},
735 {MO_GOT_PC64_LO, "loongarch-got-pc64-lo"},
736 {MO_GOT_PC64_HI, "loongarch-got-pc64-hi"},
737 {MO_LE_HI, "loongarch-le-hi"},
738 {MO_LE_LO, "loongarch-le-lo"},
739 {MO_LE64_LO, "loongarch-le64-lo"},
740 {MO_LE64_HI, "loongarch-le64-hi"},
741 {MO_IE_PC_HI, "loongarch-ie-pc-hi"},
742 {MO_IE_PC_LO, "loongarch-ie-pc-lo"},
743 {MO_IE_PC64_LO, "loongarch-ie-pc64-lo"},
744 {MO_IE_PC64_HI, "loongarch-ie-pc64-hi"},
745 {MO_LD_PC_HI, "loongarch-ld-pc-hi"},
746 {MO_GD_PC_HI, "loongarch-gd-pc-hi"},
747 {MO_CALL36, "loongarch-call36"},
748 {MO_DESC_PC_HI, "loongarch-desc-pc-hi"},
749 {MO_DESC_PC_LO, "loongarch-desc-pc-lo"},
750 {MO_DESC64_PC_LO, "loongarch-desc64-pc-lo"},
751 {MO_DESC64_PC_HI, "loongarch-desc64-pc-hi"},
752 {MO_DESC_LD, "loongarch-desc-ld"},
753 {MO_DESC_CALL, "loongarch-desc-call"},
754 {MO_LE_HI_R, "loongarch-le-hi-r"},
755 {MO_LE_ADD_R, "loongarch-le-add-r"},
756 {MO_LE_LO_R, "loongarch-le-lo-r"}};
757 return ArrayRef(TargetFlags);
758}
759
762 using namespace LoongArchII;
763 static const std::pair<unsigned, const char *> TargetFlags[] = {
764 {MO_RELAX, "loongarch-relax"}};
765 return ArrayRef(TargetFlags);
766}
767
769 Register Reg,
770 const MachineInstr &AddrI,
771 ExtAddrMode &AM) const {
772 enum MemIOffsetType {
773 Imm14Shift2,
774 Imm12,
775 Imm11Shift1,
776 Imm10Shift2,
777 Imm9Shift3,
778 Imm8,
779 Imm8Shift1,
780 Imm8Shift2,
781 Imm8Shift3
782 };
783
784 MemIOffsetType OT;
785 switch (MemI.getOpcode()) {
786 default:
787 return false;
788 case LoongArch::LDPTR_W:
789 case LoongArch::LDPTR_D:
790 case LoongArch::STPTR_W:
791 case LoongArch::STPTR_D:
792 OT = Imm14Shift2;
793 break;
794 case LoongArch::LD_B:
795 case LoongArch::LD_H:
796 case LoongArch::LD_W:
797 case LoongArch::LD_D:
798 case LoongArch::LD_BU:
799 case LoongArch::LD_HU:
800 case LoongArch::LD_WU:
801 case LoongArch::ST_B:
802 case LoongArch::ST_H:
803 case LoongArch::ST_W:
804 case LoongArch::ST_D:
805 case LoongArch::FLD_S:
806 case LoongArch::FLD_D:
807 case LoongArch::FST_S:
808 case LoongArch::FST_D:
809 case LoongArch::VLD:
810 case LoongArch::VST:
811 case LoongArch::XVLD:
812 case LoongArch::XVST:
813 case LoongArch::VLDREPL_B:
814 case LoongArch::XVLDREPL_B:
815 OT = Imm12;
816 break;
817 case LoongArch::VLDREPL_H:
818 case LoongArch::XVLDREPL_H:
819 OT = Imm11Shift1;
820 break;
821 case LoongArch::VLDREPL_W:
822 case LoongArch::XVLDREPL_W:
823 OT = Imm10Shift2;
824 break;
825 case LoongArch::VLDREPL_D:
826 case LoongArch::XVLDREPL_D:
827 OT = Imm9Shift3;
828 break;
829 case LoongArch::VSTELM_B:
830 case LoongArch::XVSTELM_B:
831 OT = Imm8;
832 break;
833 case LoongArch::VSTELM_H:
834 case LoongArch::XVSTELM_H:
835 OT = Imm8Shift1;
836 break;
837 case LoongArch::VSTELM_W:
838 case LoongArch::XVSTELM_W:
839 OT = Imm8Shift2;
840 break;
841 case LoongArch::VSTELM_D:
842 case LoongArch::XVSTELM_D:
843 OT = Imm8Shift3;
844 break;
845 }
846
847 if (MemI.getOperand(0).getReg() == Reg)
848 return false;
849
850 if ((AddrI.getOpcode() != LoongArch::ADDI_W &&
851 AddrI.getOpcode() != LoongArch::ADDI_D) ||
852 !AddrI.getOperand(1).isReg() || !AddrI.getOperand(2).isImm())
853 return false;
854
855 int64_t OldOffset = MemI.getOperand(2).getImm();
856 int64_t Disp = AddrI.getOperand(2).getImm();
857 int64_t NewOffset = OldOffset + Disp;
858 if (!STI.is64Bit())
859 NewOffset = SignExtend64<32>(NewOffset);
860
861 if (!(OT == Imm14Shift2 && isShiftedInt<14, 2>(NewOffset) && STI.hasUAL()) &&
862 !(OT == Imm12 && isInt<12>(NewOffset)) &&
863 !(OT == Imm11Shift1 && isShiftedInt<11, 1>(NewOffset)) &&
864 !(OT == Imm10Shift2 && isShiftedInt<10, 2>(NewOffset)) &&
865 !(OT == Imm9Shift3 && isShiftedInt<9, 3>(NewOffset)) &&
866 !(OT == Imm8 && isInt<8>(NewOffset)) &&
867 !(OT == Imm8Shift1 && isShiftedInt<8, 1>(NewOffset)) &&
868 !(OT == Imm8Shift2 && isShiftedInt<8, 2>(NewOffset)) &&
869 !(OT == Imm8Shift3 && isShiftedInt<8, 3>(NewOffset)))
870 return false;
871
872 AM.BaseReg = AddrI.getOperand(1).getReg();
873 AM.ScaledReg = 0;
874 AM.Scale = 0;
875 AM.Displacement = NewOffset;
877 return true;
878}
879
882 const ExtAddrMode &AM) const {
883 const DebugLoc &DL = MemI.getDebugLoc();
885
886 assert(AM.ScaledReg == 0 && AM.Scale == 0 &&
887 "Addressing mode not supported for folding");
888
889 unsigned MemIOp = MemI.getOpcode();
890 switch (MemIOp) {
891 default:
892 return BuildMI(MBB, MemI, DL, get(MemIOp))
893 .addReg(MemI.getOperand(0).getReg(),
894 MemI.mayLoad() ? RegState::Define : 0)
895 .addReg(AM.BaseReg)
897 .setMemRefs(MemI.memoperands())
898 .setMIFlags(MemI.getFlags());
899 case LoongArch::VSTELM_B:
900 case LoongArch::VSTELM_H:
901 case LoongArch::VSTELM_W:
902 case LoongArch::VSTELM_D:
903 case LoongArch::XVSTELM_B:
904 case LoongArch::XVSTELM_H:
905 case LoongArch::XVSTELM_W:
906 case LoongArch::XVSTELM_D:
907 return BuildMI(MBB, MemI, DL, get(MemIOp))
908 .addReg(MemI.getOperand(0).getReg(), 0)
909 .addReg(AM.BaseReg)
911 .addImm(MemI.getOperand(3).getImm())
912 .setMemRefs(MemI.memoperands())
913 .setMIFlags(MemI.getFlags());
914 }
915}
916
917// Returns true if this is the sext.w pattern, addi.w rd, rs, 0.
919 return MI.getOpcode() == LoongArch::ADDI_W && MI.getOperand(1).isReg() &&
920 MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0;
921}
unsigned const MachineRegisterInfo * MRI
static void parseCondBranch(MachineInstr *LastInst, MachineBasicBlock *&Target, SmallVectorImpl< MachineOperand > &Cond)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static unsigned getOppositeBranchOpc(unsigned Opcode)
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:58
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
uint64_t IntrinsicInst * II
const SmallVectorImpl< MachineOperand > MachineBasicBlock * TBB
const SmallVectorImpl< MachineOperand > & Cond
This file declares the machine register scavenger class.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:480
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:41
A debug info location.
Definition DebugLoc.h:124
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, Register DstReg, Register SrcReg, bool KillSrc, bool RenamableDest=false, bool RenamableSrc=false) const override
ArrayRef< std::pair< unsigned, const char * > > getSerializableBitmaskMachineOperandTargetFlags() const override
const LoongArchSubtarget & STI
bool reverseBranchCondition(SmallVectorImpl< MachineOperand > &Cond) const override
bool isSafeToMove(const MachineInstr &MI, const MachineBasicBlock *MBB, const MachineFunction &MF) const override
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl< MachineOperand > &Cond, bool AllowModify) const override
std::pair< unsigned, unsigned > decomposeMachineOperandsTargetFlags(unsigned TF) const override
bool isAsCheapAsAMove(const MachineInstr &MI) const override
MCInst getNop() const override
LoongArchInstrInfo(const LoongArchSubtarget &STI)
ArrayRef< std::pair< unsigned, const char * > > getSerializableDirectMachineOperandTargetFlags() const override
unsigned removeBranch(MachineBasicBlock &MBB, int *BytesRemoved=nullptr) const override
void movImm(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, Register DstReg, uint64_t Val, MachineInstr::MIFlag Flag=MachineInstr::NoFlags) const
unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, ArrayRef< MachineOperand > Cond, const DebugLoc &dl, int *BytesAdded=nullptr) const override
void insertIndirectBranch(MachineBasicBlock &MBB, MachineBasicBlock &NewDestBB, MachineBasicBlock &RestoreBB, const DebugLoc &DL, int64_t BrOffset, RegScavenger *RS) const override
bool isSchedulingBoundary(const MachineInstr &MI, const MachineBasicBlock *MBB, const MachineFunction &MF) const override
bool isBranchOffsetInRange(unsigned BranchOpc, int64_t BrOffset) const override
bool canFoldIntoAddrMode(const MachineInstr &MemI, Register Reg, const MachineInstr &AddrI, ExtAddrMode &AM) const override
unsigned getInstSizeInBytes(const MachineInstr &MI) const override
void storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SrcReg, bool IsKill, int FrameIndex, const TargetRegisterClass *RC, const TargetRegisterInfo *TRI, Register VReg, MachineInstr::MIFlag Flags=MachineInstr::NoFlags) const override
MachineBasicBlock * getBranchDestBlock(const MachineInstr &MI) const override
void loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register DstReg, int FrameIndex, const TargetRegisterClass *RC, const TargetRegisterInfo *TRI, Register VReg, MachineInstr::MIFlag Flags=MachineInstr::NoFlags) const override
MachineInstr * emitLdStWithAddr(MachineInstr &MemI, const ExtAddrMode &AM) const override
LoongArchMachineFunctionInfo - This class is derived from MachineFunctionInfo and contains private Lo...
This class is intended to be used as a base class for asm properties and features specific to the tar...
Definition MCAsmInfo.h:64
MCInstBuilder & addReg(MCRegister Reg)
Add a new register operand.
MCInstBuilder & addImm(int64_t Val)
Add a new integer immediate operand.
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
Describe properties that are true of each instruction in the target description file.
bool isConditionalBranch() const
Return true if this is a branch which may fall through to the next instruction or may transfer contro...
MachineInstrBundleIterator< MachineInstr > iterator
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
Align getObjectAlign(int ObjectIdx) const
Return the alignment of the specified stack object.
int64_t getObjectSize(int ObjectIdx) const
Return the size of the specified object.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
const MachineInstrBuilder & setMemRefs(ArrayRef< MachineMemOperand * > MMOs) const
const MachineInstrBuilder & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
reverse_iterator getReverse() const
Get a reverse iterator to the same node.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI unsigned getNumExplicitOperands() const
Returns the number of non-implicit operands.
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
ArrayRef< MachineMemOperand * > memoperands() const
Access to memory operands of the instruction.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
uint32_t getFlags() const
Return the MI flags bitvector.
A description of a memory reference used in the backend.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
void setMBB(MachineBasicBlock *MBB)
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Wrapper class representing virtual and physical registers.
Definition Register.h:20
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
MI-level Statepoint operands.
Definition StackMaps.h:159
uint32_t getNumPatchBytes() const
Return the number of patchable bytes the given statepoint should emit.
Definition StackMaps.h:208
virtual bool isSchedulingBoundary(const MachineInstr &MI, const MachineBasicBlock *MBB, const MachineFunction &MF) const
Test if the given instruction should be considered a scheduling boundary.
const MCAsmInfo * getMCAsmInfo() const
Return target specific asm information.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
Target - Wrapper for Target specific information.
self_iterator getIterator()
Definition ilist_node.h:123
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static unsigned getDirectFlags(const MachineOperand &MO)
InstSeq generateInstSeq(int64_t Val)
bool isSEXT_W(const MachineInstr &MI)
@ Define
Register definition.
@ Kill
The last use of a register.
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:165
Op::Description Desc
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:167
unsigned getKillRegState(bool B)
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr bool isShiftedInt(int64_t x)
Checks if a signed integer is an N bit number shifted left by S.
Definition MathExtras.h:182
constexpr int64_t SignExtend64(uint64_t x)
Sign-extend the number in the bottom B bits of X to a 64-bit integer.
Definition MathExtras.h:572
Used to describe addressing mode similar to ExtAddrMode in CodeGenPrepare.
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.