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
21 using namespace llvm;
22
23 #define GET_INSTRINFO_CTOR_DTOR
24 #include "LoongArchGenInstrInfo.inc"
25
LoongArchInstrInfo(LoongArchSubtarget & STI)26 LoongArchInstrInfo::LoongArchInstrInfo(LoongArchSubtarget &STI)
27 : LoongArchGenInstrInfo(LoongArch::ADJCALLSTACKDOWN,
28 LoongArch::ADJCALLSTACKUP),
29 STI(STI) {}
30
copyPhysReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,const DebugLoc & DL,MCRegister DstReg,MCRegister SrcReg,bool KillSrc) const31 void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
32 MachineBasicBlock::iterator MBBI,
33 const DebugLoc &DL, MCRegister DstReg,
34 MCRegister SrcReg, bool KillSrc) const {
35 if (LoongArch::GPRRegClass.contains(DstReg, SrcReg)) {
36 BuildMI(MBB, MBBI, DL, get(LoongArch::OR), DstReg)
37 .addReg(SrcReg, getKillRegState(KillSrc))
38 .addReg(LoongArch::R0);
39 return;
40 }
41
42 // GPR->CFR copy.
43 if (LoongArch::CFRRegClass.contains(DstReg) &&
44 LoongArch::GPRRegClass.contains(SrcReg)) {
45 BuildMI(MBB, MBBI, DL, get(LoongArch::MOVGR2CF), DstReg)
46 .addReg(SrcReg, getKillRegState(KillSrc));
47 return;
48 }
49 // CFR->GPR copy.
50 if (LoongArch::GPRRegClass.contains(DstReg) &&
51 LoongArch::CFRRegClass.contains(SrcReg)) {
52 BuildMI(MBB, MBBI, DL, get(LoongArch::MOVCF2GR), DstReg)
53 .addReg(SrcReg, getKillRegState(KillSrc));
54 return;
55 }
56
57 // FPR->FPR copies.
58 unsigned Opc;
59 if (LoongArch::FPR32RegClass.contains(DstReg, SrcReg)) {
60 Opc = LoongArch::FMOV_S;
61 } else if (LoongArch::FPR64RegClass.contains(DstReg, SrcReg)) {
62 Opc = LoongArch::FMOV_D;
63 } else {
64 // TODO: support other copies.
65 llvm_unreachable("Impossible reg-to-reg copy");
66 }
67
68 BuildMI(MBB, MBBI, DL, get(Opc), DstReg)
69 .addReg(SrcReg, getKillRegState(KillSrc));
70 }
71
storeRegToStackSlot(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,Register SrcReg,bool IsKill,int FI,const TargetRegisterClass * RC,const TargetRegisterInfo * TRI,Register VReg) const72 void LoongArchInstrInfo::storeRegToStackSlot(
73 MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register SrcReg,
74 bool IsKill, int FI, const TargetRegisterClass *RC,
75 const TargetRegisterInfo *TRI, Register VReg) const {
76 DebugLoc DL;
77 if (I != MBB.end())
78 DL = I->getDebugLoc();
79 MachineFunction *MF = MBB.getParent();
80 MachineFrameInfo &MFI = MF->getFrameInfo();
81
82 unsigned Opcode;
83 if (LoongArch::GPRRegClass.hasSubClassEq(RC))
84 Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32
85 ? LoongArch::ST_W
86 : LoongArch::ST_D;
87 else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))
88 Opcode = LoongArch::FST_S;
89 else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))
90 Opcode = LoongArch::FST_D;
91 else if (LoongArch::CFRRegClass.hasSubClassEq(RC))
92 Opcode = LoongArch::PseudoST_CFR;
93 else
94 llvm_unreachable("Can't store this register to stack slot");
95
96 MachineMemOperand *MMO = MF->getMachineMemOperand(
97 MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOStore,
98 MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
99
100 BuildMI(MBB, I, DL, get(Opcode))
101 .addReg(SrcReg, getKillRegState(IsKill))
102 .addFrameIndex(FI)
103 .addImm(0)
104 .addMemOperand(MMO);
105 }
106
loadRegFromStackSlot(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,Register DstReg,int FI,const TargetRegisterClass * RC,const TargetRegisterInfo * TRI,Register VReg) const107 void LoongArchInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
108 MachineBasicBlock::iterator I,
109 Register DstReg, int FI,
110 const TargetRegisterClass *RC,
111 const TargetRegisterInfo *TRI,
112 Register VReg) const {
113 DebugLoc DL;
114 if (I != MBB.end())
115 DL = I->getDebugLoc();
116 MachineFunction *MF = MBB.getParent();
117 MachineFrameInfo &MFI = MF->getFrameInfo();
118
119 unsigned Opcode;
120 if (LoongArch::GPRRegClass.hasSubClassEq(RC))
121 Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32
122 ? LoongArch::LD_W
123 : LoongArch::LD_D;
124 else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))
125 Opcode = LoongArch::FLD_S;
126 else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))
127 Opcode = LoongArch::FLD_D;
128 else if (LoongArch::CFRRegClass.hasSubClassEq(RC))
129 Opcode = LoongArch::PseudoLD_CFR;
130 else
131 llvm_unreachable("Can't load this register from stack slot");
132
133 MachineMemOperand *MMO = MF->getMachineMemOperand(
134 MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad,
135 MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
136
137 BuildMI(MBB, I, DL, get(Opcode), DstReg)
138 .addFrameIndex(FI)
139 .addImm(0)
140 .addMemOperand(MMO);
141 }
142
movImm(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,const DebugLoc & DL,Register DstReg,uint64_t Val,MachineInstr::MIFlag Flag) const143 void LoongArchInstrInfo::movImm(MachineBasicBlock &MBB,
144 MachineBasicBlock::iterator MBBI,
145 const DebugLoc &DL, Register DstReg,
146 uint64_t Val, MachineInstr::MIFlag Flag) const {
147 Register SrcReg = LoongArch::R0;
148
149 if (!STI.is64Bit() && !isInt<32>(Val))
150 report_fatal_error("Should only materialize 32-bit constants for LA32");
151
152 auto Seq = LoongArchMatInt::generateInstSeq(Val);
153 assert(!Seq.empty());
154
155 for (auto &Inst : Seq) {
156 switch (Inst.Opc) {
157 case LoongArch::LU12I_W:
158 BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)
159 .addImm(Inst.Imm)
160 .setMIFlag(Flag);
161 break;
162 case LoongArch::ADDI_W:
163 case LoongArch::ORI:
164 case LoongArch::LU32I_D: // "rj" is needed due to InstrInfo pattern
165 case LoongArch::LU52I_D:
166 BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)
167 .addReg(SrcReg, RegState::Kill)
168 .addImm(Inst.Imm)
169 .setMIFlag(Flag);
170 break;
171 default:
172 assert(false && "Unknown insn emitted by LoongArchMatInt");
173 }
174
175 // Only the first instruction has $zero as its source.
176 SrcReg = DstReg;
177 }
178 }
179
getInstSizeInBytes(const MachineInstr & MI) const180 unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
181 unsigned Opcode = MI.getOpcode();
182
183 if (Opcode == TargetOpcode::INLINEASM ||
184 Opcode == TargetOpcode::INLINEASM_BR) {
185 const MachineFunction *MF = MI.getParent()->getParent();
186 const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
187 return getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI);
188 }
189 return MI.getDesc().getSize();
190 }
191
192 MachineBasicBlock *
getBranchDestBlock(const MachineInstr & MI) const193 LoongArchInstrInfo::getBranchDestBlock(const MachineInstr &MI) const {
194 assert(MI.getDesc().isBranch() && "Unexpected opcode!");
195 // The branch target is always the last operand.
196 return MI.getOperand(MI.getNumExplicitOperands() - 1).getMBB();
197 }
198
parseCondBranch(MachineInstr & LastInst,MachineBasicBlock * & Target,SmallVectorImpl<MachineOperand> & Cond)199 static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target,
200 SmallVectorImpl<MachineOperand> &Cond) {
201 // Block ends with fall-through condbranch.
202 assert(LastInst.getDesc().isConditionalBranch() &&
203 "Unknown conditional branch");
204 int NumOp = LastInst.getNumExplicitOperands();
205 Target = LastInst.getOperand(NumOp - 1).getMBB();
206
207 Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode()));
208 for (int i = 0; i < NumOp - 1; i++)
209 Cond.push_back(LastInst.getOperand(i));
210 }
211
analyzeBranch(MachineBasicBlock & MBB,MachineBasicBlock * & TBB,MachineBasicBlock * & FBB,SmallVectorImpl<MachineOperand> & Cond,bool AllowModify) const212 bool LoongArchInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
213 MachineBasicBlock *&TBB,
214 MachineBasicBlock *&FBB,
215 SmallVectorImpl<MachineOperand> &Cond,
216 bool AllowModify) const {
217 TBB = FBB = nullptr;
218 Cond.clear();
219
220 // If the block has no terminators, it just falls into the block after it.
221 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
222 if (I == MBB.end() || !isUnpredicatedTerminator(*I))
223 return false;
224
225 // Count the number of terminators and find the first unconditional or
226 // indirect branch.
227 MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end();
228 int NumTerminators = 0;
229 for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(*J);
230 J++) {
231 NumTerminators++;
232 if (J->getDesc().isUnconditionalBranch() ||
233 J->getDesc().isIndirectBranch()) {
234 FirstUncondOrIndirectBr = J.getReverse();
235 }
236 }
237
238 // If AllowModify is true, we can erase any terminators after
239 // FirstUncondOrIndirectBR.
240 if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) {
241 while (std::next(FirstUncondOrIndirectBr) != MBB.end()) {
242 std::next(FirstUncondOrIndirectBr)->eraseFromParent();
243 NumTerminators--;
244 }
245 I = FirstUncondOrIndirectBr;
246 }
247
248 // Handle a single unconditional branch.
249 if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) {
250 TBB = getBranchDestBlock(*I);
251 return false;
252 }
253
254 // Handle a single conditional branch.
255 if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) {
256 parseCondBranch(*I, TBB, Cond);
257 return false;
258 }
259
260 // Handle a conditional branch followed by an unconditional branch.
261 if (NumTerminators == 2 && std::prev(I)->getDesc().isConditionalBranch() &&
262 I->getDesc().isUnconditionalBranch()) {
263 parseCondBranch(*std::prev(I), TBB, Cond);
264 FBB = getBranchDestBlock(*I);
265 return false;
266 }
267
268 // Otherwise, we can't handle this.
269 return true;
270 }
271
isBranchOffsetInRange(unsigned BranchOp,int64_t BrOffset) const272 bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
273 int64_t BrOffset) const {
274 switch (BranchOp) {
275 default:
276 llvm_unreachable("Unknown branch instruction!");
277 case LoongArch::BEQ:
278 case LoongArch::BNE:
279 case LoongArch::BLT:
280 case LoongArch::BGE:
281 case LoongArch::BLTU:
282 case LoongArch::BGEU:
283 return isInt<18>(BrOffset);
284 case LoongArch::BEQZ:
285 case LoongArch::BNEZ:
286 case LoongArch::BCEQZ:
287 case LoongArch::BCNEZ:
288 return isInt<23>(BrOffset);
289 case LoongArch::B:
290 case LoongArch::PseudoBR:
291 return isInt<28>(BrOffset);
292 }
293 }
294
removeBranch(MachineBasicBlock & MBB,int * BytesRemoved) const295 unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB,
296 int *BytesRemoved) const {
297 if (BytesRemoved)
298 *BytesRemoved = 0;
299 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
300 if (I == MBB.end())
301 return 0;
302
303 if (!I->getDesc().isBranch())
304 return 0;
305
306 // Remove the branch.
307 if (BytesRemoved)
308 *BytesRemoved += getInstSizeInBytes(*I);
309 I->eraseFromParent();
310
311 I = MBB.end();
312
313 if (I == MBB.begin())
314 return 1;
315 --I;
316 if (!I->getDesc().isConditionalBranch())
317 return 1;
318
319 // Remove the branch.
320 if (BytesRemoved)
321 *BytesRemoved += getInstSizeInBytes(*I);
322 I->eraseFromParent();
323 return 2;
324 }
325
326 // Inserts a branch into the end of the specific MachineBasicBlock, returning
327 // the number of instructions inserted.
insertBranch(MachineBasicBlock & MBB,MachineBasicBlock * TBB,MachineBasicBlock * FBB,ArrayRef<MachineOperand> Cond,const DebugLoc & DL,int * BytesAdded) const328 unsigned LoongArchInstrInfo::insertBranch(
329 MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
330 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
331 if (BytesAdded)
332 *BytesAdded = 0;
333
334 // Shouldn't be a fall through.
335 assert(TBB && "insertBranch must not be told to insert a fallthrough");
336 assert(Cond.size() <= 3 && Cond.size() != 1 &&
337 "LoongArch branch conditions have at most two components!");
338
339 // Unconditional branch.
340 if (Cond.empty()) {
341 MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(TBB);
342 if (BytesAdded)
343 *BytesAdded += getInstSizeInBytes(MI);
344 return 1;
345 }
346
347 // Either a one or two-way conditional branch.
348 MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(Cond[0].getImm()));
349 for (unsigned i = 1; i < Cond.size(); ++i)
350 MIB.add(Cond[i]);
351 MIB.addMBB(TBB);
352 if (BytesAdded)
353 *BytesAdded += getInstSizeInBytes(*MIB);
354
355 // One-way conditional branch.
356 if (!FBB)
357 return 1;
358
359 // Two-way conditional branch.
360 MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(FBB);
361 if (BytesAdded)
362 *BytesAdded += getInstSizeInBytes(MI);
363 return 2;
364 }
365
insertIndirectBranch(MachineBasicBlock & MBB,MachineBasicBlock & DestBB,MachineBasicBlock & RestoreBB,const DebugLoc & DL,int64_t BrOffset,RegScavenger * RS) const366 void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,
367 MachineBasicBlock &DestBB,
368 MachineBasicBlock &RestoreBB,
369 const DebugLoc &DL,
370 int64_t BrOffset,
371 RegScavenger *RS) const {
372 assert(RS && "RegScavenger required for long branching");
373 assert(MBB.empty() &&
374 "new block should be inserted for expanding unconditional branch");
375 assert(MBB.pred_size() == 1);
376
377 MachineFunction *MF = MBB.getParent();
378 MachineRegisterInfo &MRI = MF->getRegInfo();
379 const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
380 LoongArchMachineFunctionInfo *LAFI =
381 MF->getInfo<LoongArchMachineFunctionInfo>();
382
383 if (!isInt<32>(BrOffset))
384 report_fatal_error(
385 "Branch offsets outside of the signed 32-bit range not supported");
386
387 Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
388 auto II = MBB.end();
389
390 MachineInstr &PCALAU12I =
391 *BuildMI(MBB, II, DL, get(LoongArch::PCALAU12I), ScratchReg)
392 .addMBB(&DestBB, LoongArchII::MO_PCREL_HI);
393 MachineInstr &ADDI =
394 *BuildMI(MBB, II, DL,
395 get(STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W),
396 ScratchReg)
397 .addReg(ScratchReg)
398 .addMBB(&DestBB, LoongArchII::MO_PCREL_LO);
399 BuildMI(MBB, II, DL, get(LoongArch::PseudoBRIND))
400 .addReg(ScratchReg, RegState::Kill)
401 .addImm(0);
402
403 RS->enterBasicBlockEnd(MBB);
404 Register Scav = RS->scavengeRegisterBackwards(
405 LoongArch::GPRRegClass, PCALAU12I.getIterator(), /*RestoreAfter=*/false,
406 /*SPAdj=*/0, /*AllowSpill=*/false);
407 if (Scav != LoongArch::NoRegister)
408 RS->setRegUsed(Scav);
409 else {
410 // When there is no scavenged register, it needs to specify a register.
411 // Specify t8 register because it won't be used too often.
412 Scav = LoongArch::R20;
413 int FrameIndex = LAFI->getBranchRelaxationSpillFrameIndex();
414 if (FrameIndex == -1)
415 report_fatal_error("The function size is incorrectly estimated.");
416 storeRegToStackSlot(MBB, PCALAU12I, Scav, /*IsKill=*/true, FrameIndex,
417 &LoongArch::GPRRegClass, TRI, Register());
418 TRI->eliminateFrameIndex(std::prev(PCALAU12I.getIterator()),
419 /*SpAdj=*/0, /*FIOperandNum=*/1);
420 PCALAU12I.getOperand(1).setMBB(&RestoreBB);
421 ADDI.getOperand(2).setMBB(&RestoreBB);
422 loadRegFromStackSlot(RestoreBB, RestoreBB.end(), Scav, FrameIndex,
423 &LoongArch::GPRRegClass, TRI, Register());
424 TRI->eliminateFrameIndex(RestoreBB.back(),
425 /*SpAdj=*/0, /*FIOperandNum=*/1);
426 }
427 MRI.replaceRegWith(ScratchReg, Scav);
428 MRI.clearVirtRegs();
429 }
430
getOppositeBranchOpc(unsigned Opc)431 static unsigned getOppositeBranchOpc(unsigned Opc) {
432 switch (Opc) {
433 default:
434 llvm_unreachable("Unrecognized conditional branch");
435 case LoongArch::BEQ:
436 return LoongArch::BNE;
437 case LoongArch::BNE:
438 return LoongArch::BEQ;
439 case LoongArch::BEQZ:
440 return LoongArch::BNEZ;
441 case LoongArch::BNEZ:
442 return LoongArch::BEQZ;
443 case LoongArch::BCEQZ:
444 return LoongArch::BCNEZ;
445 case LoongArch::BCNEZ:
446 return LoongArch::BCEQZ;
447 case LoongArch::BLT:
448 return LoongArch::BGE;
449 case LoongArch::BGE:
450 return LoongArch::BLT;
451 case LoongArch::BLTU:
452 return LoongArch::BGEU;
453 case LoongArch::BGEU:
454 return LoongArch::BLTU;
455 }
456 }
457
reverseBranchCondition(SmallVectorImpl<MachineOperand> & Cond) const458 bool LoongArchInstrInfo::reverseBranchCondition(
459 SmallVectorImpl<MachineOperand> &Cond) const {
460 assert((Cond.size() && Cond.size() <= 3) && "Invalid branch condition!");
461 Cond[0].setImm(getOppositeBranchOpc(Cond[0].getImm()));
462 return false;
463 }
464
465 std::pair<unsigned, unsigned>
decomposeMachineOperandsTargetFlags(unsigned TF) const466 LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
467 return std::make_pair(TF, 0u);
468 }
469
470 ArrayRef<std::pair<unsigned, const char *>>
getSerializableDirectMachineOperandTargetFlags() const471 LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
472 using namespace LoongArchII;
473 // TODO: Add more target flags.
474 static const std::pair<unsigned, const char *> TargetFlags[] = {
475 {MO_CALL, "loongarch-call"},
476 {MO_CALL_PLT, "loongarch-call-plt"},
477 {MO_PCREL_HI, "loongarch-pcrel-hi"},
478 {MO_PCREL_LO, "loongarch-pcrel-lo"},
479 {MO_GOT_PC_HI, "loongarch-got-pc-hi"},
480 {MO_GOT_PC_LO, "loongarch-got-pc-lo"},
481 {MO_LE_HI, "loongarch-le-hi"},
482 {MO_LE_LO, "loongarch-le-lo"},
483 {MO_IE_PC_HI, "loongarch-ie-pc-hi"},
484 {MO_IE_PC_LO, "loongarch-ie-pc-lo"},
485 {MO_LD_PC_HI, "loongarch-ld-pc-hi"},
486 {MO_GD_PC_HI, "loongarch-gd-pc-hi"}};
487 return ArrayRef(TargetFlags);
488 }
489