1317017Sdim//===- X86RegisterBankInfo.cpp -----------------------------------*- C++ -*-==//
2317017Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6317017Sdim//
7317017Sdim//===----------------------------------------------------------------------===//
8317017Sdim/// \file
9317017Sdim/// This file implements the targeting of the RegisterBankInfo class for X86.
10317017Sdim/// \todo This should be generated by TableGen.
11317017Sdim//===----------------------------------------------------------------------===//
12317017Sdim
13317017Sdim#include "X86RegisterBankInfo.h"
14317017Sdim#include "X86InstrInfo.h"
15317017Sdim#include "llvm/CodeGen/GlobalISel/RegisterBank.h"
16317017Sdim#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
17317017Sdim#include "llvm/CodeGen/MachineRegisterInfo.h"
18327952Sdim#include "llvm/CodeGen/TargetRegisterInfo.h"
19317017Sdim
20317017Sdim#define GET_TARGET_REGBANK_IMPL
21317017Sdim#include "X86GenRegisterBank.inc"
22317017Sdim
23317017Sdimusing namespace llvm;
24317017Sdim// This file will be TableGen'ed at some point.
25317017Sdim#define GET_TARGET_REGBANK_INFO_IMPL
26317017Sdim#include "X86GenRegisterBankInfo.def"
27317017Sdim
28317017SdimX86RegisterBankInfo::X86RegisterBankInfo(const TargetRegisterInfo &TRI)
29317017Sdim    : X86GenRegisterBankInfo() {
30317017Sdim
31317017Sdim  // validate RegBank initialization.
32317017Sdim  const RegisterBank &RBGPR = getRegBank(X86::GPRRegBankID);
33317017Sdim  (void)RBGPR;
34317017Sdim  assert(&X86::GPRRegBank == &RBGPR && "Incorrect RegBanks inizalization.");
35317017Sdim
36317017Sdim  // The GPR register bank is fully defined by all the registers in
37317017Sdim  // GR64 + its subclasses.
38317017Sdim  assert(RBGPR.covers(*TRI.getRegClass(X86::GR64RegClassID)) &&
39317017Sdim         "Subclass not added?");
40317017Sdim  assert(RBGPR.getSize() == 64 && "GPRs should hold up to 64-bit");
41317017Sdim}
42317017Sdim
43360784Sdimconst RegisterBank &
44360784SdimX86RegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC,
45360784Sdim                                            LLT) const {
46317017Sdim
47317017Sdim  if (X86::GR8RegClass.hasSubClassEq(&RC) ||
48317017Sdim      X86::GR16RegClass.hasSubClassEq(&RC) ||
49317017Sdim      X86::GR32RegClass.hasSubClassEq(&RC) ||
50360784Sdim      X86::GR64RegClass.hasSubClassEq(&RC) ||
51360784Sdim      X86::LOW32_ADDR_ACCESSRegClass.hasSubClassEq(&RC) ||
52360784Sdim      X86::LOW32_ADDR_ACCESS_RBPRegClass.hasSubClassEq(&RC))
53317017Sdim    return getRegBank(X86::GPRRegBankID);
54317017Sdim
55317017Sdim  if (X86::FR32XRegClass.hasSubClassEq(&RC) ||
56317017Sdim      X86::FR64XRegClass.hasSubClassEq(&RC) ||
57317017Sdim      X86::VR128XRegClass.hasSubClassEq(&RC) ||
58317017Sdim      X86::VR256XRegClass.hasSubClassEq(&RC) ||
59317017Sdim      X86::VR512RegClass.hasSubClassEq(&RC))
60317017Sdim    return getRegBank(X86::VECRRegBankID);
61317017Sdim
62317017Sdim  llvm_unreachable("Unsupported register kind yet.");
63317017Sdim}
64317017Sdim
65317017SdimX86GenRegisterBankInfo::PartialMappingIdx
66317017SdimX86GenRegisterBankInfo::getPartialMappingIdx(const LLT &Ty, bool isFP) {
67317017Sdim  if ((Ty.isScalar() && !isFP) || Ty.isPointer()) {
68317017Sdim    switch (Ty.getSizeInBits()) {
69317230Sdim    case 1:
70317017Sdim    case 8:
71317017Sdim      return PMI_GPR8;
72317017Sdim    case 16:
73317017Sdim      return PMI_GPR16;
74317017Sdim    case 32:
75317017Sdim      return PMI_GPR32;
76317017Sdim    case 64:
77317017Sdim      return PMI_GPR64;
78341825Sdim    case 128:
79341825Sdim      return PMI_VEC128;
80317017Sdim      break;
81317017Sdim    default:
82317017Sdim      llvm_unreachable("Unsupported register size.");
83317017Sdim    }
84317017Sdim  } else if (Ty.isScalar()) {
85317017Sdim    switch (Ty.getSizeInBits()) {
86317017Sdim    case 32:
87317017Sdim      return PMI_FP32;
88317017Sdim    case 64:
89317017Sdim      return PMI_FP64;
90341825Sdim    case 128:
91341825Sdim      return PMI_VEC128;
92317017Sdim    default:
93317017Sdim      llvm_unreachable("Unsupported register size.");
94317017Sdim    }
95317017Sdim  } else {
96317017Sdim    switch (Ty.getSizeInBits()) {
97317017Sdim    case 128:
98317017Sdim      return PMI_VEC128;
99317017Sdim    case 256:
100317017Sdim      return PMI_VEC256;
101317017Sdim    case 512:
102317017Sdim      return PMI_VEC512;
103317017Sdim    default:
104317017Sdim      llvm_unreachable("Unsupported register size.");
105317017Sdim    }
106317017Sdim  }
107317017Sdim
108317017Sdim  return PMI_None;
109317017Sdim}
110317017Sdim
111317017Sdimvoid X86RegisterBankInfo::getInstrPartialMappingIdxs(
112317017Sdim    const MachineInstr &MI, const MachineRegisterInfo &MRI, const bool isFP,
113317017Sdim    SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx) {
114317017Sdim
115317017Sdim  unsigned NumOperands = MI.getNumOperands();
116317017Sdim  for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
117317017Sdim    auto &MO = MI.getOperand(Idx);
118317017Sdim    if (!MO.isReg())
119317017Sdim      OpRegBankIdx[Idx] = PMI_None;
120317017Sdim    else
121317017Sdim      OpRegBankIdx[Idx] = getPartialMappingIdx(MRI.getType(MO.getReg()), isFP);
122317017Sdim  }
123317017Sdim}
124317017Sdim
125317017Sdimbool X86RegisterBankInfo::getInstrValueMapping(
126317017Sdim    const MachineInstr &MI,
127317017Sdim    const SmallVectorImpl<PartialMappingIdx> &OpRegBankIdx,
128317017Sdim    SmallVectorImpl<const ValueMapping *> &OpdsMapping) {
129317017Sdim
130317017Sdim  unsigned NumOperands = MI.getNumOperands();
131317017Sdim  for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
132317017Sdim    if (!MI.getOperand(Idx).isReg())
133317017Sdim      continue;
134317017Sdim
135317017Sdim    auto Mapping = getValueMapping(OpRegBankIdx[Idx], 1);
136317017Sdim    if (!Mapping->isValid())
137317017Sdim      return false;
138317017Sdim
139317017Sdim    OpdsMapping[Idx] = Mapping;
140317017Sdim  }
141317017Sdim  return true;
142317017Sdim}
143317017Sdim
144317969Sdimconst RegisterBankInfo::InstructionMapping &
145317969SdimX86RegisterBankInfo::getSameOperandsMapping(const MachineInstr &MI,
146317969Sdim                                            bool isFP) const {
147317017Sdim  const MachineFunction &MF = *MI.getParent()->getParent();
148317017Sdim  const MachineRegisterInfo &MRI = MF.getRegInfo();
149317017Sdim
150317017Sdim  unsigned NumOperands = MI.getNumOperands();
151317017Sdim  LLT Ty = MRI.getType(MI.getOperand(0).getReg());
152317017Sdim
153317017Sdim  if (NumOperands != 3 || (Ty != MRI.getType(MI.getOperand(1).getReg())) ||
154317017Sdim      (Ty != MRI.getType(MI.getOperand(2).getReg())))
155317017Sdim    llvm_unreachable("Unsupported operand mapping yet.");
156317017Sdim
157317017Sdim  auto Mapping = getValueMapping(getPartialMappingIdx(Ty, isFP), 3);
158317969Sdim  return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);
159317017Sdim}
160317017Sdim
161317969Sdimconst RegisterBankInfo::InstructionMapping &
162317017SdimX86RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
163317017Sdim  const MachineFunction &MF = *MI.getParent()->getParent();
164317017Sdim  const MachineRegisterInfo &MRI = MF.getRegInfo();
165353358Sdim  unsigned Opc = MI.getOpcode();
166317017Sdim
167317017Sdim  // Try the default logic for non-generic instructions that are either copies
168317017Sdim  // or already have some operands assigned to banks.
169327952Sdim  if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
170317969Sdim    const InstructionMapping &Mapping = getInstrMappingImpl(MI);
171317017Sdim    if (Mapping.isValid())
172317017Sdim      return Mapping;
173317017Sdim  }
174317017Sdim
175317017Sdim  switch (Opc) {
176317017Sdim  case TargetOpcode::G_ADD:
177317017Sdim  case TargetOpcode::G_SUB:
178341825Sdim  case TargetOpcode::G_MUL:
179317017Sdim    return getSameOperandsMapping(MI, false);
180317017Sdim  case TargetOpcode::G_FADD:
181317017Sdim  case TargetOpcode::G_FSUB:
182317017Sdim  case TargetOpcode::G_FMUL:
183317017Sdim  case TargetOpcode::G_FDIV:
184317017Sdim    return getSameOperandsMapping(MI, true);
185353358Sdim  case TargetOpcode::G_SHL:
186353358Sdim  case TargetOpcode::G_LSHR:
187353358Sdim  case TargetOpcode::G_ASHR: {
188353358Sdim    unsigned NumOperands = MI.getNumOperands();
189353358Sdim    LLT Ty = MRI.getType(MI.getOperand(0).getReg());
190353358Sdim
191353358Sdim    auto Mapping = getValueMapping(getPartialMappingIdx(Ty, false), 3);
192353358Sdim    return getInstructionMapping(DefaultMappingID, 1, Mapping, NumOperands);
193353358Sdim
194353358Sdim  }
195317017Sdim  default:
196317017Sdim    break;
197317017Sdim  }
198317017Sdim
199317017Sdim  unsigned NumOperands = MI.getNumOperands();
200317017Sdim  SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
201317017Sdim
202327952Sdim  switch (Opc) {
203327952Sdim  case TargetOpcode::G_FPEXT:
204344779Sdim  case TargetOpcode::G_FPTRUNC:
205327952Sdim  case TargetOpcode::G_FCONSTANT:
206327952Sdim    // Instruction having only floating-point operands (all scalars in VECRReg)
207327952Sdim    getInstrPartialMappingIdxs(MI, MRI, /* isFP */ true, OpRegBankIdx);
208327952Sdim    break;
209344779Sdim  case TargetOpcode::G_SITOFP:
210344779Sdim  case TargetOpcode::G_FPTOSI: {
211341825Sdim    // Some of the floating-point instructions have mixed GPR and FP operands:
212341825Sdim    // fine-tune the computed mapping.
213341825Sdim    auto &Op0 = MI.getOperand(0);
214341825Sdim    auto &Op1 = MI.getOperand(1);
215341825Sdim    const LLT Ty0 = MRI.getType(Op0.getReg());
216341825Sdim    const LLT Ty1 = MRI.getType(Op1.getReg());
217344779Sdim
218344779Sdim    bool FirstArgIsFP = Opc == TargetOpcode::G_SITOFP;
219344779Sdim    bool SecondArgIsFP = Opc == TargetOpcode::G_FPTOSI;
220344779Sdim    OpRegBankIdx[0] = getPartialMappingIdx(Ty0, /* isFP */ FirstArgIsFP);
221344779Sdim    OpRegBankIdx[1] = getPartialMappingIdx(Ty1, /* isFP */ SecondArgIsFP);
222341825Sdim    break;
223341825Sdim  }
224344779Sdim  case TargetOpcode::G_FCMP: {
225344779Sdim    LLT Ty1 = MRI.getType(MI.getOperand(2).getReg());
226344779Sdim    LLT Ty2 = MRI.getType(MI.getOperand(3).getReg());
227344779Sdim    (void)Ty2;
228344779Sdim    assert(Ty1.getSizeInBits() == Ty2.getSizeInBits() &&
229344779Sdim           "Mismatched operand sizes for G_FCMP");
230344779Sdim
231344779Sdim    unsigned Size = Ty1.getSizeInBits();
232344779Sdim    (void)Size;
233344779Sdim    assert((Size == 32 || Size == 64) && "Unsupported size for G_FCMP");
234344779Sdim
235344779Sdim    auto FpRegBank = getPartialMappingIdx(Ty1, /* isFP */ true);
236344779Sdim    OpRegBankIdx = {PMI_GPR8,
237344779Sdim                    /* Predicate */ PMI_None, FpRegBank, FpRegBank};
238344779Sdim    break;
239344779Sdim  }
240341825Sdim  case TargetOpcode::G_TRUNC:
241341825Sdim  case TargetOpcode::G_ANYEXT: {
242341825Sdim    auto &Op0 = MI.getOperand(0);
243341825Sdim    auto &Op1 = MI.getOperand(1);
244341825Sdim    const LLT Ty0 = MRI.getType(Op0.getReg());
245341825Sdim    const LLT Ty1 = MRI.getType(Op1.getReg());
246341825Sdim
247341825Sdim    bool isFPTrunc = (Ty0.getSizeInBits() == 32 || Ty0.getSizeInBits() == 64) &&
248341825Sdim                     Ty1.getSizeInBits() == 128 && Opc == TargetOpcode::G_TRUNC;
249341825Sdim    bool isFPAnyExt =
250341825Sdim        Ty0.getSizeInBits() == 128 &&
251341825Sdim        (Ty1.getSizeInBits() == 32 || Ty1.getSizeInBits() == 64) &&
252341825Sdim        Opc == TargetOpcode::G_ANYEXT;
253341825Sdim
254341825Sdim    getInstrPartialMappingIdxs(MI, MRI, /* isFP */ isFPTrunc || isFPAnyExt,
255341825Sdim                               OpRegBankIdx);
256341825Sdim  } break;
257327952Sdim  default:
258327952Sdim    // Track the bank of each register, use NotFP mapping (all scalars in GPRs)
259327952Sdim    getInstrPartialMappingIdxs(MI, MRI, /* isFP */ false, OpRegBankIdx);
260327952Sdim    break;
261327952Sdim  }
262327952Sdim
263317017Sdim  // Finally construct the computed mapping.
264317017Sdim  SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
265317017Sdim  if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))
266317969Sdim    return getInvalidInstructionMapping();
267317017Sdim
268317969Sdim  return getInstructionMapping(DefaultMappingID, /* Cost */ 1,
269317969Sdim                               getOperandsMapping(OpdsMapping), NumOperands);
270317017Sdim}
271317017Sdim
272317017Sdimvoid X86RegisterBankInfo::applyMappingImpl(
273317017Sdim    const OperandsMapper &OpdMapper) const {
274317017Sdim  return applyDefaultMapping(OpdMapper);
275317017Sdim}
276317017Sdim
277317017SdimRegisterBankInfo::InstructionMappings
278317017SdimX86RegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const {
279317017Sdim
280317017Sdim  const MachineFunction &MF = *MI.getParent()->getParent();
281317017Sdim  const TargetSubtargetInfo &STI = MF.getSubtarget();
282317017Sdim  const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
283317017Sdim  const MachineRegisterInfo &MRI = MF.getRegInfo();
284317017Sdim
285317017Sdim  switch (MI.getOpcode()) {
286317017Sdim  case TargetOpcode::G_LOAD:
287327952Sdim  case TargetOpcode::G_STORE:
288327952Sdim  case TargetOpcode::G_IMPLICIT_DEF: {
289317017Sdim    // we going to try to map 32/64 bit to PMI_FP32/PMI_FP64
290317017Sdim    unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);
291317017Sdim    if (Size != 32 && Size != 64)
292317017Sdim      break;
293317017Sdim
294317017Sdim    unsigned NumOperands = MI.getNumOperands();
295317017Sdim
296317017Sdim    // Track the bank of each register, use FP mapping (all scalars in VEC)
297317017Sdim    SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
298317017Sdim    getInstrPartialMappingIdxs(MI, MRI, /* isFP */ true, OpRegBankIdx);
299317017Sdim
300317017Sdim    // Finally construct the computed mapping.
301317017Sdim    SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
302317017Sdim    if (!getInstrValueMapping(MI, OpRegBankIdx, OpdsMapping))
303317017Sdim      break;
304317017Sdim
305317969Sdim    const RegisterBankInfo::InstructionMapping &Mapping = getInstructionMapping(
306317969Sdim        /*ID*/ 1, /*Cost*/ 1, getOperandsMapping(OpdsMapping), NumOperands);
307317017Sdim    InstructionMappings AltMappings;
308317969Sdim    AltMappings.push_back(&Mapping);
309317017Sdim    return AltMappings;
310317017Sdim  }
311317017Sdim  default:
312317017Sdim    break;
313317017Sdim  }
314317017Sdim  return RegisterBankInfo::getInstrAlternativeMappings(MI);
315317017Sdim}
316