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
28using namespace llvm;
29
30PPCRegisterBankInfo::PPCRegisterBankInfo(const TargetRegisterInfo &TRI) {}
31
32const RegisterBank &
33PPCRegisterBankInfo::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(ID: PPC::FPRRegBankID);
45 default:
46 return PPCGenRegisterBankInfo::getRegBankFromRegClass(RC, Ty);
47 }
48}
49
50const RegisterBankInfo::InstructionMapping &
51PPCRegisterBankInfo::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(Opcode: 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(Reg: MI.getOperand(i: 0).getReg());
88 unsigned Size = Ty.getSizeInBits();
89 switch (Size) {
90 case 128:
91 OperandsMapping = getValueMapping(RBIdx: PMI_VEC128);
92 break;
93 default:
94 OperandsMapping = getValueMapping(RBIdx: 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(i: 1).getReg();
104 unsigned Size = getSizeInBits(Reg: 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(RBIdx: PMI_FPR32);
111 break;
112 case 64:
113 OperandsMapping = getValueMapping(RBIdx: PMI_FPR64);
114 break;
115 case 128:
116 OperandsMapping = getValueMapping(RBIdx: PMI_VEC128);
117 break;
118 }
119 break;
120 }
121 case TargetOpcode::G_FCMP: {
122 unsigned CmpSize = MRI.getType(Reg: MI.getOperand(i: 2).getReg()).getSizeInBits();
123
124 OperandsMapping = getOperandsMapping(
125 OpdsMapping: {getValueMapping(RBIdx: PMI_CR), nullptr,
126 getValueMapping(RBIdx: CmpSize == 32 ? PMI_FPR32 : PMI_FPR64),
127 getValueMapping(RBIdx: CmpSize == 32 ? PMI_FPR32 : PMI_FPR64)});
128 break;
129 }
130 case TargetOpcode::G_CONSTANT:
131 OperandsMapping = getOperandsMapping(OpdsMapping: {getValueMapping(RBIdx: PMI_GPR64), nullptr});
132 break;
133 case TargetOpcode::G_CONSTANT_POOL:
134 OperandsMapping = getOperandsMapping(OpdsMapping: {getValueMapping(RBIdx: PMI_GPR64), nullptr});
135 break;
136 case TargetOpcode::G_FPTOUI:
137 case TargetOpcode::G_FPTOSI: {
138 Register SrcReg = MI.getOperand(i: 1).getReg();
139 unsigned Size = getSizeInBits(Reg: SrcReg, MRI, TRI);
140
141 OperandsMapping = getOperandsMapping(
142 OpdsMapping: {getValueMapping(RBIdx: PMI_GPR64),
143 getValueMapping(RBIdx: Size == 32 ? PMI_FPR32 : PMI_FPR64)});
144 break;
145 }
146 case TargetOpcode::G_UITOFP:
147 case TargetOpcode::G_SITOFP: {
148 Register SrcReg = MI.getOperand(i: 0).getReg();
149 unsigned Size = getSizeInBits(Reg: SrcReg, MRI, TRI);
150
151 OperandsMapping =
152 getOperandsMapping(OpdsMapping: {getValueMapping(RBIdx: Size == 32 ? PMI_FPR32 : PMI_FPR64),
153 getValueMapping(RBIdx: PMI_GPR64)});
154 break;
155 }
156 case TargetOpcode::G_LOAD: {
157 unsigned Size = MRI.getType(Reg: MI.getOperand(i: 0).getReg()).getSizeInBits();
158 // Check if that load feeds fp instructions.
159 if (any_of(Range: MRI.use_nodbg_instructions(Reg: MI.getOperand(i: 0).getReg()),
160 P: [&](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(MI: UseMI, MRI, TRI);
169 }))
170 OperandsMapping = getOperandsMapping(
171 OpdsMapping: {getValueMapping(RBIdx: Size == 64 ? PMI_FPR64 : PMI_FPR32),
172 getValueMapping(RBIdx: PMI_GPR64)});
173 else
174 OperandsMapping = getOperandsMapping(
175 OpdsMapping: {getValueMapping(RBIdx: Size == 64 ? PMI_GPR64 : PMI_GPR32),
176 getValueMapping(RBIdx: 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(Reg: MI.getOperand(i: 0).getReg());
182 unsigned Size = MRI.getType(Reg: MI.getOperand(i: 0).getReg()).getSizeInBits();
183 if (onlyDefinesFP(MI: *DefMI, MRI, TRI))
184 OperandsMapping = getOperandsMapping(
185 OpdsMapping: {getValueMapping(RBIdx: Size == 64 ? PMI_FPR64 : PMI_FPR32),
186 getValueMapping(RBIdx: PMI_GPR64)});
187 else
188 OperandsMapping = getOperandsMapping(
189 OpdsMapping: {getValueMapping(RBIdx: Size == 64 ? PMI_GPR64 : PMI_GPR32),
190 getValueMapping(RBIdx: 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(Reg: MI.getOperand(i: 0).getReg());
202 LLT SrcTy = MRI.getType(Reg: MI.getOperand(i: 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 ID: MappingID, Cost, OperandsMapping: getCopyMapping(DstBankID: DstRB.getID(), SrcBankID: SrcRB.getID(), Size: DstSize),
215 NumOperands);
216 }
217 default:
218 return getInvalidInstructionMapping();
219 }
220
221 return getInstructionMapping(ID: MappingID, Cost, OperandsMapping, NumOperands);
222}
223
224/// \returns true if a given intrinsic \p ID only uses and defines FPRs.
225static 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.
232bool 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>(Val: &MI)) {
239 if (isFPIntrinsic(ID: GI->getIntrinsicID()))
240 return true;
241 }
242
243 // Do we have an explicit floating point instruction?
244 if (isPreISelGenericFloatingPointOpcode(Opc: 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(Opcode: Op))
251 return false;
252
253 // Check if we already know the register bank.
254 auto *RB = getRegBank(Reg: MI.getOperand(i: 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(Range: MI.explicit_uses(), P: [&](const MachineOperand &Op) {
268 return Op.isReg() &&
269 onlyDefinesFP(MI: *MRI.getVRegDef(Reg: Op.getReg()), MRI, TRI, Depth: 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.
275bool 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.
294bool 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
308RegisterBankInfo::InstructionMappings
309PPCRegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const {
310 // TODO Implement.
311 return RegisterBankInfo::getInstrAlternativeMappings(MI);
312}
313