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