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/MCInstBuilder.h" |
22 | |
23 | using namespace llvm; |
24 | |
25 | #define GET_INSTRINFO_CTOR_DTOR |
26 | #include "LoongArchGenInstrInfo.inc" |
27 | |
28 | LoongArchInstrInfo::LoongArchInstrInfo(LoongArchSubtarget &STI) |
29 | : LoongArchGenInstrInfo(LoongArch::ADJCALLSTACKDOWN, |
30 | LoongArch::ADJCALLSTACKUP), |
31 | STI(STI) {} |
32 | |
33 | MCInst LoongArchInstrInfo::getNop() const { |
34 | return MCInstBuilder(LoongArch::ANDI) |
35 | .addReg(Reg: LoongArch::R0) |
36 | .addReg(Reg: LoongArch::R0) |
37 | .addImm(Val: 0); |
38 | } |
39 | |
40 | void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock &MBB, |
41 | MachineBasicBlock::iterator MBBI, |
42 | const DebugLoc &DL, Register DstReg, |
43 | Register SrcReg, bool KillSrc, |
44 | bool RenamableDest, |
45 | bool RenamableSrc) const { |
46 | if (LoongArch::GPRRegClass.contains(Reg1: DstReg, Reg2: SrcReg)) { |
47 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: LoongArch::OR), DestReg: DstReg) |
48 | .addReg(RegNo: SrcReg, flags: getKillRegState(B: KillSrc)) |
49 | .addReg(RegNo: LoongArch::R0); |
50 | return; |
51 | } |
52 | |
53 | // VR->VR copies. |
54 | if (LoongArch::LSX128RegClass.contains(Reg1: DstReg, Reg2: SrcReg)) { |
55 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: LoongArch::VORI_B), DestReg: DstReg) |
56 | .addReg(RegNo: SrcReg, flags: getKillRegState(B: KillSrc)) |
57 | .addImm(Val: 0); |
58 | return; |
59 | } |
60 | |
61 | // XR->XR copies. |
62 | if (LoongArch::LASX256RegClass.contains(Reg1: DstReg, Reg2: SrcReg)) { |
63 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: LoongArch::XVORI_B), DestReg: DstReg) |
64 | .addReg(RegNo: SrcReg, flags: getKillRegState(B: KillSrc)) |
65 | .addImm(Val: 0); |
66 | return; |
67 | } |
68 | |
69 | // GPR->CFR copy. |
70 | if (LoongArch::CFRRegClass.contains(Reg: DstReg) && |
71 | LoongArch::GPRRegClass.contains(Reg: SrcReg)) { |
72 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: LoongArch::MOVGR2CF), DestReg: DstReg) |
73 | .addReg(RegNo: SrcReg, flags: getKillRegState(B: KillSrc)); |
74 | return; |
75 | } |
76 | // CFR->GPR copy. |
77 | if (LoongArch::GPRRegClass.contains(Reg: DstReg) && |
78 | LoongArch::CFRRegClass.contains(Reg: SrcReg)) { |
79 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: LoongArch::MOVCF2GR), DestReg: DstReg) |
80 | .addReg(RegNo: SrcReg, flags: getKillRegState(B: KillSrc)); |
81 | return; |
82 | } |
83 | // CFR->CFR copy. |
84 | if (LoongArch::CFRRegClass.contains(Reg1: DstReg, Reg2: SrcReg)) { |
85 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: LoongArch::PseudoCopyCFR), DestReg: DstReg) |
86 | .addReg(RegNo: SrcReg, flags: getKillRegState(B: KillSrc)); |
87 | return; |
88 | } |
89 | |
90 | // FPR->FPR copies. |
91 | unsigned Opc; |
92 | if (LoongArch::FPR32RegClass.contains(Reg1: DstReg, Reg2: SrcReg)) { |
93 | Opc = LoongArch::FMOV_S; |
94 | } else if (LoongArch::FPR64RegClass.contains(Reg1: DstReg, Reg2: SrcReg)) { |
95 | Opc = LoongArch::FMOV_D; |
96 | } else if (LoongArch::GPRRegClass.contains(Reg: DstReg) && |
97 | LoongArch::FPR32RegClass.contains(Reg: SrcReg)) { |
98 | // FPR32 -> GPR copies |
99 | Opc = LoongArch::MOVFR2GR_S; |
100 | } else if (LoongArch::GPRRegClass.contains(Reg: DstReg) && |
101 | LoongArch::FPR64RegClass.contains(Reg: 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(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: Opc), DestReg: DstReg) |
110 | .addReg(RegNo: SrcReg, flags: getKillRegState(B: KillSrc)); |
111 | } |
112 | |
113 | void LoongArchInstrInfo::storeRegToStackSlot( |
114 | MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register SrcReg, |
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(RC: 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 | |
139 | MachineMemOperand *MMO = MF->getMachineMemOperand( |
140 | PtrInfo: MachinePointerInfo::getFixedStack(MF&: *MF, FI), F: MachineMemOperand::MOStore, |
141 | Size: MFI.getObjectSize(ObjectIdx: FI), BaseAlignment: MFI.getObjectAlign(ObjectIdx: FI)); |
142 | |
143 | BuildMI(BB&: MBB, I, MIMD: DebugLoc(), MCID: get(Opcode)) |
144 | .addReg(RegNo: SrcReg, flags: getKillRegState(B: IsKill)) |
145 | .addFrameIndex(Idx: FI) |
146 | .addImm(Val: 0) |
147 | .addMemOperand(MMO); |
148 | } |
149 | |
150 | void LoongArchInstrInfo::loadRegFromStackSlot( |
151 | MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register DstReg, |
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(RC: 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 | |
178 | MachineMemOperand *MMO = MF->getMachineMemOperand( |
179 | PtrInfo: MachinePointerInfo::getFixedStack(MF&: *MF, FI), F: MachineMemOperand::MOLoad, |
180 | Size: MFI.getObjectSize(ObjectIdx: FI), BaseAlignment: MFI.getObjectAlign(ObjectIdx: FI)); |
181 | |
182 | BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode), DestReg: DstReg) |
183 | .addFrameIndex(Idx: FI) |
184 | .addImm(Val: 0) |
185 | .addMemOperand(MMO); |
186 | } |
187 | |
188 | void LoongArchInstrInfo::movImm(MachineBasicBlock &MBB, |
189 | MachineBasicBlock::iterator MBBI, |
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>(x: Val)) |
195 | report_fatal_error(reason: "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(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: Inst.Opc), DestReg: DstReg) |
204 | .addImm(Val: 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(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: Inst.Opc), DestReg: DstReg) |
212 | .addReg(RegNo: SrcReg, flags: RegState::Kill) |
213 | .addImm(Val: Inst.Imm) |
214 | .setMIFlag(Flag); |
215 | break; |
216 | case LoongArch::BSTRINS_D: |
217 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: get(Opcode: Inst.Opc), DestReg: DstReg) |
218 | .addReg(RegNo: SrcReg, flags: RegState::Kill) |
219 | .addReg(RegNo: SrcReg, flags: RegState::Kill) |
220 | .addImm(Val: Inst.Imm >> 32) |
221 | .addImm(Val: 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 | |
233 | unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { |
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(Str: MI.getOperand(i: 0).getSymbolName(), MAI: *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 | |
263 | bool LoongArchInstrInfo::isAsCheapAsAMove(const MachineInstr &MI) const { |
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(i: 1).isReg() && |
272 | MI.getOperand(i: 1).getReg() == LoongArch::R0) || |
273 | (MI.getOperand(i: 2).isImm() && MI.getOperand(i: 2).getImm() == 0); |
274 | } |
275 | return MI.isAsCheapAsAMove(); |
276 | } |
277 | |
278 | MachineBasicBlock * |
279 | LoongArchInstrInfo::getBranchDestBlock(const MachineInstr &MI) const { |
280 | assert(MI.getDesc().isBranch() && "Unexpected opcode!" ); |
281 | // The branch target is always the last operand. |
282 | return MI.getOperand(i: MI.getNumExplicitOperands() - 1).getMBB(); |
283 | } |
284 | |
285 | static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target, |
286 | SmallVectorImpl<MachineOperand> &Cond) { |
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(i: NumOp - 1).getMBB(); |
292 | |
293 | Cond.push_back(Elt: MachineOperand::CreateImm(Val: LastInst.getOpcode())); |
294 | for (int i = 0; i < NumOp - 1; i++) |
295 | Cond.push_back(Elt: LastInst.getOperand(i)); |
296 | } |
297 | |
298 | bool LoongArchInstrInfo::analyzeBranch(MachineBasicBlock &MBB, |
299 | MachineBasicBlock *&TBB, |
300 | MachineBasicBlock *&FBB, |
301 | SmallVectorImpl<MachineOperand> &Cond, |
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(MI: *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(MI: *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(x: FirstUncondOrIndirectBr) != MBB.end()) { |
328 | std::next(x: FirstUncondOrIndirectBr)->eraseFromParent(); |
329 | NumTerminators--; |
330 | } |
331 | I = FirstUncondOrIndirectBr; |
332 | } |
333 | |
334 | // Handle a single unconditional branch. |
335 | if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) { |
336 | TBB = getBranchDestBlock(MI: *I); |
337 | return false; |
338 | } |
339 | |
340 | // Handle a single conditional branch. |
341 | if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) { |
342 | parseCondBranch(LastInst&: *I, Target&: TBB, Cond); |
343 | return false; |
344 | } |
345 | |
346 | // Handle a conditional branch followed by an unconditional branch. |
347 | if (NumTerminators == 2 && std::prev(x: I)->getDesc().isConditionalBranch() && |
348 | I->getDesc().isUnconditionalBranch()) { |
349 | parseCondBranch(LastInst&: *std::prev(x: I), Target&: TBB, Cond); |
350 | FBB = getBranchDestBlock(MI: *I); |
351 | return false; |
352 | } |
353 | |
354 | // Otherwise, we can't handle this. |
355 | return true; |
356 | } |
357 | |
358 | bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp, |
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>(x: BrOffset); |
370 | case LoongArch::BEQZ: |
371 | case LoongArch::BNEZ: |
372 | case LoongArch::BCEQZ: |
373 | case LoongArch::BCNEZ: |
374 | return isInt<23>(x: BrOffset); |
375 | case LoongArch::B: |
376 | case LoongArch::PseudoBR: |
377 | return isInt<28>(x: BrOffset); |
378 | } |
379 | } |
380 | |
381 | bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI, |
382 | const MachineBasicBlock *MBB, |
383 | const MachineFunction &MF) const { |
384 | if (TargetInstrInfo::isSchedulingBoundary(MI, MBB, MF)) |
385 | return true; |
386 | |
387 | auto MII = MI.getIterator(); |
388 | auto MIE = MBB->end(); |
389 | |
390 | // According to psABI v2.30: |
391 | // |
392 | // https://github.com/loongson/la-abi-specs/releases/tag/v2.30 |
393 | // |
394 | // The following instruction patterns are prohibited from being reordered: |
395 | // |
396 | // * pcalau12i $a0, %pc_hi20(s) |
397 | // addi.d $a1, $zero, %pc_lo12(s) |
398 | // lu32i.d $a1, %pc64_lo20(s) |
399 | // lu52i.d $a1, $a1, %pc64_hi12(s) |
400 | // |
401 | // * pcalau12i $a0, %got_pc_hi20(s) | %ld_pc_hi20(s) | %gd_pc_hi20(s) |
402 | // addi.d $a1, $zero, %got_pc_lo12(s) |
403 | // lu32i.d $a1, %got64_pc_lo20(s) |
404 | // lu52i.d $a1, $a1, %got64_pc_hi12(s) |
405 | // |
406 | // * pcalau12i $a0, %ie_pc_hi20(s) |
407 | // addi.d $a1, $zero, %ie_pc_lo12(s) |
408 | // lu32i.d $a1, %ie64_pc_lo20(s) |
409 | // lu52i.d $a1, $a1, %ie64_pc_hi12(s) |
410 | // |
411 | // * pcalau12i $a0, %desc_pc_hi20(s) |
412 | // addi.d $a1, $zero, %desc_pc_lo12(s) |
413 | // lu32i.d $a1, %desc64_pc_lo20(s) |
414 | // lu52i.d $a1, $a1, %desc64_pc_hi12(s) |
415 | // |
416 | // For simplicity, only pcalau12i and lu52i.d are marked as scheduling |
417 | // boundaries, and the instructions between them are guaranteed to be |
418 | // ordered according to data dependencies. |
419 | switch (MI.getOpcode()) { |
420 | case LoongArch::PCALAU12I: { |
421 | auto AddI = std::next(x: MII); |
422 | if (AddI == MIE || AddI->getOpcode() != LoongArch::ADDI_D) |
423 | break; |
424 | auto Lu32I = std::next(x: AddI); |
425 | if (Lu32I == MIE || Lu32I->getOpcode() != LoongArch::LU32I_D) |
426 | break; |
427 | auto MO0 = MI.getOperand(i: 1).getTargetFlags(); |
428 | auto MO1 = AddI->getOperand(i: 2).getTargetFlags(); |
429 | auto MO2 = Lu32I->getOperand(i: 2).getTargetFlags(); |
430 | if (MO0 == LoongArchII::MO_PCREL_HI && MO1 == LoongArchII::MO_PCREL_LO && |
431 | MO2 == LoongArchII::MO_PCREL64_LO) |
432 | return true; |
433 | if ((MO0 == LoongArchII::MO_GOT_PC_HI || MO0 == LoongArchII::MO_LD_PC_HI || |
434 | MO0 == LoongArchII::MO_GD_PC_HI) && |
435 | MO1 == LoongArchII::MO_GOT_PC_LO && MO2 == LoongArchII::MO_GOT_PC64_LO) |
436 | return true; |
437 | if (MO0 == LoongArchII::MO_IE_PC_HI && MO1 == LoongArchII::MO_IE_PC_LO && |
438 | MO2 == LoongArchII::MO_IE_PC64_LO) |
439 | return true; |
440 | if (MO0 == LoongArchII::MO_DESC_PC_HI && |
441 | MO1 == LoongArchII::MO_DESC_PC_LO && |
442 | MO2 == LoongArchII::MO_DESC64_PC_LO) |
443 | return true; |
444 | break; |
445 | } |
446 | case LoongArch::LU52I_D: { |
447 | auto MO = MI.getOperand(i: 2).getTargetFlags(); |
448 | if (MO == LoongArchII::MO_PCREL64_HI || MO == LoongArchII::MO_GOT_PC64_HI || |
449 | MO == LoongArchII::MO_IE_PC64_HI || MO == LoongArchII::MO_DESC64_PC_HI) |
450 | return true; |
451 | break; |
452 | } |
453 | default: |
454 | break; |
455 | } |
456 | |
457 | const auto &STI = MF.getSubtarget<LoongArchSubtarget>(); |
458 | if (STI.hasFeature(Feature: LoongArch::FeatureRelax)) { |
459 | // When linker relaxation enabled, the following instruction patterns are |
460 | // prohibited from being reordered: |
461 | // |
462 | // * pcalau12i $a0, %pc_hi20(s) |
463 | // addi.w/d $a0, $a0, %pc_lo12(s) |
464 | // |
465 | // * pcalau12i $a0, %got_pc_hi20(s) |
466 | // ld.w/d $a0, $a0, %got_pc_lo12(s) |
467 | // |
468 | // * pcalau12i $a0, %ld_pc_hi20(s) | %gd_pc_hi20(s) |
469 | // addi.w/d $a0, $a0, %got_pc_lo12(s) |
470 | // |
471 | // * pcalau12i $a0, %desc_pc_hi20(s) |
472 | // addi.w/d $a0, $a0, %desc_pc_lo12(s) |
473 | // ld.w/d $ra, $a0, %desc_ld(s) |
474 | // jirl $ra, $ra, %desc_call(s) |
475 | unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; |
476 | unsigned LdOp = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; |
477 | switch (MI.getOpcode()) { |
478 | case LoongArch::PCALAU12I: { |
479 | auto MO0 = LoongArchII::getDirectFlags(MO: MI.getOperand(i: 1)); |
480 | auto SecondOp = std::next(x: MII); |
481 | if (MO0 == LoongArchII::MO_DESC_PC_HI) { |
482 | if (SecondOp == MIE || SecondOp->getOpcode() != AddiOp) |
483 | break; |
484 | auto Ld = std::next(x: SecondOp); |
485 | if (Ld == MIE || Ld->getOpcode() != LdOp) |
486 | break; |
487 | auto MO1 = LoongArchII::getDirectFlags(MO: SecondOp->getOperand(i: 2)); |
488 | auto MO2 = LoongArchII::getDirectFlags(MO: Ld->getOperand(i: 2)); |
489 | if (MO1 == LoongArchII::MO_DESC_PC_LO && MO2 == LoongArchII::MO_DESC_LD) |
490 | return true; |
491 | break; |
492 | } |
493 | if (SecondOp == MIE || |
494 | (SecondOp->getOpcode() != AddiOp && SecondOp->getOpcode() != LdOp)) |
495 | break; |
496 | auto MO1 = LoongArchII::getDirectFlags(MO: SecondOp->getOperand(i: 2)); |
497 | if (MO0 == LoongArchII::MO_PCREL_HI && SecondOp->getOpcode() == AddiOp && |
498 | MO1 == LoongArchII::MO_PCREL_LO) |
499 | return true; |
500 | if (MO0 == LoongArchII::MO_GOT_PC_HI && SecondOp->getOpcode() == LdOp && |
501 | MO1 == LoongArchII::MO_GOT_PC_LO) |
502 | return true; |
503 | if ((MO0 == LoongArchII::MO_LD_PC_HI || |
504 | MO0 == LoongArchII::MO_GD_PC_HI) && |
505 | SecondOp->getOpcode() == AddiOp && MO1 == LoongArchII::MO_GOT_PC_LO) |
506 | return true; |
507 | break; |
508 | } |
509 | case LoongArch::ADDI_W: |
510 | case LoongArch::ADDI_D: { |
511 | auto MO = LoongArchII::getDirectFlags(MO: MI.getOperand(i: 2)); |
512 | if (MO == LoongArchII::MO_PCREL_LO || MO == LoongArchII::MO_GOT_PC_LO) |
513 | return true; |
514 | break; |
515 | } |
516 | case LoongArch::LD_W: |
517 | case LoongArch::LD_D: { |
518 | auto MO = LoongArchII::getDirectFlags(MO: MI.getOperand(i: 2)); |
519 | if (MO == LoongArchII::MO_GOT_PC_LO) |
520 | return true; |
521 | break; |
522 | } |
523 | case LoongArch::PseudoDESC_CALL: { |
524 | auto MO = LoongArchII::getDirectFlags(MO: MI.getOperand(i: 2)); |
525 | if (MO == LoongArchII::MO_DESC_CALL) |
526 | return true; |
527 | break; |
528 | } |
529 | default: |
530 | break; |
531 | } |
532 | } |
533 | |
534 | return false; |
535 | } |
536 | |
537 | unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB, |
538 | int *BytesRemoved) const { |
539 | if (BytesRemoved) |
540 | *BytesRemoved = 0; |
541 | MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); |
542 | if (I == MBB.end()) |
543 | return 0; |
544 | |
545 | if (!I->getDesc().isBranch()) |
546 | return 0; |
547 | |
548 | // Remove the branch. |
549 | if (BytesRemoved) |
550 | *BytesRemoved += getInstSizeInBytes(MI: *I); |
551 | I->eraseFromParent(); |
552 | |
553 | I = MBB.end(); |
554 | |
555 | if (I == MBB.begin()) |
556 | return 1; |
557 | --I; |
558 | if (!I->getDesc().isConditionalBranch()) |
559 | return 1; |
560 | |
561 | // Remove the branch. |
562 | if (BytesRemoved) |
563 | *BytesRemoved += getInstSizeInBytes(MI: *I); |
564 | I->eraseFromParent(); |
565 | return 2; |
566 | } |
567 | |
568 | // Inserts a branch into the end of the specific MachineBasicBlock, returning |
569 | // the number of instructions inserted. |
570 | unsigned LoongArchInstrInfo::insertBranch( |
571 | MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, |
572 | ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { |
573 | if (BytesAdded) |
574 | *BytesAdded = 0; |
575 | |
576 | // Shouldn't be a fall through. |
577 | assert(TBB && "insertBranch must not be told to insert a fallthrough" ); |
578 | assert(Cond.size() <= 3 && Cond.size() != 1 && |
579 | "LoongArch branch conditions have at most two components!" ); |
580 | |
581 | // Unconditional branch. |
582 | if (Cond.empty()) { |
583 | MachineInstr &MI = *BuildMI(BB: &MBB, MIMD: DL, MCID: get(Opcode: LoongArch::PseudoBR)).addMBB(MBB: TBB); |
584 | if (BytesAdded) |
585 | *BytesAdded += getInstSizeInBytes(MI); |
586 | return 1; |
587 | } |
588 | |
589 | // Either a one or two-way conditional branch. |
590 | MachineInstrBuilder MIB = BuildMI(BB: &MBB, MIMD: DL, MCID: get(Opcode: Cond[0].getImm())); |
591 | for (unsigned i = 1; i < Cond.size(); ++i) |
592 | MIB.add(MO: Cond[i]); |
593 | MIB.addMBB(MBB: TBB); |
594 | if (BytesAdded) |
595 | *BytesAdded += getInstSizeInBytes(MI: *MIB); |
596 | |
597 | // One-way conditional branch. |
598 | if (!FBB) |
599 | return 1; |
600 | |
601 | // Two-way conditional branch. |
602 | MachineInstr &MI = *BuildMI(BB: &MBB, MIMD: DL, MCID: get(Opcode: LoongArch::PseudoBR)).addMBB(MBB: FBB); |
603 | if (BytesAdded) |
604 | *BytesAdded += getInstSizeInBytes(MI); |
605 | return 2; |
606 | } |
607 | |
608 | void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB, |
609 | MachineBasicBlock &DestBB, |
610 | MachineBasicBlock &RestoreBB, |
611 | const DebugLoc &DL, |
612 | int64_t BrOffset, |
613 | RegScavenger *RS) const { |
614 | assert(RS && "RegScavenger required for long branching" ); |
615 | assert(MBB.empty() && |
616 | "new block should be inserted for expanding unconditional branch" ); |
617 | assert(MBB.pred_size() == 1); |
618 | |
619 | MachineFunction *MF = MBB.getParent(); |
620 | MachineRegisterInfo &MRI = MF->getRegInfo(); |
621 | const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); |
622 | LoongArchMachineFunctionInfo *LAFI = |
623 | MF->getInfo<LoongArchMachineFunctionInfo>(); |
624 | |
625 | if (!isInt<32>(x: BrOffset)) |
626 | report_fatal_error( |
627 | reason: "Branch offsets outside of the signed 32-bit range not supported" ); |
628 | |
629 | Register ScratchReg = MRI.createVirtualRegister(RegClass: &LoongArch::GPRRegClass); |
630 | auto II = MBB.end(); |
631 | |
632 | MachineInstr &PCALAU12I = |
633 | *BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: LoongArch::PCALAU12I), DestReg: ScratchReg) |
634 | .addMBB(MBB: &DestBB, TargetFlags: LoongArchII::MO_PCREL_HI); |
635 | MachineInstr &ADDI = |
636 | *BuildMI(BB&: MBB, I: II, MIMD: DL, |
637 | MCID: get(Opcode: STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W), |
638 | DestReg: ScratchReg) |
639 | .addReg(RegNo: ScratchReg) |
640 | .addMBB(MBB: &DestBB, TargetFlags: LoongArchII::MO_PCREL_LO); |
641 | BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: LoongArch::PseudoBRIND)) |
642 | .addReg(RegNo: ScratchReg, flags: RegState::Kill) |
643 | .addImm(Val: 0); |
644 | |
645 | RS->enterBasicBlockEnd(MBB); |
646 | Register Scav = RS->scavengeRegisterBackwards( |
647 | RC: LoongArch::GPRRegClass, To: PCALAU12I.getIterator(), /*RestoreAfter=*/false, |
648 | /*SPAdj=*/0, /*AllowSpill=*/false); |
649 | if (Scav != LoongArch::NoRegister) |
650 | RS->setRegUsed(Reg: Scav); |
651 | else { |
652 | // When there is no scavenged register, it needs to specify a register. |
653 | // Specify t8 register because it won't be used too often. |
654 | Scav = LoongArch::R20; |
655 | int FrameIndex = LAFI->getBranchRelaxationSpillFrameIndex(); |
656 | if (FrameIndex == -1) |
657 | report_fatal_error(reason: "The function size is incorrectly estimated." ); |
658 | storeRegToStackSlot(MBB, I: PCALAU12I, SrcReg: Scav, /*IsKill=*/true, FI: FrameIndex, |
659 | RC: &LoongArch::GPRRegClass, TRI, VReg: Register()); |
660 | TRI->eliminateFrameIndex(MI: std::prev(x: PCALAU12I.getIterator()), |
661 | /*SpAdj=*/SPAdj: 0, /*FIOperandNum=*/1); |
662 | PCALAU12I.getOperand(i: 1).setMBB(&RestoreBB); |
663 | ADDI.getOperand(i: 2).setMBB(&RestoreBB); |
664 | loadRegFromStackSlot(MBB&: RestoreBB, I: RestoreBB.end(), DstReg: Scav, FI: FrameIndex, |
665 | RC: &LoongArch::GPRRegClass, TRI, VReg: Register()); |
666 | TRI->eliminateFrameIndex(MI: RestoreBB.back(), |
667 | /*SpAdj=*/SPAdj: 0, /*FIOperandNum=*/1); |
668 | } |
669 | MRI.replaceRegWith(FromReg: ScratchReg, ToReg: Scav); |
670 | MRI.clearVirtRegs(); |
671 | } |
672 | |
673 | static unsigned getOppositeBranchOpc(unsigned Opc) { |
674 | switch (Opc) { |
675 | default: |
676 | llvm_unreachable("Unrecognized conditional branch" ); |
677 | case LoongArch::BEQ: |
678 | return LoongArch::BNE; |
679 | case LoongArch::BNE: |
680 | return LoongArch::BEQ; |
681 | case LoongArch::BEQZ: |
682 | return LoongArch::BNEZ; |
683 | case LoongArch::BNEZ: |
684 | return LoongArch::BEQZ; |
685 | case LoongArch::BCEQZ: |
686 | return LoongArch::BCNEZ; |
687 | case LoongArch::BCNEZ: |
688 | return LoongArch::BCEQZ; |
689 | case LoongArch::BLT: |
690 | return LoongArch::BGE; |
691 | case LoongArch::BGE: |
692 | return LoongArch::BLT; |
693 | case LoongArch::BLTU: |
694 | return LoongArch::BGEU; |
695 | case LoongArch::BGEU: |
696 | return LoongArch::BLTU; |
697 | } |
698 | } |
699 | |
700 | bool LoongArchInstrInfo::reverseBranchCondition( |
701 | SmallVectorImpl<MachineOperand> &Cond) const { |
702 | assert((Cond.size() && Cond.size() <= 3) && "Invalid branch condition!" ); |
703 | Cond[0].setImm(getOppositeBranchOpc(Opc: Cond[0].getImm())); |
704 | return false; |
705 | } |
706 | |
707 | std::pair<unsigned, unsigned> |
708 | LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const { |
709 | const unsigned Mask = LoongArchII::MO_DIRECT_FLAG_MASK; |
710 | return std::make_pair(x: TF & Mask, y: TF & ~Mask); |
711 | } |
712 | |
713 | ArrayRef<std::pair<unsigned, const char *>> |
714 | LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const { |
715 | using namespace LoongArchII; |
716 | // TODO: Add more target flags. |
717 | static const std::pair<unsigned, const char *> TargetFlags[] = { |
718 | {MO_CALL, "loongarch-call" }, |
719 | {MO_CALL_PLT, "loongarch-call-plt" }, |
720 | {MO_PCREL_HI, "loongarch-pcrel-hi" }, |
721 | {MO_PCREL_LO, "loongarch-pcrel-lo" }, |
722 | {MO_PCREL64_LO, "loongarch-pcrel64-lo" }, |
723 | {MO_PCREL64_HI, "loongarch-pcrel64-hi" }, |
724 | {MO_GOT_PC_HI, "loongarch-got-pc-hi" }, |
725 | {MO_GOT_PC_LO, "loongarch-got-pc-lo" }, |
726 | {MO_GOT_PC64_LO, "loongarch-got-pc64-lo" }, |
727 | {MO_GOT_PC64_HI, "loongarch-got-pc64-hi" }, |
728 | {MO_LE_HI, "loongarch-le-hi" }, |
729 | {MO_LE_LO, "loongarch-le-lo" }, |
730 | {MO_LE64_LO, "loongarch-le64-lo" }, |
731 | {MO_LE64_HI, "loongarch-le64-hi" }, |
732 | {MO_IE_PC_HI, "loongarch-ie-pc-hi" }, |
733 | {MO_IE_PC_LO, "loongarch-ie-pc-lo" }, |
734 | {MO_IE_PC64_LO, "loongarch-ie-pc64-lo" }, |
735 | {MO_IE_PC64_HI, "loongarch-ie-pc64-hi" }, |
736 | {MO_LD_PC_HI, "loongarch-ld-pc-hi" }, |
737 | {MO_GD_PC_HI, "loongarch-gd-pc-hi" }, |
738 | {MO_CALL36, "loongarch-call36" }, |
739 | {MO_DESC_PC_HI, "loongarch-desc-pc-hi" }, |
740 | {MO_DESC_PC_LO, "loongarch-desc-pc-lo" }, |
741 | {MO_DESC64_PC_LO, "loongarch-desc64-pc-lo" }, |
742 | {MO_DESC64_PC_HI, "loongarch-desc64-pc-hi" }, |
743 | {MO_DESC_LD, "loongarch-desc-ld" }, |
744 | {MO_DESC_CALL, "loongarch-desc-call" }, |
745 | {MO_LE_HI_R, "loongarch-le-hi-r" }, |
746 | {MO_LE_ADD_R, "loongarch-le-add-r" }, |
747 | {MO_LE_LO_R, "loongarch-le-lo-r" }}; |
748 | return ArrayRef(TargetFlags); |
749 | } |
750 | |
751 | ArrayRef<std::pair<unsigned, const char *>> |
752 | LoongArchInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const { |
753 | using namespace LoongArchII; |
754 | static const std::pair<unsigned, const char *> TargetFlags[] = { |
755 | {MO_RELAX, "loongarch-relax" }}; |
756 | return ArrayRef(TargetFlags); |
757 | } |
758 | |
759 | // Returns true if this is the sext.w pattern, addi.w rd, rs, 0. |
760 | bool LoongArch::isSEXT_W(const MachineInstr &MI) { |
761 | return MI.getOpcode() == LoongArch::ADDI_W && MI.getOperand(i: 1).isReg() && |
762 | MI.getOperand(i: 2).isImm() && MI.getOperand(i: 2).getImm() == 0; |
763 | } |
764 | |