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