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