LLVM 23.0.0git
X86RegisterBankInfo.cpp
Go to the documentation of this file.
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"
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
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.
48static bool isFPIntrinsic(const MachineRegisterInfo &MRI,
49 const MachineInstr &MI) {
50 // TODO: Add more intrinsics.
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,
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?
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() &&
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
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
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,
200
201 unsigned NumOperands = MI.getNumOperands();
202 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
203 auto &MO = MI.getOperand(Idx);
204 if (!MO.isReg() || !MO.getReg().isVirtual())
205 OpRegBankIdx[Idx] = PMI_None;
206 else
207 OpRegBankIdx[Idx] =
208 getPartialMappingIdx(MI, MRI.getType(MO.getReg()), isFP);
209 }
210}
211
212bool X86RegisterBankInfo::getInstrValueMapping(
213 const MachineInstr &MI,
214 const SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx,
216
217 unsigned NumOperands = MI.getNumOperands();
218 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
219 if (!MI.getOperand(Idx).isReg())
220 continue;
221 if (!MI.getOperand(Idx).getReg().isVirtual())
222 continue;
223
224 auto Mapping = getValueMapping(OpRegBankIdx[Idx], 1);
225 if (!Mapping->isValid())
226 return false;
227
228 OpdsMapping[Idx] = Mapping;
229 }
230 return true;
231}
232
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(MI.getOperand(0).getReg());
241
242 if (NumOperands != 3 || (Ty != MRI.getType(MI.getOperand(1).getReg())) ||
243 (Ty != MRI.getType(MI.getOperand(2).getReg())))
244 llvm_unreachable("Unsupported operand mapping yet.");
245
246 auto Mapping = getValueMapping(getPartialMappingIdx(MI, Ty, isFP), 3);
247 return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);
248}
249
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(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, 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, 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(MI.getOperand(0).getReg());
281
282 auto Mapping = getValueMapping(getPartialMappingIdx(MI, Ty, false), 3);
283 return getInstructionMapping(DefaultMappingID, 1, 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 case TargetOpcode::G_FPEXTLOAD:
298 case TargetOpcode::G_FPTRUNCSTORE:
299 // Instruction having only floating-point operands (all scalars in
300 // VECRReg)
301 getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx);
302 break;
303 case X86::G_FIST:
304 case X86::G_FILD: {
305 auto &Op0 = MI.getOperand(0);
306 auto &Op1 = MI.getOperand(1);
307 const LLT Ty0 = MRI.getType(Op0.getReg());
308 const LLT Ty1 = MRI.getType(Op1.getReg());
309 OpRegBankIdx[0] = getPartialMappingIdx(MI, Ty0, /* isFP= */ true);
310 OpRegBankIdx[1] = getPartialMappingIdx(MI, Ty1, /* isFP= */ false);
311 break;
312 }
313 case TargetOpcode::G_SITOFP:
314 case TargetOpcode::G_FPTOSI:
315 case TargetOpcode::G_UITOFP:
316 case TargetOpcode::G_FPTOUI: {
317 // Some of the floating-point instructions have mixed GPR and FP
318 // operands: fine-tune the computed mapping.
319 auto &Op0 = MI.getOperand(0);
320 auto &Op1 = MI.getOperand(1);
321 const LLT Ty0 = MRI.getType(Op0.getReg());
322 const LLT Ty1 = MRI.getType(Op1.getReg());
323
324 bool FirstArgIsFP =
325 Opc == TargetOpcode::G_SITOFP || Opc == TargetOpcode::G_UITOFP;
326 OpRegBankIdx[0] = getPartialMappingIdx(MI, Ty0, /* isFP= */ FirstArgIsFP);
327 OpRegBankIdx[1] = getPartialMappingIdx(MI, Ty1, /* isFP= */ !FirstArgIsFP);
328 break;
329 }
330 case TargetOpcode::G_FCMP: {
331 LLT Ty1 = MRI.getType(MI.getOperand(2).getReg());
332 LLT Ty2 = MRI.getType(MI.getOperand(3).getReg());
333 (void)Ty2;
334 assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() &&
335 "Mismatched operand sizes for G_FCMP");
336
337 unsigned Size = Ty1.getSizeInBits();
338 (void)Size;
339 assert((Size == 32 || Size == 64 || Size == 80) &&
340 "Unsupported size for G_FCMP");
341 auto FpRegBank = getPartialMappingIdx(MI, Ty1, /* isFP= */ true);
342 OpRegBankIdx = {PMI_GPR8,
343 /* Predicate */ PMI_None, FpRegBank, FpRegBank};
344 break;
345 }
346 case TargetOpcode::G_FABS:
347 case TargetOpcode::G_TRUNC:
348 case TargetOpcode::G_ANYEXT: {
349 auto &Op0 = MI.getOperand(0);
350 auto &Op1 = MI.getOperand(1);
351 const LLT Ty0 = MRI.getType(Op0.getReg());
352 const LLT Ty1 = MRI.getType(Op1.getReg());
353
354 bool isFPTrunc = (Ty0.getSizeInBits() == 32 || Ty0.getSizeInBits() == 64) &&
355 Ty1.getSizeInBits() == 128 && Opc == TargetOpcode::G_TRUNC;
356 bool isFPAnyExt =
357 Ty0.getSizeInBits() == 128 &&
358 (Ty1.getSizeInBits() == 32 || Ty1.getSizeInBits() == 64) &&
359 Opc == TargetOpcode::G_ANYEXT;
360 bool isFAbs = (Opc == TargetOpcode::G_FABS);
361 getInstrPartialMappingIdxs(
362 MI, MRI, /* isFP= */ isFPTrunc || isFPAnyExt || isFAbs, OpRegBankIdx);
363 break;
364 }
365 case TargetOpcode::G_LOAD: {
366 // Check if that load feeds fp instructions.
367 // In that case, we want the default mapping to be on FPR
368 // instead of blind map every scalar to GPR.
369 bool IsFP = any_of(MRI.use_nodbg_instructions(cast<GLoad>(MI).getDstReg()),
370 [&](const MachineInstr &UseMI) {
371 // If we have at least one direct use in a FP
372 // instruction, assume this was a floating point load
373 // in the IR. If it was not, we would have had a
374 // bitcast before reaching that instruction.
375 return onlyUsesFP(UseMI, MRI, TRI);
376 });
377 getInstrPartialMappingIdxs(MI, MRI, IsFP, OpRegBankIdx);
378 break;
379 }
380 case TargetOpcode::G_STORE: {
381 // Check if that store is fed by fp instructions.
382 Register VReg = cast<GStore>(MI).getValueReg();
383 if (!VReg)
384 break;
385 MachineInstr *DefMI = MRI.getVRegDef(VReg);
386 bool IsFP = onlyDefinesFP(*DefMI, MRI, TRI);
387 getInstrPartialMappingIdxs(MI, MRI, IsFP, OpRegBankIdx);
388 break;
389 }
390 default:
391 // Track the bank of each register, use NotFP mapping (all scalars in
392 // GPRs)
393 getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ false, OpRegBankIdx);
394 break;
395 }
396
397 // Finally construct the computed mapping.
398 SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
399 if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))
401
402 return getInstructionMapping(DefaultMappingID, /* Cost */ 1,
403 getOperandsMapping(OpdsMapping), NumOperands);
404}
405
407 MachineIRBuilder &Builder, const OperandsMapper &OpdMapper) const {
408 return applyDefaultMapping(OpdMapper);
409}
410
413
414 const MachineFunction &MF = *MI.getParent()->getParent();
415 const TargetSubtargetInfo &STI = MF.getSubtarget();
416 const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
417 const MachineRegisterInfo &MRI = MF.getRegInfo();
418
419 switch (MI.getOpcode()) {
420 case TargetOpcode::G_LOAD:
421 case TargetOpcode::G_STORE:
422 case TargetOpcode::G_IMPLICIT_DEF: {
423 // we going to try to map 32/64/80 bit to PMI_FP32/PMI_FP64/PMI_FP80
424 unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);
425 if (Size != 32 && Size != 64 && Size != 80)
426 break;
427
428 unsigned NumOperands = MI.getNumOperands();
429
430 // Track the bank of each register, use FP mapping (all scalars in VEC)
431 SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
432 getInstrPartialMappingIdxs(MI, MRI, /* isFP= */ true, OpRegBankIdx);
433
434 // Finally construct the computed mapping.
435 SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
436 if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))
437 break;
438
440 /*ID*/ 1, /*Cost*/ 1, getOperandsMapping(OpdsMapping), NumOperands);
441 InstructionMappings AltMappings;
442 AltMappings.push_back(&Mapping);
443 return AltMappings;
444 }
445 default:
446 break;
447 }
449}
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
static unsigned getIntrinsicID(const SDNode *N)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static bool isFPIntrinsic(const MachineRegisterInfo &MRI, const MachineInstr &MI)
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
Register const TargetRegisterInfo * TRI
This file declares the targeting of the RegisterBankInfo class for X86.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Helper class to build MachineInstr.
Representation of each machine instruction.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
Helper class that represents how the value of an instruction may be mapped and what is the related co...
bool isValid() const
Check whether this object is valid.
Helper class used to get/create the virtual registers that will be used to replace the MachineOperand...
virtual InstructionMappings getInstrAlternativeMappings(const MachineInstr &MI) const
Get the alternative mappings for MI.
const InstructionMapping & getInstructionMapping(unsigned ID, unsigned Cost, const ValueMapping *OperandsMapping, unsigned NumOperands) const
Method to get a uniquely generated InstructionMapping.
static void applyDefaultMapping(const OperandsMapper &OpdMapper)
Helper method to apply something that is like the default mapping.
const InstructionMapping & getInvalidInstructionMapping() const
Method to get a uniquely generated invalid InstructionMapping.
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
unsigned getMaximumSize(unsigned RegBankID) const
Get the maximum size in bits that fits in the given register bank.
TypeSize getSizeInBits(Register Reg, const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI) const
Get the size in bits of Reg.
const ValueMapping * getOperandsMapping(Iterator Begin, Iterator End) const
Get the uniquely generated array of ValueMapping for the elements of between Begin and End.
static const unsigned DefaultMappingID
Identifier used when the related instruction mapping instance is generated by target independent code...
SmallVector< const InstructionMapping *, 4 > InstructionMappings
Convenient type to represent the alternatives for mapping an instruction.
const InstructionMapping & getInstrMappingImpl(const MachineInstr &MI) const
Try to get the mapping of MI.
This class implements the register bank concept.
LLVM_ABI bool covers(const TargetRegisterClass &RC) const
Check whether this register bank covers RC.
unsigned getID() const
Get the identifier of this register bank.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
TargetSubtargetInfo - Generic base class for all target subtargets.
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
static PartialMappingIdx getPartialMappingIdx(const MachineInstr &MI, const LLT &Ty, bool isFP)
static const RegisterBankInfo::ValueMapping * getValueMapping(PartialMappingIdx Idx, unsigned NumOperands)
X86RegisterBankInfo(const TargetRegisterInfo &TRI)
InstructionMappings getInstrAlternativeMappings(const MachineInstr &MI) const override
Get the alternative mappings for MI.
const InstructionMapping & getInstrMapping(const MachineInstr &MI) const override
Get the mapping of the different operands of MI on the register bank.
void applyMappingImpl(MachineIRBuilder &Builder, const OperandsMapper &OpdMapper) const override
See RegisterBankInfo::applyMapping.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
bool isPreISelGenericOptimizationHint(unsigned Opcode)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1745
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI bool isPreISelGenericFloatingPointOpcode(unsigned Opc)
Returns whether opcode Opc is a pre-isel generic floating-point opcode, having only floating-point op...
Definition Utils.cpp:1701