1 //===- PPCRegisterBankInfo.cpp --------------------------------------------===//
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 /// \file
9 /// This file implements the targeting of the RegisterBankInfo class for
10 /// PowerPC.
11 //===----------------------------------------------------------------------===//
12
13 #include "PPCRegisterBankInfo.h"
14 #include "PPCRegisterInfo.h"
15 #include "llvm/CodeGen/MachineFunction.h"
16 #include "llvm/CodeGen/MachineRegisterInfo.h"
17 #include "llvm/Support/Debug.h"
18
19 #define DEBUG_TYPE "ppc-reg-bank-info"
20
21 #define GET_TARGET_REGBANK_IMPL
22 #include "PPCGenRegisterBank.inc"
23
24 // This file will be TableGen'ed at some point.
25 #include "PPCGenRegisterBankInfo.def"
26
27 using namespace llvm;
28
PPCRegisterBankInfo(const TargetRegisterInfo & TRI)29 PPCRegisterBankInfo::PPCRegisterBankInfo(const TargetRegisterInfo &TRI) {}
30
31 const RegisterBank &
getRegBankFromRegClass(const TargetRegisterClass & RC,LLT Ty) const32 PPCRegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC,
33 LLT Ty) const {
34 switch (RC.getID()) {
35 case PPC::G8RCRegClassID:
36 case PPC::G8RC_NOX0RegClassID:
37 case PPC::G8RC_and_G8RC_NOX0RegClassID:
38 case PPC::GPRCRegClassID:
39 case PPC::GPRC_NOR0RegClassID:
40 case PPC::GPRC_and_GPRC_NOR0RegClassID:
41 return getRegBank(PPC::GPRRegBankID);
42 case PPC::VSFRCRegClassID:
43 case PPC::SPILLTOVSRRC_and_VSFRCRegClassID:
44 case PPC::SPILLTOVSRRC_and_VFRCRegClassID:
45 case PPC::SPILLTOVSRRC_and_F4RCRegClassID:
46 case PPC::F8RCRegClassID:
47 case PPC::VFRCRegClassID:
48 case PPC::VSSRCRegClassID:
49 case PPC::F4RCRegClassID:
50 return getRegBank(PPC::FPRRegBankID);
51 case PPC::CRRCRegClassID:
52 case PPC::CRBITRCRegClassID:
53 return getRegBank(PPC::CRRegBankID);
54 default:
55 llvm_unreachable("Unexpected register class");
56 }
57 }
58
59 const RegisterBankInfo::InstructionMapping &
getInstrMapping(const MachineInstr & MI) const60 PPCRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
61 const unsigned Opc = MI.getOpcode();
62
63 // Try the default logic for non-generic instructions that are either copies
64 // or already have some operands assigned to banks.
65 if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
66 const RegisterBankInfo::InstructionMapping &Mapping =
67 getInstrMappingImpl(MI);
68 if (Mapping.isValid())
69 return Mapping;
70 }
71
72 const MachineFunction &MF = *MI.getParent()->getParent();
73 const MachineRegisterInfo &MRI = MF.getRegInfo();
74 const TargetSubtargetInfo &STI = MF.getSubtarget();
75 const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
76
77 unsigned NumOperands = MI.getNumOperands();
78 const ValueMapping *OperandsMapping = nullptr;
79 unsigned Cost = 1;
80 unsigned MappingID = DefaultMappingID;
81
82 switch (Opc) {
83 // Arithmetic ops.
84 case TargetOpcode::G_ADD:
85 case TargetOpcode::G_SUB:
86 // Bitwise ops.
87 case TargetOpcode::G_AND:
88 case TargetOpcode::G_OR:
89 case TargetOpcode::G_XOR:
90 // Extension ops.
91 case TargetOpcode::G_SEXT:
92 case TargetOpcode::G_ZEXT:
93 case TargetOpcode::G_ANYEXT:
94 assert(NumOperands <= 3 &&
95 "This code is for instructions with 3 or less operands");
96 OperandsMapping = getValueMapping(PMI_GPR64);
97 break;
98 case TargetOpcode::G_FADD:
99 case TargetOpcode::G_FSUB:
100 case TargetOpcode::G_FMUL:
101 case TargetOpcode::G_FDIV: {
102 Register SrcReg = MI.getOperand(1).getReg();
103 unsigned Size = getSizeInBits(SrcReg, MRI, TRI);
104
105 assert((Size == 32 || Size == 64) && "Unsupported floating point types!\n");
106 OperandsMapping = getValueMapping(Size == 32 ? PMI_FPR32 : PMI_FPR64);
107 break;
108 }
109 case TargetOpcode::G_FCMP: {
110 unsigned CmpSize = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits();
111
112 OperandsMapping = getOperandsMapping(
113 {getValueMapping(PMI_CR), nullptr,
114 getValueMapping(CmpSize == 32 ? PMI_FPR32 : PMI_FPR64),
115 getValueMapping(CmpSize == 32 ? PMI_FPR32 : PMI_FPR64)});
116 break;
117 }
118 case TargetOpcode::G_CONSTANT:
119 OperandsMapping = getOperandsMapping({getValueMapping(PMI_GPR64), nullptr});
120 break;
121 case TargetOpcode::G_FPTOUI:
122 case TargetOpcode::G_FPTOSI: {
123 Register SrcReg = MI.getOperand(1).getReg();
124 unsigned Size = getSizeInBits(SrcReg, MRI, TRI);
125
126 OperandsMapping = getOperandsMapping(
127 {getValueMapping(PMI_GPR64),
128 getValueMapping(Size == 32 ? PMI_FPR32 : PMI_FPR64)});
129 break;
130 }
131 case TargetOpcode::G_UITOFP:
132 case TargetOpcode::G_SITOFP: {
133 Register SrcReg = MI.getOperand(0).getReg();
134 unsigned Size = getSizeInBits(SrcReg, MRI, TRI);
135
136 OperandsMapping =
137 getOperandsMapping({getValueMapping(Size == 32 ? PMI_FPR32 : PMI_FPR64),
138 getValueMapping(PMI_GPR64)});
139 break;
140 }
141 case TargetOpcode::G_LOAD: {
142 unsigned Size = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
143 // Check if that load feeds fp instructions.
144 if (any_of(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()),
145 [&](const MachineInstr &UseMI) {
146 // If we have at least one direct use in a FP instruction,
147 // assume this was a floating point load in the IR. If it was
148 // not, we would have had a bitcast before reaching that
149 // instruction.
150 //
151 // Int->FP conversion operations are also captured in
152 // onlyDefinesFP().
153 return onlyUsesFP(UseMI, MRI, TRI);
154 }))
155 OperandsMapping = getOperandsMapping(
156 {getValueMapping(Size == 64 ? PMI_FPR64 : PMI_FPR32),
157 getValueMapping(PMI_GPR64)});
158 else
159 OperandsMapping = getOperandsMapping(
160 {getValueMapping(Size == 64 ? PMI_GPR64 : PMI_GPR32),
161 getValueMapping(PMI_GPR64)});
162 break;
163 }
164 case TargetOpcode::G_STORE: {
165 // Check if the store is fed by fp instructions.
166 MachineInstr *DefMI = MRI.getVRegDef(MI.getOperand(0).getReg());
167 unsigned Size = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
168 if (onlyDefinesFP(*DefMI, MRI, TRI))
169 OperandsMapping = getOperandsMapping(
170 {getValueMapping(Size == 64 ? PMI_FPR64 : PMI_FPR32),
171 getValueMapping(PMI_GPR64)});
172 else
173 OperandsMapping = getOperandsMapping(
174 {getValueMapping(Size == 64 ? PMI_GPR64 : PMI_GPR32),
175 getValueMapping(PMI_GPR64)});
176 break;
177 }
178 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: {
179 // FIXME: We have to check every operand in this MI and compute value
180 // mapping accordingly.
181 SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
182 OperandsMapping = getOperandsMapping(OpdsMapping);
183 break;
184 }
185 default:
186 return getInvalidInstructionMapping();
187 }
188
189 return getInstructionMapping(MappingID, Cost, OperandsMapping, NumOperands);
190 }
191
192 /// Returns whether opcode \p Opc is a pre-isel generic floating-point opcode,
193 /// having only floating-point operands.
194 /// FIXME: this is copied from target AArch64. Needs some code refactor here to
195 /// put this function in GlobalISel/Utils.cpp.
isPreISelGenericFloatingPointOpcode(unsigned Opc)196 static bool isPreISelGenericFloatingPointOpcode(unsigned Opc) {
197 switch (Opc) {
198 case TargetOpcode::G_FADD:
199 case TargetOpcode::G_FSUB:
200 case TargetOpcode::G_FMUL:
201 case TargetOpcode::G_FMA:
202 case TargetOpcode::G_FDIV:
203 case TargetOpcode::G_FCONSTANT:
204 case TargetOpcode::G_FPEXT:
205 case TargetOpcode::G_FPTRUNC:
206 case TargetOpcode::G_FCEIL:
207 case TargetOpcode::G_FFLOOR:
208 case TargetOpcode::G_FNEARBYINT:
209 case TargetOpcode::G_FNEG:
210 case TargetOpcode::G_FCOS:
211 case TargetOpcode::G_FSIN:
212 case TargetOpcode::G_FLOG10:
213 case TargetOpcode::G_FLOG:
214 case TargetOpcode::G_FLOG2:
215 case TargetOpcode::G_FSQRT:
216 case TargetOpcode::G_FABS:
217 case TargetOpcode::G_FEXP:
218 case TargetOpcode::G_FRINT:
219 case TargetOpcode::G_INTRINSIC_TRUNC:
220 case TargetOpcode::G_INTRINSIC_ROUND:
221 case TargetOpcode::G_FMAXNUM:
222 case TargetOpcode::G_FMINNUM:
223 case TargetOpcode::G_FMAXIMUM:
224 case TargetOpcode::G_FMINIMUM:
225 return true;
226 }
227 return false;
228 }
229
230 /// \returns true if a given intrinsic \p ID only uses and defines FPRs.
isFPIntrinsic(unsigned ID)231 static bool isFPIntrinsic(unsigned ID) {
232 // TODO: Add more intrinsics.
233 return false;
234 }
235
236 /// FIXME: this is copied from target AArch64. Needs some code refactor here to
237 /// put this function in class RegisterBankInfo.
hasFPConstraints(const MachineInstr & MI,const MachineRegisterInfo & MRI,const TargetRegisterInfo & TRI,unsigned Depth) const238 bool PPCRegisterBankInfo::hasFPConstraints(const MachineInstr &MI,
239 const MachineRegisterInfo &MRI,
240 const TargetRegisterInfo &TRI,
241 unsigned Depth) const {
242 unsigned Op = MI.getOpcode();
243 if (Op == TargetOpcode::G_INTRINSIC && isFPIntrinsic(MI.getIntrinsicID()))
244 return true;
245
246 // Do we have an explicit floating point instruction?
247 if (isPreISelGenericFloatingPointOpcode(Op))
248 return true;
249
250 // No. Check if we have a copy-like instruction. If we do, then we could
251 // still be fed by floating point instructions.
252 if (Op != TargetOpcode::COPY && !MI.isPHI() &&
253 !isPreISelGenericOptimizationHint(Op))
254 return false;
255
256 // Check if we already know the register bank.
257 auto *RB = getRegBank(MI.getOperand(0).getReg(), MRI, TRI);
258 if (RB == &PPC::FPRRegBank)
259 return true;
260 if (RB == &PPC::GPRRegBank)
261 return false;
262
263 // We don't know anything.
264 //
265 // If we have a phi, we may be able to infer that it will be assigned a FPR
266 // based off of its inputs.
267 if (!MI.isPHI() || Depth > MaxFPRSearchDepth)
268 return false;
269
270 return any_of(MI.explicit_uses(), [&](const MachineOperand &Op) {
271 return Op.isReg() &&
272 onlyDefinesFP(*MRI.getVRegDef(Op.getReg()), MRI, TRI, Depth + 1);
273 });
274 }
275
276 /// FIXME: this is copied from target AArch64. Needs some code refactor here to
277 /// put this function in class RegisterBankInfo.
onlyUsesFP(const MachineInstr & MI,const MachineRegisterInfo & MRI,const TargetRegisterInfo & TRI,unsigned Depth) const278 bool PPCRegisterBankInfo::onlyUsesFP(const MachineInstr &MI,
279 const MachineRegisterInfo &MRI,
280 const TargetRegisterInfo &TRI,
281 unsigned Depth) const {
282 switch (MI.getOpcode()) {
283 case TargetOpcode::G_FPTOSI:
284 case TargetOpcode::G_FPTOUI:
285 case TargetOpcode::G_FCMP:
286 case TargetOpcode::G_LROUND:
287 case TargetOpcode::G_LLROUND:
288 return true;
289 default:
290 break;
291 }
292 return hasFPConstraints(MI, MRI, TRI, Depth);
293 }
294
295 /// FIXME: this is copied from target AArch64. Needs some code refactor here to
296 /// put this function in class RegisterBankInfo.
onlyDefinesFP(const MachineInstr & MI,const MachineRegisterInfo & MRI,const TargetRegisterInfo & TRI,unsigned Depth) const297 bool PPCRegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,
298 const MachineRegisterInfo &MRI,
299 const TargetRegisterInfo &TRI,
300 unsigned Depth) const {
301 switch (MI.getOpcode()) {
302 case TargetOpcode::G_SITOFP:
303 case TargetOpcode::G_UITOFP:
304 return true;
305 default:
306 break;
307 }
308 return hasFPConstraints(MI, MRI, TRI, Depth);
309 }
310
311 RegisterBankInfo::InstructionMappings
getInstrAlternativeMappings(const MachineInstr & MI) const312 PPCRegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const {
313 // TODO Implement.
314 return RegisterBankInfo::getInstrAlternativeMappings(MI);
315 }
316