1//===-- LanaiRegisterInfo.cpp - Lanai Register 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 Lanai implementation of the TargetRegisterInfo class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "LanaiRegisterInfo.h"
14#include "LanaiAluCode.h"
15#include "LanaiCondCode.h"
16#include "LanaiFrameLowering.h"
17#include "LanaiInstrInfo.h"
18#include "llvm/ADT/BitVector.h"
19#include "llvm/CodeGen/MachineFrameInfo.h"
20#include "llvm/CodeGen/MachineFunction.h"
21#include "llvm/CodeGen/MachineInstrBuilder.h"
22#include "llvm/CodeGen/RegisterScavenging.h"
23#include "llvm/CodeGen/TargetFrameLowering.h"
24#include "llvm/CodeGen/TargetInstrInfo.h"
25#include "llvm/Support/ErrorHandling.h"
26
27#define GET_REGINFO_TARGET_DESC
28#include "LanaiGenRegisterInfo.inc"
29
30using namespace llvm;
31
32LanaiRegisterInfo::LanaiRegisterInfo() : LanaiGenRegisterInfo(Lanai::RCA) {}
33
34const uint16_t *
35LanaiRegisterInfo::getCalleeSavedRegs(const MachineFunction * /*MF*/) const {
36 return CSR_SaveList;
37}
38
39BitVector LanaiRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
40 BitVector Reserved(getNumRegs());
41
42 Reserved.set(Lanai::R0);
43 Reserved.set(Lanai::R1);
44 Reserved.set(Lanai::PC);
45 Reserved.set(Lanai::R2);
46 Reserved.set(Lanai::SP);
47 Reserved.set(Lanai::R4);
48 Reserved.set(Lanai::FP);
49 Reserved.set(Lanai::R5);
50 Reserved.set(Lanai::RR1);
51 Reserved.set(Lanai::R10);
52 Reserved.set(Lanai::RR2);
53 Reserved.set(Lanai::R11);
54 Reserved.set(Lanai::RCA);
55 Reserved.set(Lanai::R15);
56 if (hasBasePointer(MF))
57 Reserved.set(getBaseRegister());
58 return Reserved;
59}
60
61bool LanaiRegisterInfo::requiresRegisterScavenging(
62 const MachineFunction & /*MF*/) const {
63 return true;
64}
65
66static bool isALUArithLoOpcode(unsigned Opcode) {
67 switch (Opcode) {
68 case Lanai::ADD_I_LO:
69 case Lanai::SUB_I_LO:
70 case Lanai::ADD_F_I_LO:
71 case Lanai::SUB_F_I_LO:
72 case Lanai::ADDC_I_LO:
73 case Lanai::SUBB_I_LO:
74 case Lanai::ADDC_F_I_LO:
75 case Lanai::SUBB_F_I_LO:
76 return true;
77 default:
78 return false;
79 }
80}
81
82static unsigned getOppositeALULoOpcode(unsigned Opcode) {
83 switch (Opcode) {
84 case Lanai::ADD_I_LO:
85 return Lanai::SUB_I_LO;
86 case Lanai::SUB_I_LO:
87 return Lanai::ADD_I_LO;
88 case Lanai::ADD_F_I_LO:
89 return Lanai::SUB_F_I_LO;
90 case Lanai::SUB_F_I_LO:
91 return Lanai::ADD_F_I_LO;
92 case Lanai::ADDC_I_LO:
93 return Lanai::SUBB_I_LO;
94 case Lanai::SUBB_I_LO:
95 return Lanai::ADDC_I_LO;
96 case Lanai::ADDC_F_I_LO:
97 return Lanai::SUBB_F_I_LO;
98 case Lanai::SUBB_F_I_LO:
99 return Lanai::ADDC_F_I_LO;
100 default:
101 llvm_unreachable("Invalid ALU lo opcode");
102 }
103}
104
105static unsigned getRRMOpcodeVariant(unsigned Opcode) {
106 switch (Opcode) {
107 case Lanai::LDBs_RI:
108 return Lanai::LDBs_RR;
109 case Lanai::LDBz_RI:
110 return Lanai::LDBz_RR;
111 case Lanai::LDHs_RI:
112 return Lanai::LDHs_RR;
113 case Lanai::LDHz_RI:
114 return Lanai::LDHz_RR;
115 case Lanai::LDW_RI:
116 return Lanai::LDW_RR;
117 case Lanai::STB_RI:
118 return Lanai::STB_RR;
119 case Lanai::STH_RI:
120 return Lanai::STH_RR;
121 case Lanai::SW_RI:
122 return Lanai::SW_RR;
123 default:
124 llvm_unreachable("Opcode has no RRM variant");
125 }
126}
127
128bool LanaiRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
129 int SPAdj, unsigned FIOperandNum,
130 RegScavenger *RS) const {
131 assert(SPAdj == 0 && "Unexpected");
132
133 MachineInstr &MI = *II;
134 MachineFunction &MF = *MI.getParent()->getParent();
135 const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
136 const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
137 bool HasFP = TFI->hasFP(MF);
138 DebugLoc DL = MI.getDebugLoc();
139
140 int FrameIndex = MI.getOperand(i: FIOperandNum).getIndex();
141
142 int Offset = MF.getFrameInfo().getObjectOffset(ObjectIdx: FrameIndex) +
143 MI.getOperand(i: FIOperandNum + 1).getImm();
144
145 // Addressable stack objects are addressed using neg. offsets from fp
146 // or pos. offsets from sp/basepointer
147 if (!HasFP || (hasStackRealignment(MF) && FrameIndex >= 0))
148 Offset += MF.getFrameInfo().getStackSize();
149
150 Register FrameReg = getFrameRegister(MF);
151 if (FrameIndex >= 0) {
152 if (hasBasePointer(MF))
153 FrameReg = getBaseRegister();
154 else if (hasStackRealignment(MF))
155 FrameReg = Lanai::SP;
156 }
157
158 // Replace frame index with a frame pointer reference.
159 // If the offset is small enough to fit in the immediate field, directly
160 // encode it.
161 // Otherwise scavenge a register and encode it into a MOVHI, OR_I_LO sequence.
162 if ((isSPLSOpcode(Opcode: MI.getOpcode()) && !isInt<10>(x: Offset)) ||
163 !isInt<16>(x: Offset)) {
164 assert(RS && "Register scavenging must be on");
165 Register Reg = RS->FindUnusedReg(RC: &Lanai::GPRRegClass);
166 if (!Reg)
167 Reg = RS->scavengeRegisterBackwards(RC: Lanai::GPRRegClass, To: II, RestoreAfter: false, SPAdj);
168 assert(Reg && "Register scavenger failed");
169
170 bool HasNegOffset = false;
171 // ALU ops have unsigned immediate values. If the Offset is negative, we
172 // negate it here and reverse the opcode later.
173 if (Offset < 0) {
174 HasNegOffset = true;
175 Offset = -Offset;
176 }
177
178 if (!isInt<16>(x: Offset)) {
179 // Reg = hi(offset) | lo(offset)
180 BuildMI(BB&: *MI.getParent(), I: II, MIMD: DL, MCID: TII->get(Opcode: Lanai::MOVHI), DestReg: Reg)
181 .addImm(Val: static_cast<uint32_t>(Offset) >> 16);
182 BuildMI(BB&: *MI.getParent(), I: II, MIMD: DL, MCID: TII->get(Opcode: Lanai::OR_I_LO), DestReg: Reg)
183 .addReg(RegNo: Reg)
184 .addImm(Val: Offset & 0xffffU);
185 } else {
186 // Reg = mov(offset)
187 BuildMI(BB&: *MI.getParent(), I: II, MIMD: DL, MCID: TII->get(Opcode: Lanai::ADD_I_LO), DestReg: Reg)
188 .addImm(Val: 0)
189 .addImm(Val: Offset);
190 }
191 // Reg = FrameReg OP Reg
192 if (MI.getOpcode() == Lanai::ADD_I_LO) {
193 BuildMI(BB&: *MI.getParent(), I: II, MIMD: DL,
194 MCID: HasNegOffset ? TII->get(Opcode: Lanai::SUB_R) : TII->get(Opcode: Lanai::ADD_R),
195 DestReg: MI.getOperand(i: 0).getReg())
196 .addReg(RegNo: FrameReg)
197 .addReg(RegNo: Reg)
198 .addImm(Val: LPCC::ICC_T);
199 MI.eraseFromParent();
200 return true;
201 }
202 if (isSPLSOpcode(Opcode: MI.getOpcode()) || isRMOpcode(Opcode: MI.getOpcode())) {
203 MI.setDesc(TII->get(Opcode: getRRMOpcodeVariant(Opcode: MI.getOpcode())));
204 if (HasNegOffset) {
205 // Change the ALU op (operand 3) from LPAC::ADD (the default) to
206 // LPAC::SUB with the already negated offset.
207 assert((MI.getOperand(3).getImm() == LPAC::ADD) &&
208 "Unexpected ALU op in RRM instruction");
209 MI.getOperand(i: 3).setImm(LPAC::SUB);
210 }
211 } else
212 llvm_unreachable("Unexpected opcode in frame index operation");
213
214 MI.getOperand(i: FIOperandNum).ChangeToRegister(Reg: FrameReg, /*isDef=*/false);
215 MI.getOperand(i: FIOperandNum + 1)
216 .ChangeToRegister(Reg, /*isDef=*/false, /*isImp=*/false,
217 /*isKill=*/true);
218 return false;
219 }
220
221 // ALU arithmetic ops take unsigned immediates. If the offset is negative,
222 // we replace the instruction with one that inverts the opcode and negates
223 // the immediate.
224 if ((Offset < 0) && isALUArithLoOpcode(Opcode: MI.getOpcode())) {
225 unsigned NewOpcode = getOppositeALULoOpcode(Opcode: MI.getOpcode());
226 // We know this is an ALU op, so we know the operands are as follows:
227 // 0: destination register
228 // 1: source register (frame register)
229 // 2: immediate
230 BuildMI(BB&: *MI.getParent(), I: II, MIMD: DL, MCID: TII->get(Opcode: NewOpcode),
231 DestReg: MI.getOperand(i: 0).getReg())
232 .addReg(RegNo: FrameReg)
233 .addImm(Val: -Offset);
234 MI.eraseFromParent();
235 return true;
236 }
237
238 MI.getOperand(i: FIOperandNum).ChangeToRegister(Reg: FrameReg, /*isDef=*/false);
239 MI.getOperand(i: FIOperandNum + 1).ChangeToImmediate(ImmVal: Offset);
240 return false;
241}
242
243bool LanaiRegisterInfo::hasBasePointer(const MachineFunction &MF) const {
244 const MachineFrameInfo &MFI = MF.getFrameInfo();
245 // When we need stack realignment and there are dynamic allocas, we can't
246 // reference off of the stack pointer, so we reserve a base pointer.
247 if (hasStackRealignment(MF) && MFI.hasVarSizedObjects())
248 return true;
249
250 return false;
251}
252
253unsigned LanaiRegisterInfo::getRARegister() const { return Lanai::RCA; }
254
255Register
256LanaiRegisterInfo::getFrameRegister(const MachineFunction & /*MF*/) const {
257 return Lanai::FP;
258}
259
260Register LanaiRegisterInfo::getBaseRegister() const { return Lanai::R14; }
261
262const uint32_t *
263LanaiRegisterInfo::getCallPreservedMask(const MachineFunction & /*MF*/,
264 CallingConv::ID /*CC*/) const {
265 return CSR_RegMask;
266}
267