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