LLVM 19.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
47const RegisterBank &
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.
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
95bool X86RegisterBankInfo::hasFPConstraints(const MachineInstr &MI,
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?
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() &&
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
133bool X86RegisterBankInfo::onlyUsesFP(const MachineInstr &MI,
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
152bool X86RegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,
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
166X86GenRegisterBankInfo::PartialMappingIdx
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
222void X86RegisterBankInfo::getInstrPartialMappingIdxs(
223 const MachineInstr &MI, const MachineRegisterInfo &MRI, const bool isFP,
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
237bool X86RegisterBankInfo::getInstrValueMapping(
238 const MachineInstr &MI,
239 const SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx,
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
259X86RegisterBankInfo::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
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))
410
411 return getInstructionMapping(DefaultMappingID, /* Cost */ 1,
412 getOperandsMapping(OpdsMapping), NumOperands);
413}
414
416 MachineIRBuilder &Builder, const OperandsMapper &OpdMapper) const {
417 return applyDefaultMapping(OpdMapper);
418}
419
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
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 }
458}
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
static unsigned getIntrinsicID(const SDNode *N)
static bool isFPIntrinsic(const MachineRegisterInfo &MRI, const MachineInstr &MI)
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
uint64_t Size
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
unsigned const TargetRegisterInfo * TRI
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file declares the targeting of the RegisterBankInfo class for X86.
This class represents an Operation in the Expression.
constexpr bool isScalar() const
Definition: LowLevelType.h:146
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
Definition: LowLevelType.h:193
constexpr bool isPointer() const
Definition: LowLevelType.h:149
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.
Definition: MachineInstr.h:69
MachineOperand class - Representation of each machine instruction operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
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...
const InstructionMapping & getInstrMappingImpl(const MachineInstr &MI) const
Try to get the mapping of MI.
This class implements the register bank concept.
Definition: RegisterBank.h:28
bool covers(const TargetRegisterClass &RC) const
Check whether this register bank covers RC.
unsigned getID() const
Get the identifier of this register bank.
Definition: RegisterBank.h:45
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:586
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
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
getRegisterInfo - If register information is available, return it.
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 RegisterBank & getRegBankFromRegClass(const TargetRegisterClass &RC, LLT) const override
Get a register bank that covers RC.
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.
Definition: AddressRanges.h:18
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
Definition: TargetOpcodes.h:30
bool isPreISelGenericOptimizationHint(unsigned Opcode)
Definition: TargetOpcodes.h:42
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:1729
bool isPreISelGenericFloatingPointOpcode(unsigned Opc)
Returns whether opcode Opc is a pre-isel generic floating-point opcode, having only floating-point op...
Definition: Utils.cpp:1684