1 //=- LoongArchInstrInfo.cpp - LoongArch Instruction Information -*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains the LoongArch implementation of the TargetInstrInfo class.
11 //===----------------------------------------------------------------------===//
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/MC/MCInstBuilder.h"
24 #define GET_INSTRINFO_CTOR_DTOR
25 #include "LoongArchGenInstrInfo.inc"
27 LoongArchInstrInfo::LoongArchInstrInfo(LoongArchSubtarget
&STI
)
28 : LoongArchGenInstrInfo(LoongArch::ADJCALLSTACKDOWN
,
29 LoongArch::ADJCALLSTACKUP
),
32 MCInst
LoongArchInstrInfo::getNop() const {
33 return MCInstBuilder(LoongArch::ANDI
)
34 .addReg(LoongArch::R0
)
35 .addReg(LoongArch::R0
)
39 void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock
&MBB
,
40 MachineBasicBlock::iterator MBBI
,
41 const DebugLoc
&DL
, MCRegister DstReg
,
42 MCRegister SrcReg
, bool KillSrc
) const {
43 if (LoongArch::GPRRegClass
.contains(DstReg
, SrcReg
)) {
44 BuildMI(MBB
, MBBI
, DL
, get(LoongArch::OR
), DstReg
)
45 .addReg(SrcReg
, getKillRegState(KillSrc
))
46 .addReg(LoongArch::R0
);
51 if (LoongArch::LSX128RegClass
.contains(DstReg
, SrcReg
)) {
52 BuildMI(MBB
, MBBI
, DL
, get(LoongArch::VORI_B
), DstReg
)
53 .addReg(SrcReg
, getKillRegState(KillSrc
))
59 if (LoongArch::LASX256RegClass
.contains(DstReg
, SrcReg
)) {
60 BuildMI(MBB
, MBBI
, DL
, get(LoongArch::XVORI_B
), DstReg
)
61 .addReg(SrcReg
, getKillRegState(KillSrc
))
67 if (LoongArch::CFRRegClass
.contains(DstReg
) &&
68 LoongArch::GPRRegClass
.contains(SrcReg
)) {
69 BuildMI(MBB
, MBBI
, DL
, get(LoongArch::MOVGR2CF
), DstReg
)
70 .addReg(SrcReg
, getKillRegState(KillSrc
));
74 if (LoongArch::GPRRegClass
.contains(DstReg
) &&
75 LoongArch::CFRRegClass
.contains(SrcReg
)) {
76 BuildMI(MBB
, MBBI
, DL
, get(LoongArch::MOVCF2GR
), DstReg
)
77 .addReg(SrcReg
, getKillRegState(KillSrc
));
81 if (LoongArch::CFRRegClass
.contains(DstReg
, SrcReg
)) {
82 BuildMI(MBB
, MBBI
, DL
, get(LoongArch::PseudoCopyCFR
), DstReg
)
83 .addReg(SrcReg
, getKillRegState(KillSrc
));
89 if (LoongArch::FPR32RegClass
.contains(DstReg
, SrcReg
)) {
90 Opc
= LoongArch::FMOV_S
;
91 } else if (LoongArch::FPR64RegClass
.contains(DstReg
, SrcReg
)) {
92 Opc
= LoongArch::FMOV_D
;
93 } else if (LoongArch::GPRRegClass
.contains(DstReg
) &&
94 LoongArch::FPR32RegClass
.contains(SrcReg
)) {
95 // FPR32 -> GPR copies
96 Opc
= LoongArch::MOVFR2GR_S
;
97 } else if (LoongArch::GPRRegClass
.contains(DstReg
) &&
98 LoongArch::FPR64RegClass
.contains(SrcReg
)) {
99 // FPR64 -> GPR copies
100 Opc
= LoongArch::MOVFR2GR_D
;
102 // TODO: support other copies.
103 llvm_unreachable("Impossible reg-to-reg copy");
106 BuildMI(MBB
, MBBI
, DL
, get(Opc
), DstReg
)
107 .addReg(SrcReg
, getKillRegState(KillSrc
));
110 void LoongArchInstrInfo::storeRegToStackSlot(
111 MachineBasicBlock
&MBB
, MachineBasicBlock::iterator I
, Register SrcReg
,
112 bool IsKill
, int FI
, const TargetRegisterClass
*RC
,
113 const TargetRegisterInfo
*TRI
, Register VReg
) const {
114 MachineFunction
*MF
= MBB
.getParent();
115 MachineFrameInfo
&MFI
= MF
->getFrameInfo();
118 if (LoongArch::GPRRegClass
.hasSubClassEq(RC
))
119 Opcode
= TRI
->getRegSizeInBits(LoongArch::GPRRegClass
) == 32
122 else if (LoongArch::FPR32RegClass
.hasSubClassEq(RC
))
123 Opcode
= LoongArch::FST_S
;
124 else if (LoongArch::FPR64RegClass
.hasSubClassEq(RC
))
125 Opcode
= LoongArch::FST_D
;
126 else if (LoongArch::LSX128RegClass
.hasSubClassEq(RC
))
127 Opcode
= LoongArch::VST
;
128 else if (LoongArch::LASX256RegClass
.hasSubClassEq(RC
))
129 Opcode
= LoongArch::XVST
;
130 else if (LoongArch::CFRRegClass
.hasSubClassEq(RC
))
131 Opcode
= LoongArch::PseudoST_CFR
;
133 llvm_unreachable("Can't store this register to stack slot");
135 MachineMemOperand
*MMO
= MF
->getMachineMemOperand(
136 MachinePointerInfo::getFixedStack(*MF
, FI
), MachineMemOperand::MOStore
,
137 MFI
.getObjectSize(FI
), MFI
.getObjectAlign(FI
));
139 BuildMI(MBB
, I
, DebugLoc(), get(Opcode
))
140 .addReg(SrcReg
, getKillRegState(IsKill
))
146 void LoongArchInstrInfo::loadRegFromStackSlot(MachineBasicBlock
&MBB
,
147 MachineBasicBlock::iterator I
,
148 Register DstReg
, int FI
,
149 const TargetRegisterClass
*RC
,
150 const TargetRegisterInfo
*TRI
,
151 Register VReg
) const {
152 MachineFunction
*MF
= MBB
.getParent();
153 MachineFrameInfo
&MFI
= MF
->getFrameInfo();
156 if (LoongArch::GPRRegClass
.hasSubClassEq(RC
))
157 Opcode
= TRI
->getRegSizeInBits(LoongArch::GPRRegClass
) == 32
160 else if (LoongArch::FPR32RegClass
.hasSubClassEq(RC
))
161 Opcode
= LoongArch::FLD_S
;
162 else if (LoongArch::FPR64RegClass
.hasSubClassEq(RC
))
163 Opcode
= LoongArch::FLD_D
;
164 else if (LoongArch::LSX128RegClass
.hasSubClassEq(RC
))
165 Opcode
= LoongArch::VLD
;
166 else if (LoongArch::LASX256RegClass
.hasSubClassEq(RC
))
167 Opcode
= LoongArch::XVLD
;
168 else if (LoongArch::CFRRegClass
.hasSubClassEq(RC
))
169 Opcode
= LoongArch::PseudoLD_CFR
;
171 llvm_unreachable("Can't load this register from stack slot");
173 MachineMemOperand
*MMO
= MF
->getMachineMemOperand(
174 MachinePointerInfo::getFixedStack(*MF
, FI
), MachineMemOperand::MOLoad
,
175 MFI
.getObjectSize(FI
), MFI
.getObjectAlign(FI
));
177 BuildMI(MBB
, I
, DebugLoc(), get(Opcode
), DstReg
)
183 void LoongArchInstrInfo::movImm(MachineBasicBlock
&MBB
,
184 MachineBasicBlock::iterator MBBI
,
185 const DebugLoc
&DL
, Register DstReg
,
186 uint64_t Val
, MachineInstr::MIFlag Flag
) const {
187 Register SrcReg
= LoongArch::R0
;
189 if (!STI
.is64Bit() && !isInt
<32>(Val
))
190 report_fatal_error("Should only materialize 32-bit constants for LA32");
192 auto Seq
= LoongArchMatInt::generateInstSeq(Val
);
193 assert(!Seq
.empty());
195 for (auto &Inst
: Seq
) {
197 case LoongArch::LU12I_W
:
198 BuildMI(MBB
, MBBI
, DL
, get(Inst
.Opc
), DstReg
)
202 case LoongArch::ADDI_W
:
204 case LoongArch::LU32I_D
: // "rj" is needed due to InstrInfo pattern
205 case LoongArch::LU52I_D
:
206 BuildMI(MBB
, MBBI
, DL
, get(Inst
.Opc
), DstReg
)
207 .addReg(SrcReg
, RegState::Kill
)
212 assert(false && "Unknown insn emitted by LoongArchMatInt");
215 // Only the first instruction has $zero as its source.
220 unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr
&MI
) const {
221 unsigned Opcode
= MI
.getOpcode();
223 if (Opcode
== TargetOpcode::INLINEASM
||
224 Opcode
== TargetOpcode::INLINEASM_BR
) {
225 const MachineFunction
*MF
= MI
.getParent()->getParent();
226 const MCAsmInfo
*MAI
= MF
->getTarget().getMCAsmInfo();
227 return getInlineAsmLength(MI
.getOperand(0).getSymbolName(), *MAI
);
229 return MI
.getDesc().getSize();
232 bool LoongArchInstrInfo::isAsCheapAsAMove(const MachineInstr
&MI
) const {
233 const unsigned Opcode
= MI
.getOpcode();
237 case LoongArch::ADDI_D
:
239 case LoongArch::XORI
:
240 return (MI
.getOperand(1).isReg() &&
241 MI
.getOperand(1).getReg() == LoongArch::R0
) ||
242 (MI
.getOperand(2).isImm() && MI
.getOperand(2).getImm() == 0);
244 return MI
.isAsCheapAsAMove();
248 LoongArchInstrInfo::getBranchDestBlock(const MachineInstr
&MI
) const {
249 assert(MI
.getDesc().isBranch() && "Unexpected opcode!");
250 // The branch target is always the last operand.
251 return MI
.getOperand(MI
.getNumExplicitOperands() - 1).getMBB();
254 static void parseCondBranch(MachineInstr
&LastInst
, MachineBasicBlock
*&Target
,
255 SmallVectorImpl
<MachineOperand
> &Cond
) {
256 // Block ends with fall-through condbranch.
257 assert(LastInst
.getDesc().isConditionalBranch() &&
258 "Unknown conditional branch");
259 int NumOp
= LastInst
.getNumExplicitOperands();
260 Target
= LastInst
.getOperand(NumOp
- 1).getMBB();
262 Cond
.push_back(MachineOperand::CreateImm(LastInst
.getOpcode()));
263 for (int i
= 0; i
< NumOp
- 1; i
++)
264 Cond
.push_back(LastInst
.getOperand(i
));
267 bool LoongArchInstrInfo::analyzeBranch(MachineBasicBlock
&MBB
,
268 MachineBasicBlock
*&TBB
,
269 MachineBasicBlock
*&FBB
,
270 SmallVectorImpl
<MachineOperand
> &Cond
,
271 bool AllowModify
) const {
275 // If the block has no terminators, it just falls into the block after it.
276 MachineBasicBlock::iterator I
= MBB
.getLastNonDebugInstr();
277 if (I
== MBB
.end() || !isUnpredicatedTerminator(*I
))
280 // Count the number of terminators and find the first unconditional or
282 MachineBasicBlock::iterator FirstUncondOrIndirectBr
= MBB
.end();
283 int NumTerminators
= 0;
284 for (auto J
= I
.getReverse(); J
!= MBB
.rend() && isUnpredicatedTerminator(*J
);
287 if (J
->getDesc().isUnconditionalBranch() ||
288 J
->getDesc().isIndirectBranch()) {
289 FirstUncondOrIndirectBr
= J
.getReverse();
293 // If AllowModify is true, we can erase any terminators after
294 // FirstUncondOrIndirectBR.
295 if (AllowModify
&& FirstUncondOrIndirectBr
!= MBB
.end()) {
296 while (std::next(FirstUncondOrIndirectBr
) != MBB
.end()) {
297 std::next(FirstUncondOrIndirectBr
)->eraseFromParent();
300 I
= FirstUncondOrIndirectBr
;
303 // Handle a single unconditional branch.
304 if (NumTerminators
== 1 && I
->getDesc().isUnconditionalBranch()) {
305 TBB
= getBranchDestBlock(*I
);
309 // Handle a single conditional branch.
310 if (NumTerminators
== 1 && I
->getDesc().isConditionalBranch()) {
311 parseCondBranch(*I
, TBB
, Cond
);
315 // Handle a conditional branch followed by an unconditional branch.
316 if (NumTerminators
== 2 && std::prev(I
)->getDesc().isConditionalBranch() &&
317 I
->getDesc().isUnconditionalBranch()) {
318 parseCondBranch(*std::prev(I
), TBB
, Cond
);
319 FBB
= getBranchDestBlock(*I
);
323 // Otherwise, we can't handle this.
327 bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp
,
328 int64_t BrOffset
) const {
331 llvm_unreachable("Unknown branch instruction!");
336 case LoongArch::BLTU
:
337 case LoongArch::BGEU
:
338 return isInt
<18>(BrOffset
);
339 case LoongArch::BEQZ
:
340 case LoongArch::BNEZ
:
341 case LoongArch::BCEQZ
:
342 case LoongArch::BCNEZ
:
343 return isInt
<23>(BrOffset
);
345 case LoongArch::PseudoBR
:
346 return isInt
<28>(BrOffset
);
350 unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock
&MBB
,
351 int *BytesRemoved
) const {
354 MachineBasicBlock::iterator I
= MBB
.getLastNonDebugInstr();
358 if (!I
->getDesc().isBranch())
361 // Remove the branch.
363 *BytesRemoved
+= getInstSizeInBytes(*I
);
364 I
->eraseFromParent();
368 if (I
== MBB
.begin())
371 if (!I
->getDesc().isConditionalBranch())
374 // Remove the branch.
376 *BytesRemoved
+= getInstSizeInBytes(*I
);
377 I
->eraseFromParent();
381 // Inserts a branch into the end of the specific MachineBasicBlock, returning
382 // the number of instructions inserted.
383 unsigned LoongArchInstrInfo::insertBranch(
384 MachineBasicBlock
&MBB
, MachineBasicBlock
*TBB
, MachineBasicBlock
*FBB
,
385 ArrayRef
<MachineOperand
> Cond
, const DebugLoc
&DL
, int *BytesAdded
) const {
389 // Shouldn't be a fall through.
390 assert(TBB
&& "insertBranch must not be told to insert a fallthrough");
391 assert(Cond
.size() <= 3 && Cond
.size() != 1 &&
392 "LoongArch branch conditions have at most two components!");
394 // Unconditional branch.
396 MachineInstr
&MI
= *BuildMI(&MBB
, DL
, get(LoongArch::PseudoBR
)).addMBB(TBB
);
398 *BytesAdded
+= getInstSizeInBytes(MI
);
402 // Either a one or two-way conditional branch.
403 MachineInstrBuilder MIB
= BuildMI(&MBB
, DL
, get(Cond
[0].getImm()));
404 for (unsigned i
= 1; i
< Cond
.size(); ++i
)
408 *BytesAdded
+= getInstSizeInBytes(*MIB
);
410 // One-way conditional branch.
414 // Two-way conditional branch.
415 MachineInstr
&MI
= *BuildMI(&MBB
, DL
, get(LoongArch::PseudoBR
)).addMBB(FBB
);
417 *BytesAdded
+= getInstSizeInBytes(MI
);
421 void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock
&MBB
,
422 MachineBasicBlock
&DestBB
,
423 MachineBasicBlock
&RestoreBB
,
426 RegScavenger
*RS
) const {
427 assert(RS
&& "RegScavenger required for long branching");
428 assert(MBB
.empty() &&
429 "new block should be inserted for expanding unconditional branch");
430 assert(MBB
.pred_size() == 1);
432 MachineFunction
*MF
= MBB
.getParent();
433 MachineRegisterInfo
&MRI
= MF
->getRegInfo();
434 const TargetRegisterInfo
*TRI
= MF
->getSubtarget().getRegisterInfo();
435 LoongArchMachineFunctionInfo
*LAFI
=
436 MF
->getInfo
<LoongArchMachineFunctionInfo
>();
438 if (!isInt
<32>(BrOffset
))
440 "Branch offsets outside of the signed 32-bit range not supported");
442 Register ScratchReg
= MRI
.createVirtualRegister(&LoongArch::GPRRegClass
);
445 MachineInstr
&PCALAU12I
=
446 *BuildMI(MBB
, II
, DL
, get(LoongArch::PCALAU12I
), ScratchReg
)
447 .addMBB(&DestBB
, LoongArchII::MO_PCREL_HI
);
449 *BuildMI(MBB
, II
, DL
,
450 get(STI
.is64Bit() ? LoongArch::ADDI_D
: LoongArch::ADDI_W
),
453 .addMBB(&DestBB
, LoongArchII::MO_PCREL_LO
);
454 BuildMI(MBB
, II
, DL
, get(LoongArch::PseudoBRIND
))
455 .addReg(ScratchReg
, RegState::Kill
)
458 RS
->enterBasicBlockEnd(MBB
);
459 Register Scav
= RS
->scavengeRegisterBackwards(
460 LoongArch::GPRRegClass
, PCALAU12I
.getIterator(), /*RestoreAfter=*/false,
461 /*SPAdj=*/0, /*AllowSpill=*/false);
462 if (Scav
!= LoongArch::NoRegister
)
463 RS
->setRegUsed(Scav
);
465 // When there is no scavenged register, it needs to specify a register.
466 // Specify t8 register because it won't be used too often.
467 Scav
= LoongArch::R20
;
468 int FrameIndex
= LAFI
->getBranchRelaxationSpillFrameIndex();
469 if (FrameIndex
== -1)
470 report_fatal_error("The function size is incorrectly estimated.");
471 storeRegToStackSlot(MBB
, PCALAU12I
, Scav
, /*IsKill=*/true, FrameIndex
,
472 &LoongArch::GPRRegClass
, TRI
, Register());
473 TRI
->eliminateFrameIndex(std::prev(PCALAU12I
.getIterator()),
474 /*SpAdj=*/0, /*FIOperandNum=*/1);
475 PCALAU12I
.getOperand(1).setMBB(&RestoreBB
);
476 ADDI
.getOperand(2).setMBB(&RestoreBB
);
477 loadRegFromStackSlot(RestoreBB
, RestoreBB
.end(), Scav
, FrameIndex
,
478 &LoongArch::GPRRegClass
, TRI
, Register());
479 TRI
->eliminateFrameIndex(RestoreBB
.back(),
480 /*SpAdj=*/0, /*FIOperandNum=*/1);
482 MRI
.replaceRegWith(ScratchReg
, Scav
);
486 static unsigned getOppositeBranchOpc(unsigned Opc
) {
489 llvm_unreachable("Unrecognized conditional branch");
491 return LoongArch::BNE
;
493 return LoongArch::BEQ
;
494 case LoongArch::BEQZ
:
495 return LoongArch::BNEZ
;
496 case LoongArch::BNEZ
:
497 return LoongArch::BEQZ
;
498 case LoongArch::BCEQZ
:
499 return LoongArch::BCNEZ
;
500 case LoongArch::BCNEZ
:
501 return LoongArch::BCEQZ
;
503 return LoongArch::BGE
;
505 return LoongArch::BLT
;
506 case LoongArch::BLTU
:
507 return LoongArch::BGEU
;
508 case LoongArch::BGEU
:
509 return LoongArch::BLTU
;
513 bool LoongArchInstrInfo::reverseBranchCondition(
514 SmallVectorImpl
<MachineOperand
> &Cond
) const {
515 assert((Cond
.size() && Cond
.size() <= 3) && "Invalid branch condition!");
516 Cond
[0].setImm(getOppositeBranchOpc(Cond
[0].getImm()));
520 std::pair
<unsigned, unsigned>
521 LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF
) const {
522 return std::make_pair(TF
, 0u);
525 ArrayRef
<std::pair
<unsigned, const char *>>
526 LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
527 using namespace LoongArchII
;
528 // TODO: Add more target flags.
529 static const std::pair
<unsigned, const char *> TargetFlags
[] = {
530 {MO_CALL
, "loongarch-call"},
531 {MO_CALL_PLT
, "loongarch-call-plt"},
532 {MO_PCREL_HI
, "loongarch-pcrel-hi"},
533 {MO_PCREL_LO
, "loongarch-pcrel-lo"},
534 {MO_PCREL64_LO
, "loongarch-pcrel64-lo"},
535 {MO_PCREL64_HI
, "loongarch-pcrel64-hi"},
536 {MO_GOT_PC_HI
, "loongarch-got-pc-hi"},
537 {MO_GOT_PC_LO
, "loongarch-got-pc-lo"},
538 {MO_GOT_PC64_LO
, "loongarch-got-pc64-lo"},
539 {MO_GOT_PC64_HI
, "loongarch-got-pc64-hi"},
540 {MO_LE_HI
, "loongarch-le-hi"},
541 {MO_LE_LO
, "loongarch-le-lo"},
542 {MO_LE64_LO
, "loongarch-le64-lo"},
543 {MO_LE64_HI
, "loongarch-le64-hi"},
544 {MO_IE_PC_HI
, "loongarch-ie-pc-hi"},
545 {MO_IE_PC_LO
, "loongarch-ie-pc-lo"},
546 {MO_IE_PC64_LO
, "loongarch-ie-pc64-lo"},
547 {MO_IE_PC64_HI
, "loongarch-ie-pc64-hi"},
548 {MO_DESC_PC_HI
, "loongarch-desc-pc-hi"},
549 {MO_DESC_PC_LO
, "loongarch-desc-pc-lo"},
550 {MO_DESC64_PC_LO
, "loongarch-desc64-pc-lo"},
551 {MO_DESC64_PC_HI
, "loongarch-desc64-pc-hi"},
552 {MO_DESC_LD
, "loongarch-desc-ld"},
553 {MO_DESC_CALL
, "loongarch-desc-call"},
554 {MO_LD_PC_HI
, "loongarch-ld-pc-hi"},
555 {MO_GD_PC_HI
, "loongarch-gd-pc-hi"}};
556 return ArrayRef(TargetFlags
);
559 // Returns true if this is the sext.w pattern, addi.w rd, rs, 0.
560 bool LoongArch::isSEXT_W(const MachineInstr
&MI
) {
561 return MI
.getOpcode() == LoongArch::ADDI_W
&& MI
.getOperand(1).isReg() &&
562 MI
.getOperand(2).isImm() && MI
.getOperand(2).getImm() == 0;