1bdd1243dSDimitry Andric //===-- RISCVRegisterBankInfo.cpp -------------------------------*- C++ -*-===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric /// \file
906c3fb27SDimitry Andric /// This file implements the targeting of the RegisterBankInfo class for RISC-V.
10bdd1243dSDimitry Andric /// \todo This should be generated by TableGen.
11bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
12bdd1243dSDimitry Andric 
13bdd1243dSDimitry Andric #include "RISCVRegisterBankInfo.h"
14bdd1243dSDimitry Andric #include "MCTargetDesc/RISCVMCTargetDesc.h"
15*5f757f3fSDimitry Andric #include "RISCVSubtarget.h"
16bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
17bdd1243dSDimitry Andric #include "llvm/CodeGen/RegisterBank.h"
18bdd1243dSDimitry Andric #include "llvm/CodeGen/RegisterBankInfo.h"
19bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
20bdd1243dSDimitry Andric 
21bdd1243dSDimitry Andric #define GET_TARGET_REGBANK_IMPL
22bdd1243dSDimitry Andric #include "RISCVGenRegisterBank.inc"
23bdd1243dSDimitry Andric 
24*5f757f3fSDimitry Andric namespace llvm {
25*5f757f3fSDimitry Andric namespace RISCV {
26*5f757f3fSDimitry Andric 
27*5f757f3fSDimitry Andric const RegisterBankInfo::PartialMapping PartMappings[] = {
28*5f757f3fSDimitry Andric     {0, 32, GPRBRegBank},
29*5f757f3fSDimitry Andric     {0, 64, GPRBRegBank},
30*5f757f3fSDimitry Andric     {0, 32, FPRBRegBank},
31*5f757f3fSDimitry Andric     {0, 64, FPRBRegBank},
32*5f757f3fSDimitry Andric };
33*5f757f3fSDimitry Andric 
34*5f757f3fSDimitry Andric enum PartialMappingIdx {
35*5f757f3fSDimitry Andric   PMI_GPRB32 = 0,
36*5f757f3fSDimitry Andric   PMI_GPRB64 = 1,
37*5f757f3fSDimitry Andric   PMI_FPRB32 = 2,
38*5f757f3fSDimitry Andric   PMI_FPRB64 = 3,
39*5f757f3fSDimitry Andric };
40*5f757f3fSDimitry Andric 
41*5f757f3fSDimitry Andric const RegisterBankInfo::ValueMapping ValueMappings[] = {
42*5f757f3fSDimitry Andric     // Invalid value mapping.
43*5f757f3fSDimitry Andric     {nullptr, 0},
44*5f757f3fSDimitry Andric     // Maximum 3 GPR operands; 32 bit.
45*5f757f3fSDimitry Andric     {&PartMappings[PMI_GPRB32], 1},
46*5f757f3fSDimitry Andric     {&PartMappings[PMI_GPRB32], 1},
47*5f757f3fSDimitry Andric     {&PartMappings[PMI_GPRB32], 1},
48*5f757f3fSDimitry Andric     // Maximum 3 GPR operands; 64 bit.
49*5f757f3fSDimitry Andric     {&PartMappings[PMI_GPRB64], 1},
50*5f757f3fSDimitry Andric     {&PartMappings[PMI_GPRB64], 1},
51*5f757f3fSDimitry Andric     {&PartMappings[PMI_GPRB64], 1},
52*5f757f3fSDimitry Andric     // Maximum 3 FPR operands; 32 bit.
53*5f757f3fSDimitry Andric     {&PartMappings[PMI_FPRB32], 1},
54*5f757f3fSDimitry Andric     {&PartMappings[PMI_FPRB32], 1},
55*5f757f3fSDimitry Andric     {&PartMappings[PMI_FPRB32], 1},
56*5f757f3fSDimitry Andric     // Maximum 3 FPR operands; 64 bit.
57*5f757f3fSDimitry Andric     {&PartMappings[PMI_FPRB64], 1},
58*5f757f3fSDimitry Andric     {&PartMappings[PMI_FPRB64], 1},
59*5f757f3fSDimitry Andric     {&PartMappings[PMI_FPRB64], 1},
60*5f757f3fSDimitry Andric };
61*5f757f3fSDimitry Andric 
62*5f757f3fSDimitry Andric enum ValueMappingIdx {
63*5f757f3fSDimitry Andric   InvalidIdx = 0,
64*5f757f3fSDimitry Andric   GPRB32Idx = 1,
65*5f757f3fSDimitry Andric   GPRB64Idx = 4,
66*5f757f3fSDimitry Andric   FPRB32Idx = 7,
67*5f757f3fSDimitry Andric   FPRB64Idx = 10,
68*5f757f3fSDimitry Andric };
69*5f757f3fSDimitry Andric } // namespace RISCV
70*5f757f3fSDimitry Andric } // namespace llvm
71*5f757f3fSDimitry Andric 
72bdd1243dSDimitry Andric using namespace llvm;
73bdd1243dSDimitry Andric 
RISCVRegisterBankInfo(unsigned HwMode)7406c3fb27SDimitry Andric RISCVRegisterBankInfo::RISCVRegisterBankInfo(unsigned HwMode)
7506c3fb27SDimitry Andric     : RISCVGenRegisterBankInfo(HwMode) {}
76*5f757f3fSDimitry Andric 
77*5f757f3fSDimitry Andric const RegisterBank &
getRegBankFromRegClass(const TargetRegisterClass & RC,LLT Ty) const78*5f757f3fSDimitry Andric RISCVRegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC,
79*5f757f3fSDimitry Andric                                               LLT Ty) const {
80*5f757f3fSDimitry Andric   switch (RC.getID()) {
81*5f757f3fSDimitry Andric   default:
82*5f757f3fSDimitry Andric     llvm_unreachable("Register class not supported");
83*5f757f3fSDimitry Andric   case RISCV::GPRRegClassID:
84*5f757f3fSDimitry Andric   case RISCV::GPRF16RegClassID:
85*5f757f3fSDimitry Andric   case RISCV::GPRF32RegClassID:
86*5f757f3fSDimitry Andric   case RISCV::GPRNoX0RegClassID:
87*5f757f3fSDimitry Andric   case RISCV::GPRNoX0X2RegClassID:
88*5f757f3fSDimitry Andric   case RISCV::GPRJALRRegClassID:
89*5f757f3fSDimitry Andric   case RISCV::GPRTCRegClassID:
90*5f757f3fSDimitry Andric   case RISCV::GPRC_and_GPRTCRegClassID:
91*5f757f3fSDimitry Andric   case RISCV::GPRCRegClassID:
92*5f757f3fSDimitry Andric   case RISCV::GPRC_and_SR07RegClassID:
93*5f757f3fSDimitry Andric   case RISCV::SR07RegClassID:
94*5f757f3fSDimitry Andric   case RISCV::SPRegClassID:
95*5f757f3fSDimitry Andric   case RISCV::GPRX0RegClassID:
96*5f757f3fSDimitry Andric     return getRegBank(RISCV::GPRBRegBankID);
97*5f757f3fSDimitry Andric   case RISCV::FPR64RegClassID:
98*5f757f3fSDimitry Andric   case RISCV::FPR16RegClassID:
99*5f757f3fSDimitry Andric   case RISCV::FPR32RegClassID:
100*5f757f3fSDimitry Andric   case RISCV::FPR64CRegClassID:
101*5f757f3fSDimitry Andric   case RISCV::FPR32CRegClassID:
102*5f757f3fSDimitry Andric     return getRegBank(RISCV::FPRBRegBankID);
103*5f757f3fSDimitry Andric   case RISCV::VMRegClassID:
104*5f757f3fSDimitry Andric   case RISCV::VRRegClassID:
105*5f757f3fSDimitry Andric   case RISCV::VRNoV0RegClassID:
106*5f757f3fSDimitry Andric   case RISCV::VRM2RegClassID:
107*5f757f3fSDimitry Andric   case RISCV::VRM2NoV0RegClassID:
108*5f757f3fSDimitry Andric   case RISCV::VRM4RegClassID:
109*5f757f3fSDimitry Andric   case RISCV::VRM4NoV0RegClassID:
110*5f757f3fSDimitry Andric   case RISCV::VMV0RegClassID:
111*5f757f3fSDimitry Andric   case RISCV::VRM2_with_sub_vrm1_0_in_VMV0RegClassID:
112*5f757f3fSDimitry Andric   case RISCV::VRM4_with_sub_vrm1_0_in_VMV0RegClassID:
113*5f757f3fSDimitry Andric   case RISCV::VRM8RegClassID:
114*5f757f3fSDimitry Andric   case RISCV::VRM8NoV0RegClassID:
115*5f757f3fSDimitry Andric   case RISCV::VRM8_with_sub_vrm1_0_in_VMV0RegClassID:
116*5f757f3fSDimitry Andric     return getRegBank(RISCV::VRBRegBankID);
117*5f757f3fSDimitry Andric   }
118*5f757f3fSDimitry Andric }
119*5f757f3fSDimitry Andric 
getFPValueMapping(unsigned Size)120*5f757f3fSDimitry Andric static const RegisterBankInfo::ValueMapping *getFPValueMapping(unsigned Size) {
121*5f757f3fSDimitry Andric   assert(Size == 32 || Size == 64);
122*5f757f3fSDimitry Andric   unsigned Idx = Size == 64 ? RISCV::FPRB64Idx : RISCV::FPRB32Idx;
123*5f757f3fSDimitry Andric   return &RISCV::ValueMappings[Idx];
124*5f757f3fSDimitry Andric }
125*5f757f3fSDimitry Andric 
126*5f757f3fSDimitry Andric /// Returns whether opcode \p Opc is a pre-isel generic floating-point opcode,
127*5f757f3fSDimitry Andric /// having only floating-point operands.
128*5f757f3fSDimitry Andric /// FIXME: this is copied from target AArch64. Needs some code refactor here to
129*5f757f3fSDimitry Andric /// put this function in GlobalISel/Utils.cpp.
isPreISelGenericFloatingPointOpcode(unsigned Opc)130*5f757f3fSDimitry Andric static bool isPreISelGenericFloatingPointOpcode(unsigned Opc) {
131*5f757f3fSDimitry Andric   switch (Opc) {
132*5f757f3fSDimitry Andric   case TargetOpcode::G_FADD:
133*5f757f3fSDimitry Andric   case TargetOpcode::G_FSUB:
134*5f757f3fSDimitry Andric   case TargetOpcode::G_FMUL:
135*5f757f3fSDimitry Andric   case TargetOpcode::G_FMA:
136*5f757f3fSDimitry Andric   case TargetOpcode::G_FDIV:
137*5f757f3fSDimitry Andric   case TargetOpcode::G_FCONSTANT:
138*5f757f3fSDimitry Andric   case TargetOpcode::G_FPEXT:
139*5f757f3fSDimitry Andric   case TargetOpcode::G_FPTRUNC:
140*5f757f3fSDimitry Andric   case TargetOpcode::G_FCEIL:
141*5f757f3fSDimitry Andric   case TargetOpcode::G_FFLOOR:
142*5f757f3fSDimitry Andric   case TargetOpcode::G_FNEARBYINT:
143*5f757f3fSDimitry Andric   case TargetOpcode::G_FNEG:
144*5f757f3fSDimitry Andric   case TargetOpcode::G_FCOPYSIGN:
145*5f757f3fSDimitry Andric   case TargetOpcode::G_FCOS:
146*5f757f3fSDimitry Andric   case TargetOpcode::G_FSIN:
147*5f757f3fSDimitry Andric   case TargetOpcode::G_FLOG10:
148*5f757f3fSDimitry Andric   case TargetOpcode::G_FLOG:
149*5f757f3fSDimitry Andric   case TargetOpcode::G_FLOG2:
150*5f757f3fSDimitry Andric   case TargetOpcode::G_FSQRT:
151*5f757f3fSDimitry Andric   case TargetOpcode::G_FABS:
152*5f757f3fSDimitry Andric   case TargetOpcode::G_FEXP:
153*5f757f3fSDimitry Andric   case TargetOpcode::G_FRINT:
154*5f757f3fSDimitry Andric   case TargetOpcode::G_INTRINSIC_TRUNC:
155*5f757f3fSDimitry Andric   case TargetOpcode::G_INTRINSIC_ROUND:
156*5f757f3fSDimitry Andric   case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
157*5f757f3fSDimitry Andric   case TargetOpcode::G_FMAXNUM:
158*5f757f3fSDimitry Andric   case TargetOpcode::G_FMINNUM:
159*5f757f3fSDimitry Andric   case TargetOpcode::G_FMAXIMUM:
160*5f757f3fSDimitry Andric   case TargetOpcode::G_FMINIMUM:
161*5f757f3fSDimitry Andric     return true;
162*5f757f3fSDimitry Andric   }
163*5f757f3fSDimitry Andric   return false;
164*5f757f3fSDimitry Andric }
165*5f757f3fSDimitry Andric 
166*5f757f3fSDimitry Andric // TODO: Make this more like AArch64?
hasFPConstraints(const MachineInstr & MI,const MachineRegisterInfo & MRI,const TargetRegisterInfo & TRI) const167*5f757f3fSDimitry Andric bool RISCVRegisterBankInfo::hasFPConstraints(
168*5f757f3fSDimitry Andric     const MachineInstr &MI, const MachineRegisterInfo &MRI,
169*5f757f3fSDimitry Andric     const TargetRegisterInfo &TRI) const {
170*5f757f3fSDimitry Andric   if (isPreISelGenericFloatingPointOpcode(MI.getOpcode()))
171*5f757f3fSDimitry Andric     return true;
172*5f757f3fSDimitry Andric 
173*5f757f3fSDimitry Andric   // If we have a copy instruction, we could be feeding floating point
174*5f757f3fSDimitry Andric   // instructions.
175*5f757f3fSDimitry Andric   if (MI.getOpcode() != TargetOpcode::COPY)
176*5f757f3fSDimitry Andric     return false;
177*5f757f3fSDimitry Andric 
178*5f757f3fSDimitry Andric   return getRegBank(MI.getOperand(0).getReg(), MRI, TRI) == &RISCV::FPRBRegBank;
179*5f757f3fSDimitry Andric }
180*5f757f3fSDimitry Andric 
onlyUsesFP(const MachineInstr & MI,const MachineRegisterInfo & MRI,const TargetRegisterInfo & TRI) const181*5f757f3fSDimitry Andric bool RISCVRegisterBankInfo::onlyUsesFP(const MachineInstr &MI,
182*5f757f3fSDimitry Andric                                        const MachineRegisterInfo &MRI,
183*5f757f3fSDimitry Andric                                        const TargetRegisterInfo &TRI) const {
184*5f757f3fSDimitry Andric   switch (MI.getOpcode()) {
185*5f757f3fSDimitry Andric   case TargetOpcode::G_FPTOSI:
186*5f757f3fSDimitry Andric   case TargetOpcode::G_FPTOUI:
187*5f757f3fSDimitry Andric   case TargetOpcode::G_FCMP:
188*5f757f3fSDimitry Andric     return true;
189*5f757f3fSDimitry Andric   default:
190*5f757f3fSDimitry Andric     break;
191*5f757f3fSDimitry Andric   }
192*5f757f3fSDimitry Andric 
193*5f757f3fSDimitry Andric   return hasFPConstraints(MI, MRI, TRI);
194*5f757f3fSDimitry Andric }
195*5f757f3fSDimitry Andric 
onlyDefinesFP(const MachineInstr & MI,const MachineRegisterInfo & MRI,const TargetRegisterInfo & TRI) const196*5f757f3fSDimitry Andric bool RISCVRegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,
197*5f757f3fSDimitry Andric                                           const MachineRegisterInfo &MRI,
198*5f757f3fSDimitry Andric                                           const TargetRegisterInfo &TRI) const {
199*5f757f3fSDimitry Andric   switch (MI.getOpcode()) {
200*5f757f3fSDimitry Andric   case TargetOpcode::G_SITOFP:
201*5f757f3fSDimitry Andric   case TargetOpcode::G_UITOFP:
202*5f757f3fSDimitry Andric     return true;
203*5f757f3fSDimitry Andric   default:
204*5f757f3fSDimitry Andric     break;
205*5f757f3fSDimitry Andric   }
206*5f757f3fSDimitry Andric 
207*5f757f3fSDimitry Andric   return hasFPConstraints(MI, MRI, TRI);
208*5f757f3fSDimitry Andric }
209*5f757f3fSDimitry Andric 
anyUseOnlyUseFP(Register Def,const MachineRegisterInfo & MRI,const TargetRegisterInfo & TRI) const210*5f757f3fSDimitry Andric bool RISCVRegisterBankInfo::anyUseOnlyUseFP(
211*5f757f3fSDimitry Andric     Register Def, const MachineRegisterInfo &MRI,
212*5f757f3fSDimitry Andric     const TargetRegisterInfo &TRI) const {
213*5f757f3fSDimitry Andric   return any_of(
214*5f757f3fSDimitry Andric       MRI.use_nodbg_instructions(Def),
215*5f757f3fSDimitry Andric       [&](const MachineInstr &UseMI) { return onlyUsesFP(UseMI, MRI, TRI); });
216*5f757f3fSDimitry Andric }
217*5f757f3fSDimitry Andric 
218*5f757f3fSDimitry Andric const RegisterBankInfo::InstructionMapping &
getInstrMapping(const MachineInstr & MI) const219*5f757f3fSDimitry Andric RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
220*5f757f3fSDimitry Andric   const unsigned Opc = MI.getOpcode();
221*5f757f3fSDimitry Andric 
222*5f757f3fSDimitry Andric   // Try the default logic for non-generic instructions that are either copies
223*5f757f3fSDimitry Andric   // or already have some operands assigned to banks.
224*5f757f3fSDimitry Andric   if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
225*5f757f3fSDimitry Andric     const InstructionMapping &Mapping = getInstrMappingImpl(MI);
226*5f757f3fSDimitry Andric     if (Mapping.isValid())
227*5f757f3fSDimitry Andric       return Mapping;
228*5f757f3fSDimitry Andric   }
229*5f757f3fSDimitry Andric 
230*5f757f3fSDimitry Andric   const MachineFunction &MF = *MI.getParent()->getParent();
231*5f757f3fSDimitry Andric   const MachineRegisterInfo &MRI = MF.getRegInfo();
232*5f757f3fSDimitry Andric   const TargetSubtargetInfo &STI = MF.getSubtarget();
233*5f757f3fSDimitry Andric   const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
234*5f757f3fSDimitry Andric 
235*5f757f3fSDimitry Andric   unsigned GPRSize = getMaximumSize(RISCV::GPRBRegBankID);
236*5f757f3fSDimitry Andric   assert((GPRSize == 32 || GPRSize == 64) && "Unexpected GPR size");
237*5f757f3fSDimitry Andric 
238*5f757f3fSDimitry Andric   unsigned NumOperands = MI.getNumOperands();
239*5f757f3fSDimitry Andric   const ValueMapping *GPRValueMapping =
240*5f757f3fSDimitry Andric       &RISCV::ValueMappings[GPRSize == 64 ? RISCV::GPRB64Idx
241*5f757f3fSDimitry Andric                                           : RISCV::GPRB32Idx];
242*5f757f3fSDimitry Andric 
243*5f757f3fSDimitry Andric   switch (Opc) {
244*5f757f3fSDimitry Andric   case TargetOpcode::G_ADD:
245*5f757f3fSDimitry Andric   case TargetOpcode::G_SUB:
246*5f757f3fSDimitry Andric   case TargetOpcode::G_SHL:
247*5f757f3fSDimitry Andric   case TargetOpcode::G_ASHR:
248*5f757f3fSDimitry Andric   case TargetOpcode::G_LSHR:
249*5f757f3fSDimitry Andric   case TargetOpcode::G_AND:
250*5f757f3fSDimitry Andric   case TargetOpcode::G_OR:
251*5f757f3fSDimitry Andric   case TargetOpcode::G_XOR:
252*5f757f3fSDimitry Andric   case TargetOpcode::G_MUL:
253*5f757f3fSDimitry Andric   case TargetOpcode::G_SDIV:
254*5f757f3fSDimitry Andric   case TargetOpcode::G_SREM:
255*5f757f3fSDimitry Andric   case TargetOpcode::G_SMULH:
256*5f757f3fSDimitry Andric   case TargetOpcode::G_SMAX:
257*5f757f3fSDimitry Andric   case TargetOpcode::G_SMIN:
258*5f757f3fSDimitry Andric   case TargetOpcode::G_UDIV:
259*5f757f3fSDimitry Andric   case TargetOpcode::G_UREM:
260*5f757f3fSDimitry Andric   case TargetOpcode::G_UMULH:
261*5f757f3fSDimitry Andric   case TargetOpcode::G_UMAX:
262*5f757f3fSDimitry Andric   case TargetOpcode::G_UMIN:
263*5f757f3fSDimitry Andric   case TargetOpcode::G_PTR_ADD:
264*5f757f3fSDimitry Andric   case TargetOpcode::G_PTRTOINT:
265*5f757f3fSDimitry Andric   case TargetOpcode::G_INTTOPTR:
266*5f757f3fSDimitry Andric   case TargetOpcode::G_TRUNC:
267*5f757f3fSDimitry Andric   case TargetOpcode::G_ANYEXT:
268*5f757f3fSDimitry Andric   case TargetOpcode::G_SEXT:
269*5f757f3fSDimitry Andric   case TargetOpcode::G_ZEXT:
270*5f757f3fSDimitry Andric   case TargetOpcode::G_SEXTLOAD:
271*5f757f3fSDimitry Andric   case TargetOpcode::G_ZEXTLOAD:
272*5f757f3fSDimitry Andric     return getInstructionMapping(DefaultMappingID, /*Cost=*/1, GPRValueMapping,
273*5f757f3fSDimitry Andric                                  NumOperands);
274*5f757f3fSDimitry Andric   case TargetOpcode::G_FADD:
275*5f757f3fSDimitry Andric   case TargetOpcode::G_FSUB:
276*5f757f3fSDimitry Andric   case TargetOpcode::G_FMUL:
277*5f757f3fSDimitry Andric   case TargetOpcode::G_FDIV:
278*5f757f3fSDimitry Andric   case TargetOpcode::G_FABS:
279*5f757f3fSDimitry Andric   case TargetOpcode::G_FNEG:
280*5f757f3fSDimitry Andric   case TargetOpcode::G_FSQRT:
281*5f757f3fSDimitry Andric   case TargetOpcode::G_FMAXNUM:
282*5f757f3fSDimitry Andric   case TargetOpcode::G_FMINNUM: {
283*5f757f3fSDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(0).getReg());
284*5f757f3fSDimitry Andric     return getInstructionMapping(DefaultMappingID, /*Cost=*/1,
285*5f757f3fSDimitry Andric                                  getFPValueMapping(Ty.getSizeInBits()),
286*5f757f3fSDimitry Andric                                  NumOperands);
287*5f757f3fSDimitry Andric   }
288*5f757f3fSDimitry Andric   case TargetOpcode::G_IMPLICIT_DEF: {
289*5f757f3fSDimitry Andric     Register Dst = MI.getOperand(0).getReg();
290*5f757f3fSDimitry Andric     auto Mapping = GPRValueMapping;
291*5f757f3fSDimitry Andric     // FIXME: May need to do a better job determining when to use FPRB.
292*5f757f3fSDimitry Andric     // For example, the look through COPY case:
293*5f757f3fSDimitry Andric     // %0:_(s32) = G_IMPLICIT_DEF
294*5f757f3fSDimitry Andric     // %1:_(s32) = COPY %0
295*5f757f3fSDimitry Andric     // $f10_d = COPY %1(s32)
296*5f757f3fSDimitry Andric     if (anyUseOnlyUseFP(Dst, MRI, TRI))
297*5f757f3fSDimitry Andric       Mapping = getFPValueMapping(MRI.getType(Dst).getSizeInBits());
298*5f757f3fSDimitry Andric     return getInstructionMapping(DefaultMappingID, /*Cost=*/1, Mapping,
299*5f757f3fSDimitry Andric                                  NumOperands);
300*5f757f3fSDimitry Andric   }
301*5f757f3fSDimitry Andric   }
302*5f757f3fSDimitry Andric 
303*5f757f3fSDimitry Andric   SmallVector<const ValueMapping *, 4> OpdsMapping(NumOperands);
304*5f757f3fSDimitry Andric 
305*5f757f3fSDimitry Andric   switch (Opc) {
306*5f757f3fSDimitry Andric   case TargetOpcode::G_LOAD: {
307*5f757f3fSDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(0).getReg());
308*5f757f3fSDimitry Andric     OpdsMapping[0] = GPRValueMapping;
309*5f757f3fSDimitry Andric     OpdsMapping[1] = GPRValueMapping;
310*5f757f3fSDimitry Andric     // Use FPR64 for s64 loads on rv32.
311*5f757f3fSDimitry Andric     if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
312*5f757f3fSDimitry Andric       assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
313*5f757f3fSDimitry Andric       OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
314*5f757f3fSDimitry Andric       break;
315*5f757f3fSDimitry Andric     }
316*5f757f3fSDimitry Andric 
317*5f757f3fSDimitry Andric     // Check if that load feeds fp instructions.
318*5f757f3fSDimitry Andric     // In that case, we want the default mapping to be on FPR
319*5f757f3fSDimitry Andric     // instead of blind map every scalar to GPR.
320*5f757f3fSDimitry Andric     if (anyUseOnlyUseFP(MI.getOperand(0).getReg(), MRI, TRI))
321*5f757f3fSDimitry Andric       // If we have at least one direct use in a FP instruction,
322*5f757f3fSDimitry Andric       // assume this was a floating point load in the IR. If it was
323*5f757f3fSDimitry Andric       // not, we would have had a bitcast before reaching that
324*5f757f3fSDimitry Andric       // instruction.
325*5f757f3fSDimitry Andric       OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
326*5f757f3fSDimitry Andric 
327*5f757f3fSDimitry Andric     break;
328*5f757f3fSDimitry Andric   }
329*5f757f3fSDimitry Andric   case TargetOpcode::G_STORE: {
330*5f757f3fSDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(0).getReg());
331*5f757f3fSDimitry Andric     OpdsMapping[0] = GPRValueMapping;
332*5f757f3fSDimitry Andric     OpdsMapping[1] = GPRValueMapping;
333*5f757f3fSDimitry Andric     // Use FPR64 for s64 stores on rv32.
334*5f757f3fSDimitry Andric     if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
335*5f757f3fSDimitry Andric       assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
336*5f757f3fSDimitry Andric       OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
337*5f757f3fSDimitry Andric       break;
338*5f757f3fSDimitry Andric     }
339*5f757f3fSDimitry Andric 
340*5f757f3fSDimitry Andric     MachineInstr *DefMI = MRI.getVRegDef(MI.getOperand(0).getReg());
341*5f757f3fSDimitry Andric     if (onlyDefinesFP(*DefMI, MRI, TRI))
342*5f757f3fSDimitry Andric       OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
343*5f757f3fSDimitry Andric     break;
344*5f757f3fSDimitry Andric   }
345*5f757f3fSDimitry Andric   case TargetOpcode::G_SELECT: {
346*5f757f3fSDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(0).getReg());
347*5f757f3fSDimitry Andric 
348*5f757f3fSDimitry Andric     // Try to minimize the number of copies. If we have more floating point
349*5f757f3fSDimitry Andric     // constrained values than not, then we'll put everything on FPR. Otherwise,
350*5f757f3fSDimitry Andric     // everything has to be on GPR.
351*5f757f3fSDimitry Andric     unsigned NumFP = 0;
352*5f757f3fSDimitry Andric 
353*5f757f3fSDimitry Andric     // Use FPR64 for s64 select on rv32.
354*5f757f3fSDimitry Andric     if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
355*5f757f3fSDimitry Andric       NumFP = 3;
356*5f757f3fSDimitry Andric     } else {
357*5f757f3fSDimitry Andric       // Check if the uses of the result always produce floating point values.
358*5f757f3fSDimitry Andric       //
359*5f757f3fSDimitry Andric       // For example:
360*5f757f3fSDimitry Andric       //
361*5f757f3fSDimitry Andric       // %z = G_SELECT %cond %x %y
362*5f757f3fSDimitry Andric       // fpr = G_FOO %z ...
363*5f757f3fSDimitry Andric       if (any_of(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()),
364*5f757f3fSDimitry Andric                  [&](const MachineInstr &UseMI) {
365*5f757f3fSDimitry Andric                    return onlyUsesFP(UseMI, MRI, TRI);
366*5f757f3fSDimitry Andric                  }))
367*5f757f3fSDimitry Andric         ++NumFP;
368*5f757f3fSDimitry Andric 
369*5f757f3fSDimitry Andric       // Check if the defs of the source values always produce floating point
370*5f757f3fSDimitry Andric       // values.
371*5f757f3fSDimitry Andric       //
372*5f757f3fSDimitry Andric       // For example:
373*5f757f3fSDimitry Andric       //
374*5f757f3fSDimitry Andric       // %x = G_SOMETHING_ALWAYS_FLOAT %a ...
375*5f757f3fSDimitry Andric       // %z = G_SELECT %cond %x %y
376*5f757f3fSDimitry Andric       //
377*5f757f3fSDimitry Andric       // Also check whether or not the sources have already been decided to be
378*5f757f3fSDimitry Andric       // FPR. Keep track of this.
379*5f757f3fSDimitry Andric       //
380*5f757f3fSDimitry Andric       // This doesn't check the condition, since the condition is always an
381*5f757f3fSDimitry Andric       // integer.
382*5f757f3fSDimitry Andric       for (unsigned Idx = 2; Idx < 4; ++Idx) {
383*5f757f3fSDimitry Andric         Register VReg = MI.getOperand(Idx).getReg();
384*5f757f3fSDimitry Andric         MachineInstr *DefMI = MRI.getVRegDef(VReg);
385*5f757f3fSDimitry Andric         if (getRegBank(VReg, MRI, TRI) == &RISCV::FPRBRegBank ||
386*5f757f3fSDimitry Andric             onlyDefinesFP(*DefMI, MRI, TRI))
387*5f757f3fSDimitry Andric           ++NumFP;
388*5f757f3fSDimitry Andric       }
389*5f757f3fSDimitry Andric     }
390*5f757f3fSDimitry Andric 
391*5f757f3fSDimitry Andric     // Condition operand is always GPR.
392*5f757f3fSDimitry Andric     OpdsMapping[1] = GPRValueMapping;
393*5f757f3fSDimitry Andric 
394*5f757f3fSDimitry Andric     const ValueMapping *Mapping = GPRValueMapping;
395*5f757f3fSDimitry Andric     if (NumFP >= 2)
396*5f757f3fSDimitry Andric       Mapping = getFPValueMapping(Ty.getSizeInBits());
397*5f757f3fSDimitry Andric 
398*5f757f3fSDimitry Andric     OpdsMapping[0] = OpdsMapping[2] = OpdsMapping[3] = Mapping;
399*5f757f3fSDimitry Andric     break;
400*5f757f3fSDimitry Andric   }
401*5f757f3fSDimitry Andric   case TargetOpcode::G_FPTOSI:
402*5f757f3fSDimitry Andric   case TargetOpcode::G_FPTOUI:
403*5f757f3fSDimitry Andric   case RISCV::G_FCLASS: {
404*5f757f3fSDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(1).getReg());
405*5f757f3fSDimitry Andric     OpdsMapping[0] = GPRValueMapping;
406*5f757f3fSDimitry Andric     OpdsMapping[1] = getFPValueMapping(Ty.getSizeInBits());
407*5f757f3fSDimitry Andric     break;
408*5f757f3fSDimitry Andric   }
409*5f757f3fSDimitry Andric   case TargetOpcode::G_SITOFP:
410*5f757f3fSDimitry Andric   case TargetOpcode::G_UITOFP: {
411*5f757f3fSDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(0).getReg());
412*5f757f3fSDimitry Andric     OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
413*5f757f3fSDimitry Andric     OpdsMapping[1] = GPRValueMapping;
414*5f757f3fSDimitry Andric     break;
415*5f757f3fSDimitry Andric   }
416*5f757f3fSDimitry Andric   case TargetOpcode::G_FCMP: {
417*5f757f3fSDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(2).getReg());
418*5f757f3fSDimitry Andric 
419*5f757f3fSDimitry Andric     unsigned Size = Ty.getSizeInBits();
420*5f757f3fSDimitry Andric     assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP");
421*5f757f3fSDimitry Andric 
422*5f757f3fSDimitry Andric     OpdsMapping[0] = GPRValueMapping;
423*5f757f3fSDimitry Andric     OpdsMapping[2] = OpdsMapping[3] = getFPValueMapping(Size);
424*5f757f3fSDimitry Andric     break;
425*5f757f3fSDimitry Andric   }
426*5f757f3fSDimitry Andric   case TargetOpcode::G_MERGE_VALUES: {
427*5f757f3fSDimitry Andric     // Use FPR64 for s64 merge on rv32.
428*5f757f3fSDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(0).getReg());
429*5f757f3fSDimitry Andric     if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
430*5f757f3fSDimitry Andric       assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
431*5f757f3fSDimitry Andric       OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
432*5f757f3fSDimitry Andric       OpdsMapping[1] = GPRValueMapping;
433*5f757f3fSDimitry Andric       OpdsMapping[2] = GPRValueMapping;
434*5f757f3fSDimitry Andric     }
435*5f757f3fSDimitry Andric     break;
436*5f757f3fSDimitry Andric   }
437*5f757f3fSDimitry Andric   case TargetOpcode::G_UNMERGE_VALUES: {
438*5f757f3fSDimitry Andric     // Use FPR64 for s64 unmerge on rv32.
439*5f757f3fSDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(2).getReg());
440*5f757f3fSDimitry Andric     if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
441*5f757f3fSDimitry Andric       assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
442*5f757f3fSDimitry Andric       OpdsMapping[0] = GPRValueMapping;
443*5f757f3fSDimitry Andric       OpdsMapping[1] = GPRValueMapping;
444*5f757f3fSDimitry Andric       OpdsMapping[2] = getFPValueMapping(Ty.getSizeInBits());
445*5f757f3fSDimitry Andric     }
446*5f757f3fSDimitry Andric     break;
447*5f757f3fSDimitry Andric   }
448*5f757f3fSDimitry Andric   default:
449*5f757f3fSDimitry Andric     // By default map all scalars to GPR.
450*5f757f3fSDimitry Andric     for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
451*5f757f3fSDimitry Andric        auto &MO = MI.getOperand(Idx);
452*5f757f3fSDimitry Andric        if (!MO.isReg() || !MO.getReg())
453*5f757f3fSDimitry Andric          continue;
454*5f757f3fSDimitry Andric        LLT Ty = MRI.getType(MO.getReg());
455*5f757f3fSDimitry Andric        if (!Ty.isValid())
456*5f757f3fSDimitry Andric          continue;
457*5f757f3fSDimitry Andric 
458*5f757f3fSDimitry Andric        if (isPreISelGenericFloatingPointOpcode(Opc))
459*5f757f3fSDimitry Andric          OpdsMapping[Idx] = getFPValueMapping(Ty.getSizeInBits());
460*5f757f3fSDimitry Andric        else
461*5f757f3fSDimitry Andric          OpdsMapping[Idx] = GPRValueMapping;
462*5f757f3fSDimitry Andric     }
463*5f757f3fSDimitry Andric     break;
464*5f757f3fSDimitry Andric   }
465*5f757f3fSDimitry Andric 
466*5f757f3fSDimitry Andric   return getInstructionMapping(DefaultMappingID, /*Cost=*/1,
467*5f757f3fSDimitry Andric                                getOperandsMapping(OpdsMapping), NumOperands);
468*5f757f3fSDimitry Andric }
469