1//===- Mips16InstrInfo.cpp - Mips16 Instruction Information ---------------===//
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 Mips16 implementation of the TargetInstrInfo class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "Mips16InstrInfo.h"
14#include "llvm/ADT/BitVector.h"
15#include "llvm/CodeGen/MachineBasicBlock.h"
16#include "llvm/CodeGen/MachineFrameInfo.h"
17#include "llvm/CodeGen/MachineFunction.h"
18#include "llvm/CodeGen/MachineInstr.h"
19#include "llvm/CodeGen/MachineInstrBuilder.h"
20#include "llvm/CodeGen/MachineMemOperand.h"
21#include "llvm/CodeGen/MachineOperand.h"
22#include "llvm/CodeGen/RegisterScavenging.h"
23#include "llvm/CodeGen/TargetRegisterInfo.h"
24#include "llvm/IR/DebugLoc.h"
25#include "llvm/Support/ErrorHandling.h"
26#include "llvm/Support/MathExtras.h"
27#include <cassert>
28#include <cstdint>
29#include <iterator>
30#include <vector>
31
32using namespace llvm;
33
34#define DEBUG_TYPE "mips16-instrinfo"
35
36Mips16InstrInfo::Mips16InstrInfo(const MipsSubtarget &STI)
37 : MipsInstrInfo(STI, RI, Mips::Bimm16), RI(STI) {}
38
39/// isLoadFromStackSlot - If the specified machine instruction is a direct
40/// load from a stack slot, return the virtual or physical register number of
41/// the destination along with the FrameIndex of the loaded stack slot. If
42/// not, return 0. This predicate must return 0 if the instruction has
43/// any side effects other than loading from the stack slot.
44Register Mips16InstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
45 int &FrameIndex) const {
46 return 0;
47}
48
49/// isStoreToStackSlot - If the specified machine instruction is a direct
50/// store to a stack slot, return the virtual or physical register number of
51/// the source reg along with the FrameIndex of the loaded stack slot. If
52/// not, return 0. This predicate must return 0 if the instruction has
53/// any side effects other than storing to the stack slot.
54Register Mips16InstrInfo::isStoreToStackSlot(const MachineInstr &MI,
55 int &FrameIndex) const {
56 return 0;
57}
58
59void Mips16InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
60 MachineBasicBlock::iterator I,
61 const DebugLoc &DL, Register DestReg,
62 Register SrcReg, bool KillSrc,
63 bool RenamableDest, bool RenamableSrc) const {
64 unsigned Opc = 0;
65
66 if (Mips::CPU16RegsRegClass.contains(Reg: DestReg) &&
67 Mips::GPR32RegClass.contains(Reg: SrcReg))
68 Opc = Mips::MoveR3216;
69 else if (Mips::GPR32RegClass.contains(Reg: DestReg) &&
70 Mips::CPU16RegsRegClass.contains(Reg: SrcReg))
71 Opc = Mips::Move32R16;
72 else if ((SrcReg == Mips::HI0) &&
73 (Mips::CPU16RegsRegClass.contains(Reg: DestReg)))
74 Opc = Mips::Mfhi16, SrcReg = 0;
75 else if ((SrcReg == Mips::LO0) &&
76 (Mips::CPU16RegsRegClass.contains(Reg: DestReg)))
77 Opc = Mips::Mflo16, SrcReg = 0;
78
79 assert(Opc && "Cannot copy registers");
80
81 MachineInstrBuilder MIB = BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: Opc));
82
83 if (DestReg)
84 MIB.addReg(RegNo: DestReg, Flags: RegState::Define);
85
86 if (SrcReg)
87 MIB.addReg(RegNo: SrcReg, Flags: getKillRegState(B: KillSrc));
88}
89
90std::optional<DestSourcePair>
91Mips16InstrInfo::isCopyInstrImpl(const MachineInstr &MI) const {
92 if (MI.isMoveReg())
93 return DestSourcePair{MI.getOperand(i: 0), MI.getOperand(i: 1)};
94 return std::nullopt;
95}
96
97void Mips16InstrInfo::storeRegToStack(MachineBasicBlock &MBB,
98 MachineBasicBlock::iterator I,
99 Register SrcReg, bool isKill, int FI,
100 const TargetRegisterClass *RC,
101 int64_t Offset,
102 MachineInstr::MIFlag Flags) const {
103 DebugLoc DL;
104 if (I != MBB.end()) DL = I->getDebugLoc();
105 MachineMemOperand *MMO = GetMemOperand(MBB, FI, Flags: MachineMemOperand::MOStore);
106 unsigned Opc = 0;
107 if (Mips::CPU16RegsRegClass.hasSubClassEq(RC))
108 Opc = Mips::SwRxSpImmX16;
109 assert(Opc && "Register class not handled!");
110 BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: Opc)).addReg(RegNo: SrcReg, Flags: getKillRegState(B: isKill)).
111 addFrameIndex(Idx: FI).addImm(Val: Offset)
112 .addMemOperand(MMO);
113}
114
115void Mips16InstrInfo::loadRegFromStack(MachineBasicBlock &MBB,
116 MachineBasicBlock::iterator I,
117 Register DestReg, int FI,
118 const TargetRegisterClass *RC,
119 int64_t Offset,
120 MachineInstr::MIFlag Flags) const {
121 DebugLoc DL;
122 if (I != MBB.end()) DL = I->getDebugLoc();
123 MachineMemOperand *MMO = GetMemOperand(MBB, FI, Flags: MachineMemOperand::MOLoad);
124 unsigned Opc = 0;
125
126 if (Mips::CPU16RegsRegClass.hasSubClassEq(RC))
127 Opc = Mips::LwRxSpImmX16;
128 assert(Opc && "Register class not handled!");
129 BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: Opc), DestReg).addFrameIndex(Idx: FI).addImm(Val: Offset)
130 .addMemOperand(MMO);
131}
132
133bool Mips16InstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
134 MachineBasicBlock &MBB = *MI.getParent();
135 switch (MI.getDesc().getOpcode()) {
136 default:
137 return false;
138 case Mips::RetRA16:
139 ExpandRetRA16(MBB, I: MI, Opc: Mips::JrcRa16);
140 break;
141 }
142
143 MBB.erase(I: MI.getIterator());
144 return true;
145}
146
147/// GetOppositeBranchOpc - Return the inverse of the specified
148/// opcode, e.g. turning BEQ to BNE.
149unsigned Mips16InstrInfo::getOppositeBranchOpc(unsigned Opc) const {
150 switch (Opc) {
151 case Mips::BeqzRxImmX16: return Mips::BnezRxImmX16;
152 case Mips::BnezRxImmX16: return Mips::BeqzRxImmX16;
153 case Mips::BeqzRxImm16: return Mips::BnezRxImm16;
154 case Mips::BnezRxImm16: return Mips::BeqzRxImm16;
155 case Mips::BteqzT8CmpX16: return Mips::BtnezT8CmpX16;
156 case Mips::BteqzT8SltX16: return Mips::BtnezT8SltX16;
157 case Mips::BteqzT8SltiX16: return Mips::BtnezT8SltiX16;
158 case Mips::Btnez16: return Mips::Bteqz16;
159 case Mips::BtnezX16: return Mips::BteqzX16;
160 case Mips::BtnezT8CmpiX16: return Mips::BteqzT8CmpiX16;
161 case Mips::BtnezT8SltuX16: return Mips::BteqzT8SltuX16;
162 case Mips::BtnezT8SltiuX16: return Mips::BteqzT8SltiuX16;
163 case Mips::Bteqz16: return Mips::Btnez16;
164 case Mips::BteqzX16: return Mips::BtnezX16;
165 case Mips::BteqzT8CmpiX16: return Mips::BtnezT8CmpiX16;
166 case Mips::BteqzT8SltuX16: return Mips::BtnezT8SltuX16;
167 case Mips::BteqzT8SltiuX16: return Mips::BtnezT8SltiuX16;
168 case Mips::BtnezT8CmpX16: return Mips::BteqzT8CmpX16;
169 case Mips::BtnezT8SltX16: return Mips::BteqzT8SltX16;
170 case Mips::BtnezT8SltiX16: return Mips::BteqzT8SltiX16;
171 }
172 llvm_unreachable("Illegal opcode!");
173}
174
175static void addSaveRestoreRegs(MachineInstrBuilder &MIB,
176 ArrayRef<CalleeSavedInfo> CSI,
177 RegState Flags = {}) {
178 for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
179 // Add the callee-saved register as live-in. Do not add if the register is
180 // RA and return address is taken, because it has already been added in
181 // method MipsTargetLowering::lowerRETURNADDR.
182 // It's killed at the spill, unless the register is RA and return address
183 // is taken.
184 Register Reg = CSI[e-i-1].getReg();
185 switch (Reg) {
186 case Mips::RA:
187 case Mips::S0:
188 case Mips::S1:
189 MIB.addReg(RegNo: Reg, Flags);
190 break;
191 case Mips::S2:
192 break;
193 default:
194 llvm_unreachable("unexpected mips16 callee saved register");
195
196 }
197 }
198}
199
200// Adjust SP by FrameSize bytes. Save RA, S0, S1
201void Mips16InstrInfo::makeFrame(unsigned SP, int64_t FrameSize,
202 MachineBasicBlock &MBB,
203 MachineBasicBlock::iterator I) const {
204 DebugLoc DL;
205 MachineFunction &MF = *MBB.getParent();
206 MachineFrameInfo &MFI = MF.getFrameInfo();
207 const BitVector Reserved = RI.getReservedRegs(MF);
208 bool SaveS2 = Reserved[Mips::S2];
209 MachineInstrBuilder MIB;
210 unsigned Opc = ((FrameSize <= 128) && !SaveS2)? Mips::Save16:Mips::SaveX16;
211 MIB = BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: Opc));
212 const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
213 addSaveRestoreRegs(MIB, CSI);
214 if (SaveS2)
215 MIB.addReg(RegNo: Mips::S2);
216 if (isUInt<11>(x: FrameSize))
217 MIB.addImm(Val: FrameSize);
218 else {
219 int Base = 2040; // should create template function like isUInt that
220 // returns largest possible n bit unsigned integer
221 int64_t Remainder = FrameSize - Base;
222 MIB.addImm(Val: Base);
223 if (isInt<16>(x: -Remainder))
224 BuildAddiuSpImm(MBB, I, Imm: -Remainder);
225 else
226 adjustStackPtrBig(SP, Amount: -Remainder, MBB, I, Reg1: Mips::V0, Reg2: Mips::V1);
227 }
228}
229
230// Adjust SP by FrameSize bytes. Restore RA, S0, S1
231void Mips16InstrInfo::restoreFrame(unsigned SP, int64_t FrameSize,
232 MachineBasicBlock &MBB,
233 MachineBasicBlock::iterator I) const {
234 DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc();
235 MachineFunction *MF = MBB.getParent();
236 MachineFrameInfo &MFI = MF->getFrameInfo();
237 const BitVector Reserved = RI.getReservedRegs(MF: *MF);
238 bool SaveS2 = Reserved[Mips::S2];
239 MachineInstrBuilder MIB;
240 unsigned Opc = ((FrameSize <= 128) && !SaveS2)?
241 Mips::Restore16:Mips::RestoreX16;
242
243 if (!isUInt<11>(x: FrameSize)) {
244 unsigned Base = 2040;
245 int64_t Remainder = FrameSize - Base;
246 FrameSize = Base; // should create template function like isUInt that
247 // returns largest possible n bit unsigned integer
248
249 if (isInt<16>(x: Remainder))
250 BuildAddiuSpImm(MBB, I, Imm: Remainder);
251 else
252 adjustStackPtrBig(SP, Amount: Remainder, MBB, I, Reg1: Mips::A0, Reg2: Mips::A1);
253 }
254 MIB = BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: Opc));
255 const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
256 addSaveRestoreRegs(MIB, CSI, Flags: RegState::Define);
257 if (SaveS2)
258 MIB.addReg(RegNo: Mips::S2, Flags: RegState::Define);
259 MIB.addImm(Val: FrameSize);
260}
261
262// Adjust SP by Amount bytes where bytes can be up to 32bit number.
263// This can only be called at times that we know that there is at least one free
264// register.
265// This is clearly safe at prologue and epilogue.
266void Mips16InstrInfo::adjustStackPtrBig(unsigned SP, int64_t Amount,
267 MachineBasicBlock &MBB,
268 MachineBasicBlock::iterator I,
269 unsigned Reg1, unsigned Reg2) const {
270 DebugLoc DL;
271 //
272 // li reg1, constant
273 // move reg2, sp
274 // add reg1, reg1, reg2
275 // move sp, reg1
276 //
277 //
278 MachineInstrBuilder MIB1 = BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: Mips::LwConstant32), DestReg: Reg1);
279 MIB1.addImm(Val: Amount).addImm(Val: -1);
280 MachineInstrBuilder MIB2 = BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: Mips::MoveR3216), DestReg: Reg2);
281 MIB2.addReg(RegNo: Mips::SP, Flags: RegState::Kill);
282 MachineInstrBuilder MIB3 = BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: Mips::AdduRxRyRz16), DestReg: Reg1);
283 MIB3.addReg(RegNo: Reg1);
284 MIB3.addReg(RegNo: Reg2, Flags: RegState::Kill);
285 MachineInstrBuilder MIB4 = BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: Mips::Move32R16),
286 DestReg: Mips::SP);
287 MIB4.addReg(RegNo: Reg1, Flags: RegState::Kill);
288}
289
290void Mips16InstrInfo::adjustStackPtrBigUnrestricted(
291 unsigned SP, int64_t Amount, MachineBasicBlock &MBB,
292 MachineBasicBlock::iterator I) const {
293 llvm_unreachable("adjust stack pointer amount exceeded");
294}
295
296/// Adjust SP by Amount bytes.
297void Mips16InstrInfo::adjustStackPtr(unsigned SP, int64_t Amount,
298 MachineBasicBlock &MBB,
299 MachineBasicBlock::iterator I) const {
300 if (Amount == 0)
301 return;
302
303 if (isInt<16>(x: Amount)) // need to change to addiu sp, ....and isInt<16>
304 BuildAddiuSpImm(MBB, I, Imm: Amount);
305 else
306 adjustStackPtrBigUnrestricted(SP, Amount, MBB, I);
307}
308
309/// This function generates the sequence of instructions needed to get the
310/// result of adding register REG and immediate IMM.
311unsigned Mips16InstrInfo::loadImmediate(unsigned FrameReg, int64_t Imm,
312 MachineBasicBlock &MBB,
313 MachineBasicBlock::iterator II,
314 const DebugLoc &DL,
315 unsigned &NewImm) const {
316 //
317 // given original instruction is:
318 // Instr rx, T[offset] where offset is too big.
319 //
320 // lo = offset & 0xFFFF
321 // hi = ((offset >> 16) + (lo >> 15)) & 0xFFFF;
322 //
323 // let T = temporary register
324 // li T, hi
325 // shl T, 16
326 // add T, Rx, T
327 //
328 RegScavenger rs;
329 int32_t lo = Imm & 0xFFFF;
330 NewImm = lo;
331 int Reg =0;
332 int SpReg = 0;
333
334 rs.enterBasicBlockEnd(MBB);
335 rs.backward(I: std::next(x: II));
336 //
337 // We need to know which registers can be used, in the case where there
338 // are not enough free registers. We exclude all registers that
339 // are used in the instruction that we are helping.
340 // // Consider all allocatable registers in the register class initially
341 BitVector Candidates =
342 RI.getAllocatableSet
343 (MF: *II->getParent()->getParent(), RC: &Mips::CPU16RegsRegClass);
344 // Exclude all the registers being used by the instruction.
345 for (MachineOperand &MO : II->operands()) {
346 if (MO.isReg() && MO.getReg() != 0 && !MO.isDef() &&
347 !MO.getReg().isVirtual())
348 Candidates.reset(Idx: MO.getReg());
349 }
350
351 // If the same register was used and defined in an instruction, then
352 // it will not be in the list of candidates.
353 //
354 // we need to analyze the instruction that we are helping.
355 // we need to know if it defines register x but register x is not
356 // present as an operand of the instruction. this tells
357 // whether the register is live before the instruction. if it's not
358 // then we don't need to save it in case there are no free registers.
359 int DefReg = 0;
360 for (MachineOperand &MO : II->operands()) {
361 if (MO.isReg() && MO.isDef()) {
362 DefReg = MO.getReg();
363 break;
364 }
365 }
366
367 BitVector Available = rs.getRegsAvailable(RC: &Mips::CPU16RegsRegClass);
368 Available &= Candidates;
369 //
370 // we use T0 for the first register, if we need to save something away.
371 // we use T1 for the second register, if we need to save something away.
372 //
373 unsigned FirstRegSaved =0, SecondRegSaved=0;
374 unsigned FirstRegSavedTo = 0, SecondRegSavedTo = 0;
375
376 Reg = Available.find_first();
377
378 if (Reg == -1) {
379 Reg = Candidates.find_first();
380 Candidates.reset(Idx: Reg);
381 if (DefReg != Reg) {
382 FirstRegSaved = Reg;
383 FirstRegSavedTo = Mips::T0;
384 copyPhysReg(MBB, I: II, DL, DestReg: FirstRegSavedTo, SrcReg: FirstRegSaved, KillSrc: true);
385 }
386 }
387 else
388 Available.reset(Idx: Reg);
389 BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: Mips::LwConstant32), DestReg: Reg).addImm(Val: Imm).addImm(Val: -1);
390 NewImm = 0;
391 if (FrameReg == Mips::SP) {
392 SpReg = Available.find_first();
393 if (SpReg == -1) {
394 SpReg = Candidates.find_first();
395 // Candidates.reset(SpReg); // not really needed
396 if (DefReg!= SpReg) {
397 SecondRegSaved = SpReg;
398 SecondRegSavedTo = Mips::T1;
399 }
400 if (SecondRegSaved)
401 copyPhysReg(MBB, I: II, DL, DestReg: SecondRegSavedTo, SrcReg: SecondRegSaved, KillSrc: true);
402 } else {
403 Available.reset(Idx: SpReg);
404 }
405 copyPhysReg(MBB, I: II, DL, DestReg: SpReg, SrcReg: Mips::SP, KillSrc: false);
406 BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: Mips::AdduRxRyRz16), DestReg: Reg)
407 .addReg(RegNo: SpReg, Flags: RegState::Kill)
408 .addReg(RegNo: Reg);
409 }
410 else
411 BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: get(Opcode: Mips:: AdduRxRyRz16), DestReg: Reg).addReg(RegNo: FrameReg)
412 .addReg(RegNo: Reg, Flags: RegState::Kill);
413 if (FirstRegSaved || SecondRegSaved) {
414 II = std::next(x: II);
415 if (FirstRegSaved)
416 copyPhysReg(MBB, I: II, DL, DestReg: FirstRegSaved, SrcReg: FirstRegSavedTo, KillSrc: true);
417 if (SecondRegSaved)
418 copyPhysReg(MBB, I: II, DL, DestReg: SecondRegSaved, SrcReg: SecondRegSavedTo, KillSrc: true);
419 }
420 return Reg;
421}
422
423unsigned Mips16InstrInfo::getAnalyzableBrOpc(unsigned Opc) const {
424 return (Opc == Mips::BeqzRxImmX16 || Opc == Mips::BimmX16 ||
425 Opc == Mips::Bimm16 ||
426 Opc == Mips::Bteqz16 || Opc == Mips::Btnez16 ||
427 Opc == Mips::BeqzRxImm16 || Opc == Mips::BnezRxImm16 ||
428 Opc == Mips::BnezRxImmX16 || Opc == Mips::BteqzX16 ||
429 Opc == Mips::BteqzT8CmpX16 || Opc == Mips::BteqzT8CmpiX16 ||
430 Opc == Mips::BteqzT8SltX16 || Opc == Mips::BteqzT8SltuX16 ||
431 Opc == Mips::BteqzT8SltiX16 || Opc == Mips::BteqzT8SltiuX16 ||
432 Opc == Mips::BtnezX16 || Opc == Mips::BtnezT8CmpX16 ||
433 Opc == Mips::BtnezT8CmpiX16 || Opc == Mips::BtnezT8SltX16 ||
434 Opc == Mips::BtnezT8SltuX16 || Opc == Mips::BtnezT8SltiX16 ||
435 Opc == Mips::BtnezT8SltiuX16 ) ? Opc : 0;
436}
437
438void Mips16InstrInfo::ExpandRetRA16(MachineBasicBlock &MBB,
439 MachineBasicBlock::iterator I,
440 unsigned Opc) const {
441 BuildMI(BB&: MBB, I, MIMD: I->getDebugLoc(), MCID: get(Opcode: Opc));
442}
443
444const MCInstrDesc &Mips16InstrInfo::AddiuSpImm(int64_t Imm) const {
445 if (validSpImm8(offset: Imm))
446 return get(Opcode: Mips::AddiuSpImm16);
447 else
448 return get(Opcode: Mips::AddiuSpImmX16);
449}
450
451void Mips16InstrInfo::BuildAddiuSpImm
452 (MachineBasicBlock &MBB, MachineBasicBlock::iterator I, int64_t Imm) const {
453 DebugLoc DL;
454 BuildMI(BB&: MBB, I, MIMD: DL, MCID: AddiuSpImm(Imm)).addImm(Val: Imm);
455}
456
457const MipsInstrInfo *llvm::createMips16InstrInfo(const MipsSubtarget &STI) {
458 return new Mips16InstrInfo(STI);
459}
460
461bool Mips16InstrInfo::validImmediate(unsigned Opcode, unsigned Reg,
462 int64_t Amount) {
463 switch (Opcode) {
464 case Mips::LbRxRyOffMemX16:
465 case Mips::LbuRxRyOffMemX16:
466 case Mips::LhRxRyOffMemX16:
467 case Mips::LhuRxRyOffMemX16:
468 case Mips::SbRxRyOffMemX16:
469 case Mips::ShRxRyOffMemX16:
470 case Mips::LwRxRyOffMemX16:
471 case Mips::SwRxRyOffMemX16:
472 case Mips::SwRxSpImmX16:
473 case Mips::LwRxSpImmX16:
474 return isInt<16>(x: Amount);
475 case Mips::AddiuRxRyOffMemX16:
476 if ((Reg == Mips::PC) || (Reg == Mips::SP))
477 return isInt<16>(x: Amount);
478 return isInt<15>(x: Amount);
479 }
480 llvm_unreachable("unexpected Opcode in validImmediate");
481}
482