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
27using namespace llvm;
28// This file will be TableGen'ed at some point.
29#define GET_TARGET_REGBANK_INFO_IMPL
30#include "X86GenRegisterBankInfo.def"
31
32X86RegisterBankInfo::X86RegisterBankInfo(const TargetRegisterInfo &TRI) {
33
34 // validate RegBank initialization.
35 const RegisterBank &RBGPR = getRegBank(ID: 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.
48static bool isFPIntrinsic(const MachineRegisterInfo &MRI,
49 const MachineInstr &MI) {
50 // TODO: Add more intrinsics.
51 switch (cast<GIntrinsic>(Val: 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
68bool 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(Opc: 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(Opcode: Op))
84 return false;
85
86 // Check if we already know the register bank.
87 auto *RB = getRegBank(Reg: MI.getOperand(i: 0).getReg(), MRI, TRI);
88 if (RB == &getRegBank(ID: X86::PSRRegBankID))
89 return true;
90 if (RB == &getRegBank(ID: 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(Range: MI.explicit_uses(), P: [&](const MachineOperand &Op) {
101 return Op.isReg() &&
102 onlyDefinesFP(MI: *MRI.getVRegDef(Reg: Op.getReg()), MRI, TRI, Depth: Depth + 1);
103 });
104}
105
106bool 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 X86::G_FIST:
115 case TargetOpcode::G_LROUND:
116 case TargetOpcode::G_LLROUND:
117 case TargetOpcode::G_INTRINSIC_TRUNC:
118 case TargetOpcode::G_INTRINSIC_ROUND:
119 return true;
120 default:
121 break;
122 }
123 return hasFPConstraints(MI, MRI, TRI, Depth);
124}
125
126bool X86RegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,
127 const MachineRegisterInfo &MRI,
128 const TargetRegisterInfo &TRI,
129 unsigned Depth) const {
130 switch (MI.getOpcode()) {
131 case TargetOpcode::G_SITOFP:
132 case TargetOpcode::G_UITOFP:
133 case X86::G_FILD:
134 return true;
135 default:
136 break;
137 }
138 return hasFPConstraints(MI, MRI, TRI, Depth);
139}
140
141X86GenRegisterBankInfo::PartialMappingIdx
142X86GenRegisterBankInfo::getPartialMappingIdx(const MachineInstr &MI,
143 const LLT &Ty, bool isFP) {
144 const MachineFunction *MF = MI.getMF();
145 const X86Subtarget *ST = &MF->getSubtarget<X86Subtarget>();
146 bool HasSSE1 = ST->hasSSE1();
147 bool HasSSE2 = ST->hasSSE2();
148 // 80 bits is only generated for X87 floating points.
149 if (Ty.getSizeInBits() == 80)
150 isFP = true;
151 if ((Ty.isScalar() && !isFP) || Ty.isPointer()) {
152 switch (Ty.getSizeInBits()) {
153 case 1:
154 case 8:
155 return PMI_GPR8;
156 case 16:
157 return PMI_GPR16;
158 case 32:
159 return PMI_GPR32;
160 case 64:
161 return PMI_GPR64;
162 case 128:
163 return PMI_VEC128;
164 break;
165 default:
166 llvm_unreachable("Unsupported register size.");
167 }
168 } else if (Ty.isScalar()) {
169 switch (Ty.getSizeInBits()) {
170 case 32:
171 return HasSSE1 ? PMI_FP32 : PMI_PSR32;
172 case 64:
173 return HasSSE2 ? PMI_FP64 : PMI_PSR64;
174 case 128:
175 return PMI_VEC128;
176 case 80:
177 return PMI_PSR80;
178 default:
179 llvm_unreachable("Unsupported register size.");
180 }
181 } else {
182 switch (Ty.getSizeInBits()) {
183 case 128:
184 return PMI_VEC128;
185 case 256:
186 return PMI_VEC256;
187 case 512:
188 return PMI_VEC512;
189 default:
190 llvm_unreachable("Unsupported register size.");
191 }
192 }
193
194 return PMI_None;
195}
196
197void X86RegisterBankInfo::getInstrPartialMappingIdxs(
198 const MachineInstr &MI, const MachineRegisterInfo &MRI, const bool isFP,
199 SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx) {
200
201 unsigned NumOperands = MI.getNumOperands();
202 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
203 auto &MO = MI.getOperand(i: Idx);
204 if (!MO.isReg() || !MO.getReg())
205 OpRegBankIdx[Idx] = PMI_None;
206 else
207 OpRegBankIdx[Idx] =
208 getPartialMappingIdx(MI, Ty: MRI.getType(Reg: MO.getReg()), isFP);
209 }
210}
211
212bool X86RegisterBankInfo::getInstrValueMapping(
213 const MachineInstr &MI,
214 const SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx,
215 SmallVectorImpl<const ValueMapping *> &OpdsMapping) {
216
217 unsigned NumOperands = MI.getNumOperands();
218 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
219 if (!MI.getOperand(i: Idx).isReg())
220 continue;
221 if (!MI.getOperand(i: Idx).getReg())
222 continue;
223
224 auto Mapping = getValueMapping(Idx: OpRegBankIdx[Idx], NumOperands: 1);
225 if (!Mapping->isValid())
226 return false;
227
228 OpdsMapping[Idx] = Mapping;
229 }
230 return true;
231}
232
233const RegisterBankInfo::InstructionMapping &
234X86RegisterBankInfo::getSameOperandsMapping(const MachineInstr &MI,
235 bool isFP) const {
236 const MachineFunction &MF = *MI.getParent()->getParent();
237 const MachineRegisterInfo &MRI = MF.getRegInfo();
238
239 unsigned NumOperands = MI.getNumOperands();
240 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 0).getReg());
241
242 if (NumOperands != 3 || (Ty != MRI.getType(Reg: MI.getOperand(i: 1).getReg())) ||
243 (Ty != MRI.getType(Reg: MI.getOperand(i: 2).getReg())))
244 llvm_unreachable("Unsupported operand mapping yet.");
245
246 auto Mapping = getValueMapping(Idx: getPartialMappingIdx(MI, Ty, isFP), NumOperands: 3);
247 return getInstructionMapping(ID: DefaultMappingID, Cost: 1, OperandsMapping: Mapping, NumOperands);
248}
249
250const RegisterBankInfo::InstructionMapping &
251X86RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
252 const MachineFunction &MF = *MI.getParent()->getParent();
253 const TargetSubtargetInfo &STI = MF.getSubtarget();
254 const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
255 const MachineRegisterInfo &MRI = MF.getRegInfo();
256 unsigned Opc = MI.getOpcode();
257
258 // Try the default logic for non-generic instructions that are either
259 // copies or already have some operands assigned to banks.
260 if (!isPreISelGenericOpcode(Opcode: Opc) || Opc == TargetOpcode::G_PHI) {
261 const InstructionMapping &Mapping = getInstrMappingImpl(MI);
262 if (Mapping.isValid())
263 return Mapping;
264 }
265
266 switch (Opc) {
267 case TargetOpcode::G_ADD:
268 case TargetOpcode::G_SUB:
269 case TargetOpcode::G_MUL:
270 return getSameOperandsMapping(MI, isFP: false);
271 case TargetOpcode::G_FADD:
272 case TargetOpcode::G_FSUB:
273 case TargetOpcode::G_FMUL:
274 case TargetOpcode::G_FDIV:
275 return getSameOperandsMapping(MI, isFP: true);
276 case TargetOpcode::G_SHL:
277 case TargetOpcode::G_LSHR:
278 case TargetOpcode::G_ASHR: {
279 unsigned NumOperands = MI.getNumOperands();
280 LLT Ty = MRI.getType(Reg: MI.getOperand(i: 0).getReg());
281
282 auto Mapping = getValueMapping(Idx: getPartialMappingIdx(MI, Ty, isFP: false), NumOperands: 3);
283 return getInstructionMapping(ID: DefaultMappingID, Cost: 1, OperandsMapping: Mapping, NumOperands);
284 }
285 default:
286 break;
287 }
288
289 unsigned NumOperands = MI.getNumOperands();
290 SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
291
292 switch (Opc) {
293 case TargetOpcode::G_FSQRT:
294 case TargetOpcode::G_FPEXT:
295 case TargetOpcode::G_FPTRUNC:
296 case TargetOpcode::G_FCONSTANT:
297 // Instruction having only floating-point operands (all scalars in
298 // VECRReg)
299 getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx);
300 break;
301 case X86::G_FIST:
302 case X86::G_FILD: {
303 auto &Op0 = MI.getOperand(i: 0);
304 auto &Op1 = MI.getOperand(i: 1);
305 const LLT Ty0 = MRI.getType(Reg: Op0.getReg());
306 const LLT Ty1 = MRI.getType(Reg: Op1.getReg());
307 OpRegBankIdx[0] = getPartialMappingIdx(MI, Ty: Ty0, /* isFP= */ true);
308 OpRegBankIdx[1] = getPartialMappingIdx(MI, Ty: Ty1, /* isFP= */ false);
309 break;
310 }
311 case TargetOpcode::G_SITOFP:
312 case TargetOpcode::G_FPTOSI:
313 case TargetOpcode::G_UITOFP:
314 case TargetOpcode::G_FPTOUI: {
315 // Some of the floating-point instructions have mixed GPR and FP
316 // operands: fine-tune the computed mapping.
317 auto &Op0 = MI.getOperand(i: 0);
318 auto &Op1 = MI.getOperand(i: 1);
319 const LLT Ty0 = MRI.getType(Reg: Op0.getReg());
320 const LLT Ty1 = MRI.getType(Reg: Op1.getReg());
321
322 bool FirstArgIsFP =
323 Opc == TargetOpcode::G_SITOFP || Opc == TargetOpcode::G_UITOFP;
324 OpRegBankIdx[0] = getPartialMappingIdx(MI, Ty: Ty0, /* isFP= */ FirstArgIsFP);
325 OpRegBankIdx[1] = getPartialMappingIdx(MI, Ty: Ty1, /* isFP= */ !FirstArgIsFP);
326 break;
327 }
328 case TargetOpcode::G_FCMP: {
329 LLT Ty1 = MRI.getType(Reg: MI.getOperand(i: 2).getReg());
330 LLT Ty2 = MRI.getType(Reg: MI.getOperand(i: 3).getReg());
331 (void)Ty2;
332 assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() &&
333 "Mismatched operand sizes for G_FCMP");
334
335 unsigned Size = Ty1.getSizeInBits();
336 (void)Size;
337 assert((Size == 32 || Size == 64 || Size == 80) &&
338 "Unsupported size for G_FCMP");
339 auto FpRegBank = getPartialMappingIdx(MI, Ty: Ty1, /* isFP= */ true);
340 OpRegBankIdx = {PMI_GPR8,
341 /* Predicate */ PMI_None, FpRegBank, FpRegBank};
342 break;
343 }
344 case TargetOpcode::G_FABS:
345 case TargetOpcode::G_TRUNC:
346 case TargetOpcode::G_ANYEXT: {
347 auto &Op0 = MI.getOperand(i: 0);
348 auto &Op1 = MI.getOperand(i: 1);
349 const LLT Ty0 = MRI.getType(Reg: Op0.getReg());
350 const LLT Ty1 = MRI.getType(Reg: Op1.getReg());
351
352 bool isFPTrunc = (Ty0.getSizeInBits() == 32 || Ty0.getSizeInBits() == 64) &&
353 Ty1.getSizeInBits() == 128 && Opc == TargetOpcode::G_TRUNC;
354 bool isFPAnyExt =
355 Ty0.getSizeInBits() == 128 &&
356 (Ty1.getSizeInBits() == 32 || Ty1.getSizeInBits() == 64) &&
357 Opc == TargetOpcode::G_ANYEXT;
358 bool isFAbs = (Opc == TargetOpcode::G_FABS);
359 getInstrPartialMappingIdxs(
360 MI, MRI, /* isFP= */ isFPTrunc || isFPAnyExt || isFAbs, OpRegBankIdx);
361 break;
362 }
363 case TargetOpcode::G_LOAD: {
364 // Check if that load feeds fp instructions.
365 // In that case, we want the default mapping to be on FPR
366 // instead of blind map every scalar to GPR.
367 bool IsFP = any_of(Range: MRI.use_nodbg_instructions(Reg: cast<GLoad>(Val: MI).getDstReg()),
368 P: [&](const MachineInstr &UseMI) {
369 // If we have at least one direct use in a FP
370 // instruction, assume this was a floating point load
371 // in the IR. If it was not, we would have had a
372 // bitcast before reaching that instruction.
373 return onlyUsesFP(MI: UseMI, MRI, TRI);
374 });
375 getInstrPartialMappingIdxs(MI, MRI, isFP: IsFP, OpRegBankIdx);
376 break;
377 }
378 case TargetOpcode::G_STORE: {
379 // Check if that store is fed by fp instructions.
380 Register VReg = cast<GStore>(Val: MI).getValueReg();
381 if (!VReg)
382 break;
383 MachineInstr *DefMI = MRI.getVRegDef(Reg: VReg);
384 bool IsFP = onlyDefinesFP(MI: *DefMI, MRI, TRI);
385 getInstrPartialMappingIdxs(MI, MRI, isFP: IsFP, OpRegBankIdx);
386 break;
387 }
388 default:
389 // Track the bank of each register, use NotFP mapping (all scalars in
390 // GPRs)
391 getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ false, OpRegBankIdx);
392 break;
393 }
394
395 // Finally construct the computed mapping.
396 SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
397 if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))
398 return getInvalidInstructionMapping();
399
400 return getInstructionMapping(ID: DefaultMappingID, /* Cost */ 1,
401 OperandsMapping: getOperandsMapping(OpdsMapping), NumOperands);
402}
403
404void X86RegisterBankInfo::applyMappingImpl(
405 MachineIRBuilder &Builder, const OperandsMapper &OpdMapper) const {
406 return applyDefaultMapping(OpdMapper);
407}
408
409RegisterBankInfo::InstructionMappings
410X86RegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const {
411
412 const MachineFunction &MF = *MI.getParent()->getParent();
413 const TargetSubtargetInfo &STI = MF.getSubtarget();
414 const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
415 const MachineRegisterInfo &MRI = MF.getRegInfo();
416
417 switch (MI.getOpcode()) {
418 case TargetOpcode::G_LOAD:
419 case TargetOpcode::G_STORE:
420 case TargetOpcode::G_IMPLICIT_DEF: {
421 // we going to try to map 32/64/80 bit to PMI_FP32/PMI_FP64/PMI_FP80
422 unsigned Size = getSizeInBits(Reg: MI.getOperand(i: 0).getReg(), MRI, TRI);
423 if (Size != 32 && Size != 64 && Size != 80)
424 break;
425
426 unsigned NumOperands = MI.getNumOperands();
427
428 // Track the bank of each register, use FP mapping (all scalars in VEC)
429 SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
430 getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx);
431
432 // Finally construct the computed mapping.
433 SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
434 if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))
435 break;
436
437 const RegisterBankInfo::InstructionMapping &Mapping = getInstructionMapping(
438 /*ID*/ 1, /*Cost*/ 1, OperandsMapping: getOperandsMapping(OpdsMapping), NumOperands);
439 InstructionMappings AltMappings;
440 AltMappings.push_back(Elt: &Mapping);
441 return AltMappings;
442 }
443 default:
444 break;
445 }
446 return RegisterBankInfo::getInstrAlternativeMappings(MI);
447}
448