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