1 | //===-- MipsSERegisterInfo.cpp - MIPS32/64 Register 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 MIPS32/64 implementation of the TargetRegisterInfo |
10 | // class. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "MipsSERegisterInfo.h" |
15 | #include "Mips.h" |
16 | #include "MipsMachineFunction.h" |
17 | #include "MipsSEInstrInfo.h" |
18 | #include "MipsSubtarget.h" |
19 | #include "MipsTargetMachine.h" |
20 | #include "llvm/ADT/STLExtras.h" |
21 | #include "llvm/CodeGen/MachineFrameInfo.h" |
22 | #include "llvm/CodeGen/MachineFunction.h" |
23 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
24 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
25 | #include "llvm/CodeGen/TargetFrameLowering.h" |
26 | #include "llvm/CodeGen/TargetInstrInfo.h" |
27 | #include "llvm/IR/Constants.h" |
28 | #include "llvm/IR/DebugInfo.h" |
29 | #include "llvm/IR/Function.h" |
30 | #include "llvm/IR/Type.h" |
31 | #include "llvm/Support/Debug.h" |
32 | #include "llvm/Support/ErrorHandling.h" |
33 | #include "llvm/Support/raw_ostream.h" |
34 | #include "llvm/Target/TargetMachine.h" |
35 | #include "llvm/Target/TargetOptions.h" |
36 | |
37 | using namespace llvm; |
38 | |
39 | #define DEBUG_TYPE "mips-reg-info" |
40 | |
41 | MipsSERegisterInfo::MipsSERegisterInfo() = default; |
42 | |
43 | bool MipsSERegisterInfo:: |
44 | requiresRegisterScavenging(const MachineFunction &MF) const { |
45 | return true; |
46 | } |
47 | |
48 | bool MipsSERegisterInfo:: |
49 | requiresFrameIndexScavenging(const MachineFunction &MF) const { |
50 | return true; |
51 | } |
52 | |
53 | const TargetRegisterClass * |
54 | MipsSERegisterInfo::intRegClass(unsigned Size) const { |
55 | if (Size == 4) |
56 | return &Mips::GPR32RegClass; |
57 | |
58 | assert(Size == 8); |
59 | return &Mips::GPR64RegClass; |
60 | } |
61 | |
62 | /// Get the size of the offset supported by the given load/store/inline asm. |
63 | /// The result includes the effects of any scale factors applied to the |
64 | /// instruction immediate. |
65 | static inline unsigned getLoadStoreOffsetSizeInBits(const unsigned Opcode, |
66 | MachineOperand MO) { |
67 | switch (Opcode) { |
68 | case Mips::LD_B: |
69 | case Mips::ST_B: |
70 | return 10; |
71 | case Mips::LD_H: |
72 | case Mips::ST_H: |
73 | return 10 + 1 /* scale factor */; |
74 | case Mips::LD_W: |
75 | case Mips::ST_W: |
76 | return 10 + 2 /* scale factor */; |
77 | case Mips::LD_D: |
78 | case Mips::ST_D: |
79 | return 10 + 3 /* scale factor */; |
80 | case Mips::LL: |
81 | case Mips::LL64: |
82 | case Mips::LLD: |
83 | case Mips::LLE: |
84 | case Mips::SC: |
85 | case Mips::SC64: |
86 | case Mips::SCD: |
87 | case Mips::SCE: |
88 | return 16; |
89 | case Mips::LLE_MM: |
90 | case Mips::LL_MM: |
91 | case Mips::SCE_MM: |
92 | case Mips::SC_MM: |
93 | return 12; |
94 | case Mips::LL64_R6: |
95 | case Mips::LL_R6: |
96 | case Mips::LLD_R6: |
97 | case Mips::SC64_R6: |
98 | case Mips::SCD_R6: |
99 | case Mips::SC_R6: |
100 | case Mips::LL_MMR6: |
101 | case Mips::SC_MMR6: |
102 | return 9; |
103 | case Mips::INLINEASM: { |
104 | const InlineAsm::Flag F(MO.getImm()); |
105 | switch (F.getMemoryConstraintID()) { |
106 | case InlineAsm::ConstraintCode::ZC: { |
107 | const MipsSubtarget &Subtarget = MO.getParent() |
108 | ->getParent() |
109 | ->getParent() |
110 | ->getSubtarget<MipsSubtarget>(); |
111 | if (Subtarget.inMicroMipsMode()) |
112 | return 12; |
113 | |
114 | if (Subtarget.hasMips32r6()) |
115 | return 9; |
116 | |
117 | return 16; |
118 | } |
119 | default: |
120 | return 16; |
121 | } |
122 | } |
123 | default: |
124 | return 16; |
125 | } |
126 | } |
127 | |
128 | /// Get the scale factor applied to the immediate in the given load/store. |
129 | static inline unsigned getLoadStoreOffsetAlign(const unsigned Opcode) { |
130 | switch (Opcode) { |
131 | case Mips::LD_H: |
132 | case Mips::ST_H: |
133 | return 2; |
134 | case Mips::LD_W: |
135 | case Mips::ST_W: |
136 | return 4; |
137 | case Mips::LD_D: |
138 | case Mips::ST_D: |
139 | return 8; |
140 | default: |
141 | return 1; |
142 | } |
143 | } |
144 | |
145 | void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II, |
146 | unsigned OpNo, int FrameIndex, |
147 | uint64_t StackSize, |
148 | int64_t SPOffset) const { |
149 | MachineInstr &MI = *II; |
150 | MachineFunction &MF = *MI.getParent()->getParent(); |
151 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
152 | MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); |
153 | |
154 | MipsABIInfo ABI = |
155 | static_cast<const MipsTargetMachine &>(MF.getTarget()).getABI(); |
156 | const MipsRegisterInfo *RegInfo = |
157 | static_cast<const MipsRegisterInfo *>(MF.getSubtarget().getRegisterInfo()); |
158 | |
159 | const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); |
160 | int MinCSFI = 0; |
161 | int MaxCSFI = -1; |
162 | |
163 | if (CSI.size()) { |
164 | MinCSFI = CSI[0].getFrameIdx(); |
165 | MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); |
166 | } |
167 | |
168 | bool EhDataRegFI = MipsFI->isEhDataRegFI(FI: FrameIndex); |
169 | bool IsISRRegFI = MipsFI->isISRRegFI(FI: FrameIndex); |
170 | // The following stack frame objects are always referenced relative to $sp: |
171 | // 1. Outgoing arguments. |
172 | // 2. Pointer to dynamically allocated stack space. |
173 | // 3. Locations for callee-saved registers. |
174 | // 4. Locations for eh data registers. |
175 | // 5. Locations for ISR saved Coprocessor 0 registers 12 & 14. |
176 | // Everything else is referenced relative to whatever register |
177 | // getFrameRegister() returns. |
178 | unsigned FrameReg; |
179 | |
180 | if ((FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI) || EhDataRegFI || |
181 | IsISRRegFI) |
182 | FrameReg = ABI.GetStackPtr(); |
183 | else if (RegInfo->hasStackRealignment(MF)) { |
184 | if (MFI.hasVarSizedObjects() && !MFI.isFixedObjectIndex(ObjectIdx: FrameIndex)) |
185 | FrameReg = ABI.GetBasePtr(); |
186 | else if (MFI.isFixedObjectIndex(ObjectIdx: FrameIndex)) |
187 | FrameReg = getFrameRegister(MF); |
188 | else |
189 | FrameReg = ABI.GetStackPtr(); |
190 | } else |
191 | FrameReg = getFrameRegister(MF); |
192 | |
193 | // Calculate final offset. |
194 | // - There is no need to change the offset if the frame object is one of the |
195 | // following: an outgoing argument, pointer to a dynamically allocated |
196 | // stack space or a $gp restore location, |
197 | // - If the frame object is any of the following, its offset must be adjusted |
198 | // by adding the size of the stack: |
199 | // incoming argument, callee-saved register location or local variable. |
200 | bool IsKill = false; |
201 | int64_t Offset; |
202 | |
203 | Offset = SPOffset + (int64_t)StackSize; |
204 | Offset += MI.getOperand(i: OpNo + 1).getImm(); |
205 | |
206 | LLVM_DEBUG(errs() << "Offset : " << Offset << "\n" |
207 | << "<--------->\n" ); |
208 | |
209 | if (!MI.isDebugValue()) { |
210 | // Make sure Offset fits within the field available. |
211 | // For MSA instructions, this is a 10-bit signed immediate (scaled by |
212 | // element size), otherwise it is a 16-bit signed immediate. |
213 | unsigned OffsetBitSize = |
214 | getLoadStoreOffsetSizeInBits(Opcode: MI.getOpcode(), MO: MI.getOperand(i: OpNo - 1)); |
215 | const Align OffsetAlign(getLoadStoreOffsetAlign(Opcode: MI.getOpcode())); |
216 | if (OffsetBitSize < 16 && isInt<16>(x: Offset) && |
217 | (!isIntN(N: OffsetBitSize, x: Offset) || !isAligned(Lhs: OffsetAlign, SizeInBytes: Offset))) { |
218 | // If we have an offset that needs to fit into a signed n-bit immediate |
219 | // (where n < 16) and doesn't, but does fit into 16-bits then use an ADDiu |
220 | MachineBasicBlock &MBB = *MI.getParent(); |
221 | DebugLoc DL = II->getDebugLoc(); |
222 | const TargetRegisterClass *PtrRC = |
223 | ABI.ArePtrs64bit() ? &Mips::GPR64RegClass : &Mips::GPR32RegClass; |
224 | MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); |
225 | Register Reg = RegInfo.createVirtualRegister(RegClass: PtrRC); |
226 | const MipsSEInstrInfo &TII = |
227 | *static_cast<const MipsSEInstrInfo *>( |
228 | MBB.getParent()->getSubtarget().getInstrInfo()); |
229 | BuildMI(MBB, II, DL, TII.get(ABI.GetPtrAddiuOp()), Reg) |
230 | .addReg(FrameReg) |
231 | .addImm(Offset); |
232 | |
233 | FrameReg = Reg; |
234 | Offset = 0; |
235 | IsKill = true; |
236 | } else if (!isInt<16>(x: Offset)) { |
237 | // Otherwise split the offset into 16-bit pieces and add it in multiple |
238 | // instructions. |
239 | MachineBasicBlock &MBB = *MI.getParent(); |
240 | DebugLoc DL = II->getDebugLoc(); |
241 | unsigned NewImm = 0; |
242 | const MipsSEInstrInfo &TII = |
243 | *static_cast<const MipsSEInstrInfo *>( |
244 | MBB.getParent()->getSubtarget().getInstrInfo()); |
245 | unsigned Reg = TII.loadImmediate(Imm: Offset, MBB, II, DL, |
246 | NewImm: OffsetBitSize == 16 ? &NewImm : nullptr); |
247 | BuildMI(MBB, II, DL, TII.get(ABI.GetPtrAdduOp()), Reg).addReg(FrameReg) |
248 | .addReg(Reg, RegState::Kill); |
249 | |
250 | FrameReg = Reg; |
251 | Offset = SignExtend64<16>(x: NewImm); |
252 | IsKill = true; |
253 | } |
254 | } |
255 | |
256 | MI.getOperand(i: OpNo).ChangeToRegister(Reg: FrameReg, isDef: false, isImp: false, isKill: IsKill); |
257 | MI.getOperand(i: OpNo + 1).ChangeToImmediate(ImmVal: Offset); |
258 | } |
259 | |