1 //===- X86RegisterBankInfo.cpp -----------------------------------*- C++ -*-==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 /// \file
10 /// This file implements the targeting of the RegisterBankInfo class for X86.
11 /// \todo This should be generated by TableGen.
12 //===----------------------------------------------------------------------===//
13 
14 #include "X86RegisterBankInfo.h"
15 #include "X86InstrInfo.h"
16 #include "llvm/CodeGen/GlobalISel/RegisterBank.h"
17 #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
18 #include "llvm/CodeGen/MachineRegisterInfo.h"
19 #include "llvm/CodeGen/TargetRegisterInfo.h"
20 
21 #define GET_TARGET_REGBANK_IMPL
22 #include "X86GenRegisterBank.inc"
23 
24 using namespace llvm;
25 // This file will be TableGen'ed at some point.
26 #define GET_TARGET_REGBANK_INFO_IMPL
27 #include "X86GenRegisterBankInfo.def"
28 
X86RegisterBankInfo(const TargetRegisterInfo & TRI)29 X86RegisterBankInfo::X86RegisterBankInfo(const TargetRegisterInfo &TRI)
30     : X86GenRegisterBankInfo() {
31 
32   // validate RegBank initialization.
33   const RegisterBank &RBGPR = getRegBank(X86::GPRRegBankID);
34   (void)RBGPR;
35   assert(&X86::GPRRegBank == &RBGPR && "Incorrect RegBanks inizalization.");
36 
37   // The GPR register bank is fully defined by all the registers in
38   // GR64 + its subclasses.
39   assert(RBGPR.covers(*TRI.getRegClass(X86::GR64RegClassID)) &&
40          "Subclass not added?");
41   assert(RBGPR.getSize() == 64 && "GPRs should hold up to 64-bit");
42 }
43 
getRegBankFromRegClass(const TargetRegisterClass & RC) const44 const RegisterBank &X86RegisterBankInfo::getRegBankFromRegClass(
45     const TargetRegisterClass &RC) const {
46 
47   if (X86::GR8RegClass.hasSubClassEq(&RC) ||
48       X86::GR16RegClass.hasSubClassEq(&RC) ||
49       X86::GR32RegClass.hasSubClassEq(&RC) ||
50       X86::GR64RegClass.hasSubClassEq(&RC))
51     return getRegBank(X86::GPRRegBankID);
52 
53   if (X86::FR32XRegClass.hasSubClassEq(&RC) ||
54       X86::FR64XRegClass.hasSubClassEq(&RC) ||
55       X86::VR128XRegClass.hasSubClassEq(&RC) ||
56       X86::VR256XRegClass.hasSubClassEq(&RC) ||
57       X86::VR512RegClass.hasSubClassEq(&RC))
58     return getRegBank(X86::VECRRegBankID);
59 
60   llvm_unreachable("Unsupported register kind yet.");
61 }
62 
63 X86GenRegisterBankInfo::PartialMappingIdx
getPartialMappingIdx(const LLT & Ty,bool isFP)64 X86GenRegisterBankInfo::getPartialMappingIdx(const LLT &Ty, bool isFP) {
65   if ((Ty.isScalar() && !isFP) || Ty.isPointer()) {
66     switch (Ty.getSizeInBits()) {
67     case 1:
68     case 8:
69       return PMI_GPR8;
70     case 16:
71       return PMI_GPR16;
72     case 32:
73       return PMI_GPR32;
74     case 64:
75       return PMI_GPR64;
76     case 128:
77       return PMI_VEC128;
78       break;
79     default:
80       llvm_unreachable("Unsupported register size.");
81     }
82   } else if (Ty.isScalar()) {
83     switch (Ty.getSizeInBits()) {
84     case 32:
85       return PMI_FP32;
86     case 64:
87       return PMI_FP64;
88     case 128:
89       return PMI_VEC128;
90     default:
91       llvm_unreachable("Unsupported register size.");
92     }
93   } else {
94     switch (Ty.getSizeInBits()) {
95     case 128:
96       return PMI_VEC128;
97     case 256:
98       return PMI_VEC256;
99     case 512:
100       return PMI_VEC512;
101     default:
102       llvm_unreachable("Unsupported register size.");
103     }
104   }
105 
106   return PMI_None;
107 }
108 
getInstrPartialMappingIdxs(const MachineInstr & MI,const MachineRegisterInfo & MRI,const bool isFP,SmallVectorImpl<PartialMappingIdx> & OpRegBankIdx)109 void X86RegisterBankInfo::getInstrPartialMappingIdxs(
110     const MachineInstr &MI, const MachineRegisterInfo &MRI, const bool isFP,
111     SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx) {
112 
113   unsigned NumOperands = MI.getNumOperands();
114   for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
115     auto &MO = MI.getOperand(Idx);
116     if (!MO.isReg())
117       OpRegBankIdx[Idx] = PMI_None;
118     else
119       OpRegBankIdx[Idx] = getPartialMappingIdx(MRI.getType(MO.getReg()), isFP);
120   }
121 }
122 
getInstrValueMapping(const MachineInstr & MI,const SmallVectorImpl<PartialMappingIdx> & OpRegBankIdx,SmallVectorImpl<const ValueMapping * > & OpdsMapping)123 bool X86RegisterBankInfo::getInstrValueMapping(
124     const MachineInstr &MI,
125     const SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx,
126     SmallVectorImpl<const ValueMapping *> &OpdsMapping) {
127 
128   unsigned NumOperands = MI.getNumOperands();
129   for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
130     if (!MI.getOperand(Idx).isReg())
131       continue;
132 
133     auto Mapping = getValueMapping(OpRegBankIdx[Idx], 1);
134     if (!Mapping->isValid())
135       return false;
136 
137     OpdsMapping[Idx] = Mapping;
138   }
139   return true;
140 }
141 
142 const RegisterBankInfo::InstructionMapping &
getSameOperandsMapping(const MachineInstr & MI,bool isFP) const143 X86RegisterBankInfo::getSameOperandsMapping(const MachineInstr &MI,
144                                             bool isFP) const {
145   const MachineFunction &MF = *MI.getParent()->getParent();
146   const MachineRegisterInfo &MRI = MF.getRegInfo();
147 
148   unsigned NumOperands = MI.getNumOperands();
149   LLT Ty = MRI.getType(MI.getOperand(0).getReg());
150 
151   if (NumOperands != 3 || (Ty != MRI.getType(MI.getOperand(1).getReg())) ||
152       (Ty != MRI.getType(MI.getOperand(2).getReg())))
153     llvm_unreachable("Unsupported operand mapping yet.");
154 
155   auto Mapping = getValueMapping(getPartialMappingIdx(Ty, isFP), 3);
156   return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);
157 }
158 
159 const RegisterBankInfo::InstructionMapping &
getInstrMapping(const MachineInstr & MI) const160 X86RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
161   const MachineFunction &MF = *MI.getParent()->getParent();
162   const MachineRegisterInfo &MRI = MF.getRegInfo();
163   auto Opc = MI.getOpcode();
164 
165   // Try the default logic for non-generic instructions that are either copies
166   // or already have some operands assigned to banks.
167   if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
168     const InstructionMapping &Mapping = getInstrMappingImpl(MI);
169     if (Mapping.isValid())
170       return Mapping;
171   }
172 
173   switch (Opc) {
174   case TargetOpcode::G_ADD:
175   case TargetOpcode::G_SUB:
176   case TargetOpcode::G_MUL:
177   case TargetOpcode::G_SHL:
178   case TargetOpcode::G_LSHR:
179   case TargetOpcode::G_ASHR:
180     return getSameOperandsMapping(MI, false);
181     break;
182   case TargetOpcode::G_FADD:
183   case TargetOpcode::G_FSUB:
184   case TargetOpcode::G_FMUL:
185   case TargetOpcode::G_FDIV:
186     return getSameOperandsMapping(MI, true);
187     break;
188   default:
189     break;
190   }
191 
192   unsigned NumOperands = MI.getNumOperands();
193   SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
194 
195   switch (Opc) {
196   case TargetOpcode::G_FPEXT:
197   case TargetOpcode::G_FPTRUNC:
198   case TargetOpcode::G_FCONSTANT:
199     // Instruction having only floating-point operands (all scalars in VECRReg)
200     getInstrPartialMappingIdxs(MI, MRI, /* isFP */ true, OpRegBankIdx);
201     break;
202   case TargetOpcode::G_SITOFP:
203   case TargetOpcode::G_FPTOSI: {
204     // Some of the floating-point instructions have mixed GPR and FP operands:
205     // fine-tune the computed mapping.
206     auto &Op0 = MI.getOperand(0);
207     auto &Op1 = MI.getOperand(1);
208     const LLT Ty0 = MRI.getType(Op0.getReg());
209     const LLT Ty1 = MRI.getType(Op1.getReg());
210 
211     bool FirstArgIsFP = Opc == TargetOpcode::G_SITOFP;
212     bool SecondArgIsFP = Opc == TargetOpcode::G_FPTOSI;
213     OpRegBankIdx[0] = getPartialMappingIdx(Ty0, /* isFP */ FirstArgIsFP);
214     OpRegBankIdx[1] = getPartialMappingIdx(Ty1, /* isFP */ SecondArgIsFP);
215     break;
216   }
217   case TargetOpcode::G_FCMP: {
218     LLT Ty1 = MRI.getType(MI.getOperand(2).getReg());
219     LLT Ty2 = MRI.getType(MI.getOperand(3).getReg());
220     (void)Ty2;
221     assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() &&
222            "Mismatched operand sizes for G_FCMP");
223 
224     unsigned Size = Ty1.getSizeInBits();
225     (void)Size;
226     assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP");
227 
228     auto FpRegBank = getPartialMappingIdx(Ty1, /* isFP */ true);
229     OpRegBankIdx = {PMI_GPR8,
230                     /* Predicate */ PMI_None, FpRegBank, FpRegBank};
231     break;
232   }
233   case TargetOpcode::G_TRUNC:
234   case TargetOpcode::G_ANYEXT: {
235     auto &Op0 = MI.getOperand(0);
236     auto &Op1 = MI.getOperand(1);
237     const LLT Ty0 = MRI.getType(Op0.getReg());
238     const LLT Ty1 = MRI.getType(Op1.getReg());
239 
240     bool isFPTrunc = (Ty0.getSizeInBits() == 32 || Ty0.getSizeInBits() == 64) &&
241                      Ty1.getSizeInBits() == 128 && Opc == TargetOpcode::G_TRUNC;
242     bool isFPAnyExt =
243         Ty0.getSizeInBits() == 128 &&
244         (Ty1.getSizeInBits() == 32 || Ty1.getSizeInBits() == 64) &&
245         Opc == TargetOpcode::G_ANYEXT;
246 
247     getInstrPartialMappingIdxs(MI, MRI, /* isFP */ isFPTrunc || isFPAnyExt,
248                                OpRegBankIdx);
249   } break;
250   default:
251     // Track the bank of each register, use NotFP mapping (all scalars in GPRs)
252     getInstrPartialMappingIdxs(MI, MRI, /* isFP */ false, OpRegBankIdx);
253     break;
254   }
255 
256   // Finally construct the computed mapping.
257   SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
258   if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))
259     return getInvalidInstructionMapping();
260 
261   return getInstructionMapping(DefaultMappingID, /* Cost */ 1,
262                                getOperandsMapping(OpdsMapping), NumOperands);
263 }
264 
applyMappingImpl(const OperandsMapper & OpdMapper) const265 void X86RegisterBankInfo::applyMappingImpl(
266     const OperandsMapper &OpdMapper) const {
267   return applyDefaultMapping(OpdMapper);
268 }
269 
270 RegisterBankInfo::InstructionMappings
getInstrAlternativeMappings(const MachineInstr & MI) const271 X86RegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const {
272 
273   const MachineFunction &MF = *MI.getParent()->getParent();
274   const TargetSubtargetInfo &STI = MF.getSubtarget();
275   const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
276   const MachineRegisterInfo &MRI = MF.getRegInfo();
277 
278   switch (MI.getOpcode()) {
279   case TargetOpcode::G_LOAD:
280   case TargetOpcode::G_STORE:
281   case TargetOpcode::G_IMPLICIT_DEF: {
282     // we going to try to map 32/64 bit to PMI_FP32/PMI_FP64
283     unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);
284     if (Size != 32 && Size != 64)
285       break;
286 
287     unsigned NumOperands = MI.getNumOperands();
288 
289     // Track the bank of each register, use FP mapping (all scalars in VEC)
290     SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
291     getInstrPartialMappingIdxs(MI, MRI, /* isFP */ true, OpRegBankIdx);
292 
293     // Finally construct the computed mapping.
294     SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
295     if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))
296       break;
297 
298     const RegisterBankInfo::InstructionMapping &Mapping = getInstructionMapping(
299         /*ID*/ 1, /*Cost*/ 1, getOperandsMapping(OpdsMapping), NumOperands);
300     InstructionMappings AltMappings;
301     AltMappings.push_back(&Mapping);
302     return AltMappings;
303   }
304   default:
305     break;
306   }
307   return RegisterBankInfo::getInstrAlternativeMappings(MI);
308 }
309