xref: /llvm-project/llvm/lib/Target/X86/GISel/X86RegisterBankInfo.cpp (revision e9cb44090ff7b3feda386ca1ee1252ab47c0617e)
1 //===- X86RegisterBankInfo.cpp -----------------------------------*- C++ -*-==//
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 X86.
10 /// \todo This should be generated by TableGen.
11 //===----------------------------------------------------------------------===//
12 
13 #include "X86RegisterBankInfo.h"
14 #include "X86InstrInfo.h"
15 #include "X86Subtarget.h"
16 #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
17 #include "llvm/CodeGen/GlobalISel/Utils.h"
18 #include "llvm/CodeGen/MachineRegisterInfo.h"
19 #include "llvm/CodeGen/RegisterBank.h"
20 #include "llvm/CodeGen/RegisterBankInfo.h"
21 #include "llvm/CodeGen/TargetRegisterInfo.h"
22 #include "llvm/IR/IntrinsicsX86.h"
23 
24 #define GET_TARGET_REGBANK_IMPL
25 #include "X86GenRegisterBank.inc"
26 
27 using namespace llvm;
28 // This file will be TableGen'ed at some point.
29 #define GET_TARGET_REGBANK_INFO_IMPL
30 #include "X86GenRegisterBankInfo.def"
31 
32 X86RegisterBankInfo::X86RegisterBankInfo(const TargetRegisterInfo &TRI) {
33 
34   // validate RegBank initialization.
35   const RegisterBank &RBGPR = getRegBank(X86::GPRRegBankID);
36   (void)RBGPR;
37   assert(&X86::GPRRegBank == &RBGPR && "Incorrect RegBanks inizalization.");
38 
39   // The GPR register bank is fully defined by all the registers in
40   // GR64 + its subclasses.
41   assert(RBGPR.covers(*TRI.getRegClass(X86::GR64RegClassID)) &&
42          "Subclass not added?");
43   assert(getMaximumSize(RBGPR.getID()) == 64 &&
44          "GPRs should hold up to 64-bit");
45 }
46 
47 // \returns true if a given intrinsic only uses and defines FPRs.
48 static bool isFPIntrinsic(const MachineRegisterInfo &MRI,
49                           const MachineInstr &MI) {
50   // TODO: Add more intrinsics.
51   switch (cast<GIntrinsic>(MI).getIntrinsicID()) {
52   default:
53     return false;
54   // SSE1
55   case Intrinsic::x86_sse_rcp_ss:
56   case Intrinsic::x86_sse_rcp_ps:
57   case Intrinsic::x86_sse_rsqrt_ss:
58   case Intrinsic::x86_sse_rsqrt_ps:
59   case Intrinsic::x86_sse_min_ss:
60   case Intrinsic::x86_sse_min_ps:
61   case Intrinsic::x86_sse_max_ss:
62   case Intrinsic::x86_sse_max_ps:
63     return true;
64   }
65   return false;
66 }
67 
68 bool X86RegisterBankInfo::hasFPConstraints(const MachineInstr &MI,
69                                            const MachineRegisterInfo &MRI,
70                                            const TargetRegisterInfo &TRI,
71                                            unsigned Depth) const {
72   unsigned Op = MI.getOpcode();
73   if (Op == TargetOpcode::G_INTRINSIC && isFPIntrinsic(MRI, MI))
74     return true;
75 
76   // Do we have an explicit floating point instruction?
77   if (isPreISelGenericFloatingPointOpcode(Op))
78     return true;
79 
80   // No. Check if we have a copy-like instruction. If we do, then we could
81   // still be fed by floating point instructions.
82   if (Op != TargetOpcode::COPY && !MI.isPHI() &&
83       !isPreISelGenericOptimizationHint(Op))
84     return false;
85 
86   // Check if we already know the register bank.
87   auto *RB = getRegBank(MI.getOperand(0).getReg(), MRI, TRI);
88   if (RB == &getRegBank(X86::PSRRegBankID))
89     return true;
90   if (RB == &getRegBank(X86::GPRRegBankID))
91     return false;
92 
93   // We don't know anything.
94   //
95   // If we have a phi, we may be able to infer that it will be assigned a fp
96   // type based off of its inputs.
97   if (!MI.isPHI() || Depth > MaxFPRSearchDepth)
98     return false;
99 
100   return any_of(MI.explicit_uses(), [&](const MachineOperand &Op) {
101     return Op.isReg() &&
102            onlyDefinesFP(*MRI.getVRegDef(Op.getReg()), MRI, TRI, Depth + 1);
103   });
104 }
105 
106 bool X86RegisterBankInfo::onlyUsesFP(const MachineInstr &MI,
107                                      const MachineRegisterInfo &MRI,
108                                      const TargetRegisterInfo &TRI,
109                                      unsigned Depth) const {
110   switch (MI.getOpcode()) {
111   case TargetOpcode::G_FPTOSI:
112   case TargetOpcode::G_FPTOUI:
113   case TargetOpcode::G_FCMP:
114   case TargetOpcode::G_LROUND:
115   case TargetOpcode::G_LLROUND:
116   case TargetOpcode::G_INTRINSIC_TRUNC:
117   case TargetOpcode::G_INTRINSIC_ROUND:
118     return true;
119   default:
120     break;
121   }
122   return hasFPConstraints(MI, MRI, TRI, Depth);
123 }
124 
125 bool X86RegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,
126                                         const MachineRegisterInfo &MRI,
127                                         const TargetRegisterInfo &TRI,
128                                         unsigned Depth) const {
129   switch (MI.getOpcode()) {
130   case TargetOpcode::G_SITOFP:
131   case TargetOpcode::G_UITOFP:
132     return true;
133   default:
134     break;
135   }
136   return hasFPConstraints(MI, MRI, TRI, Depth);
137 }
138 
139 X86GenRegisterBankInfo::PartialMappingIdx
140 X86GenRegisterBankInfo::getPartialMappingIdx(const MachineInstr &MI,
141                                              const LLT &Ty, bool isFP) {
142   const MachineFunction *MF = MI.getMF();
143   const X86Subtarget *ST = &MF->getSubtarget<X86Subtarget>();
144   bool HasSSE1 = ST->hasSSE1();
145   bool HasSSE2 = ST->hasSSE2();
146   // 80 bits is only generated for X87 floating points.
147   if (Ty.getSizeInBits() == 80)
148     isFP = true;
149   if ((Ty.isScalar() && !isFP) || Ty.isPointer()) {
150     switch (Ty.getSizeInBits()) {
151     case 1:
152     case 8:
153       return PMI_GPR8;
154     case 16:
155       return PMI_GPR16;
156     case 32:
157       return PMI_GPR32;
158     case 64:
159       return PMI_GPR64;
160     case 128:
161       return PMI_VEC128;
162       break;
163     default:
164       llvm_unreachable("Unsupported register size.");
165     }
166   } else if (Ty.isScalar()) {
167     switch (Ty.getSizeInBits()) {
168     case 32:
169       return HasSSE1 ? PMI_FP32 : PMI_PSR32;
170     case 64:
171       return HasSSE2 ? PMI_FP64 : PMI_PSR64;
172     case 128:
173       return PMI_VEC128;
174     case 80:
175       return PMI_PSR80;
176     default:
177       llvm_unreachable("Unsupported register size.");
178     }
179   } else {
180     switch (Ty.getSizeInBits()) {
181     case 128:
182       return PMI_VEC128;
183     case 256:
184       return PMI_VEC256;
185     case 512:
186       return PMI_VEC512;
187     default:
188       llvm_unreachable("Unsupported register size.");
189     }
190   }
191 
192   return PMI_None;
193 }
194 
195 void X86RegisterBankInfo::getInstrPartialMappingIdxs(
196     const MachineInstr &MI, const MachineRegisterInfo &MRI, const bool isFP,
197     SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx) {
198 
199   unsigned NumOperands = MI.getNumOperands();
200   for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
201     auto &MO = MI.getOperand(Idx);
202     if (!MO.isReg() || !MO.getReg())
203       OpRegBankIdx[Idx] = PMI_None;
204     else
205       OpRegBankIdx[Idx] =
206           getPartialMappingIdx(MI, MRI.getType(MO.getReg()), isFP);
207   }
208 }
209 
210 bool X86RegisterBankInfo::getInstrValueMapping(
211     const MachineInstr &MI,
212     const SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx,
213     SmallVectorImpl<const ValueMapping *> &OpdsMapping) {
214 
215   unsigned NumOperands = MI.getNumOperands();
216   for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
217     if (!MI.getOperand(Idx).isReg())
218       continue;
219     if (!MI.getOperand(Idx).getReg())
220       continue;
221 
222     auto Mapping = getValueMapping(OpRegBankIdx[Idx], 1);
223     if (!Mapping->isValid())
224       return false;
225 
226     OpdsMapping[Idx] = Mapping;
227   }
228   return true;
229 }
230 
231 const RegisterBankInfo::InstructionMapping &
232 X86RegisterBankInfo::getSameOperandsMapping(const MachineInstr &MI,
233                                             bool isFP) const {
234   const MachineFunction &MF = *MI.getParent()->getParent();
235   const MachineRegisterInfo &MRI = MF.getRegInfo();
236 
237   unsigned NumOperands = MI.getNumOperands();
238   LLT Ty = MRI.getType(MI.getOperand(0).getReg());
239 
240   if (NumOperands != 3 || (Ty != MRI.getType(MI.getOperand(1).getReg())) ||
241       (Ty != MRI.getType(MI.getOperand(2).getReg())))
242     llvm_unreachable("Unsupported operand mapping yet.");
243 
244   auto Mapping = getValueMapping(getPartialMappingIdx(MI, Ty, isFP), 3);
245   return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);
246 }
247 
248 const RegisterBankInfo::InstructionMapping &
249 X86RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
250   const MachineFunction &MF = *MI.getParent()->getParent();
251   const TargetSubtargetInfo &STI = MF.getSubtarget();
252   const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
253   const MachineRegisterInfo &MRI = MF.getRegInfo();
254   unsigned Opc = MI.getOpcode();
255 
256   // Try the default logic for non-generic instructions that are either
257   // copies or already have some operands assigned to banks.
258   if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
259     const InstructionMapping &Mapping = getInstrMappingImpl(MI);
260     if (Mapping.isValid())
261       return Mapping;
262   }
263 
264   switch (Opc) {
265   case TargetOpcode::G_ADD:
266   case TargetOpcode::G_SUB:
267   case TargetOpcode::G_MUL:
268     return getSameOperandsMapping(MI, false);
269   case TargetOpcode::G_FADD:
270   case TargetOpcode::G_FSUB:
271   case TargetOpcode::G_FMUL:
272   case TargetOpcode::G_FDIV:
273     return getSameOperandsMapping(MI, true);
274   case TargetOpcode::G_SHL:
275   case TargetOpcode::G_LSHR:
276   case TargetOpcode::G_ASHR: {
277     unsigned NumOperands = MI.getNumOperands();
278     LLT Ty = MRI.getType(MI.getOperand(0).getReg());
279 
280     auto Mapping = getValueMapping(getPartialMappingIdx(MI, Ty, false), 3);
281     return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);
282   }
283   default:
284     break;
285   }
286 
287   unsigned NumOperands = MI.getNumOperands();
288   SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
289 
290   switch (Opc) {
291   case TargetOpcode::G_FPEXT:
292   case TargetOpcode::G_FPTRUNC:
293   case TargetOpcode::G_FCONSTANT:
294     // Instruction having only floating-point operands (all scalars in
295     // VECRReg)
296     getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx);
297     break;
298   case TargetOpcode::G_SITOFP:
299   case TargetOpcode::G_FPTOSI:
300   case TargetOpcode::G_UITOFP:
301   case TargetOpcode::G_FPTOUI: {
302     // Some of the floating-point instructions have mixed GPR and FP
303     // operands: fine-tune the computed mapping.
304     auto &Op0 = MI.getOperand(0);
305     auto &Op1 = MI.getOperand(1);
306     const LLT Ty0 = MRI.getType(Op0.getReg());
307     const LLT Ty1 = MRI.getType(Op1.getReg());
308 
309     bool FirstArgIsFP =
310         Opc == TargetOpcode::G_SITOFP || Opc == TargetOpcode::G_UITOFP;
311     OpRegBankIdx[0] = getPartialMappingIdx(MI, Ty0, /* isFP= */ FirstArgIsFP);
312     OpRegBankIdx[1] = getPartialMappingIdx(MI, Ty1, /* isFP= */ !FirstArgIsFP);
313     break;
314   }
315   case TargetOpcode::G_FCMP: {
316     LLT Ty1 = MRI.getType(MI.getOperand(2).getReg());
317     LLT Ty2 = MRI.getType(MI.getOperand(3).getReg());
318     (void)Ty2;
319     assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() &&
320            "Mismatched operand sizes for G_FCMP");
321 
322     unsigned Size = Ty1.getSizeInBits();
323     (void)Size;
324     assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP");
325 
326     auto FpRegBank = getPartialMappingIdx(MI, Ty1, /* isFP= */ true);
327     OpRegBankIdx = {PMI_GPR8,
328                     /* Predicate */ PMI_None, FpRegBank, FpRegBank};
329     break;
330   }
331   case TargetOpcode::G_TRUNC:
332   case TargetOpcode::G_ANYEXT: {
333     auto &Op0 = MI.getOperand(0);
334     auto &Op1 = MI.getOperand(1);
335     const LLT Ty0 = MRI.getType(Op0.getReg());
336     const LLT Ty1 = MRI.getType(Op1.getReg());
337 
338     bool isFPTrunc = (Ty0.getSizeInBits() == 32 || Ty0.getSizeInBits() == 64) &&
339                      Ty1.getSizeInBits() == 128 && Opc == TargetOpcode::G_TRUNC;
340     bool isFPAnyExt =
341         Ty0.getSizeInBits() == 128 &&
342         (Ty1.getSizeInBits() == 32 || Ty1.getSizeInBits() == 64) &&
343         Opc == TargetOpcode::G_ANYEXT;
344 
345     getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ isFPTrunc || isFPAnyExt,
346                                OpRegBankIdx);
347     break;
348   }
349   case TargetOpcode::G_LOAD: {
350     // Check if that load feeds fp instructions.
351     // In that case, we want the default mapping to be on FPR
352     // instead of blind map every scalar to GPR.
353     bool IsFP = any_of(MRI.use_nodbg_instructions(cast<GLoad>(MI).getDstReg()),
354                        [&](const MachineInstr &UseMI) {
355                          // If we have at least one direct use in a FP
356                          // instruction, assume this was a floating point load
357                          // in the IR. If it was not, we would have had a
358                          // bitcast before reaching that instruction.
359                          return onlyUsesFP(UseMI, MRI, TRI);
360                        });
361     getInstrPartialMappingIdxs(MI, MRI, IsFP, OpRegBankIdx);
362     break;
363   }
364   case TargetOpcode::G_STORE: {
365     // Check if that store is fed by fp instructions.
366     Register VReg = cast<GStore>(MI).getValueReg();
367     if (!VReg)
368       break;
369     MachineInstr *DefMI = MRI.getVRegDef(VReg);
370     bool IsFP = onlyDefinesFP(*DefMI, MRI, TRI);
371     getInstrPartialMappingIdxs(MI, MRI, IsFP, OpRegBankIdx);
372     break;
373   }
374   default:
375     // Track the bank of each register, use NotFP mapping (all scalars in
376     // GPRs)
377     getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ false, OpRegBankIdx);
378     break;
379   }
380 
381   // Finally construct the computed mapping.
382   SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
383   if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))
384     return getInvalidInstructionMapping();
385 
386   return getInstructionMapping(DefaultMappingID, /* Cost */ 1,
387                                getOperandsMapping(OpdsMapping), NumOperands);
388 }
389 
390 void X86RegisterBankInfo::applyMappingImpl(
391     MachineIRBuilder &Builder, const OperandsMapper &OpdMapper) const {
392   return applyDefaultMapping(OpdMapper);
393 }
394 
395 RegisterBankInfo::InstructionMappings
396 X86RegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const {
397 
398   const MachineFunction &MF = *MI.getParent()->getParent();
399   const TargetSubtargetInfo &STI = MF.getSubtarget();
400   const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
401   const MachineRegisterInfo &MRI = MF.getRegInfo();
402 
403   switch (MI.getOpcode()) {
404   case TargetOpcode::G_LOAD:
405   case TargetOpcode::G_STORE:
406   case TargetOpcode::G_IMPLICIT_DEF: {
407     // we going to try to map 32/64/80 bit to PMI_FP32/PMI_FP64/PMI_FP80
408     unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);
409     if (Size != 32 && Size != 64 && Size != 80)
410       break;
411 
412     unsigned NumOperands = MI.getNumOperands();
413 
414     // Track the bank of each register, use FP mapping (all scalars in VEC)
415     SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
416     getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx);
417 
418     // Finally construct the computed mapping.
419     SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
420     if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))
421       break;
422 
423     const RegisterBankInfo::InstructionMapping &Mapping = getInstructionMapping(
424         /*ID*/ 1, /*Cost*/ 1, getOperandsMapping(OpdsMapping), NumOperands);
425     InstructionMappings AltMappings;
426     AltMappings.push_back(&Mapping);
427     return AltMappings;
428   }
429   default:
430     break;
431   }
432   return RegisterBankInfo::getInstrAlternativeMappings(MI);
433 }
434