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