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