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