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