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