//===- AArch64GenRegisterBankInfo.def ----------------------------*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file defines all the static objects used by AArch64RegisterBankInfo.
/// \todo This should be generated by TableGen.
//===----------------------------------------------------------------------===//

#ifndef LLVM_BUILD_GLOBAL_ISEL
#error "You shouldn't build this"
#endif

namespace llvm {
namespace AArch64 {

RegisterBank GPRRegBank;
RegisterBank FPRRegBank;
RegisterBank CCRRegBank;

RegisterBank *RegBanks[] = {&GPRRegBank, &FPRRegBank, &CCRRegBank};

// PartialMappings.
enum PartialMappingIdx {
  PMI_None = -1,
  PMI_GPR32 = 1,
  PMI_GPR64,
  PMI_FPR32,
  PMI_FPR64,
  PMI_FPR128,
  PMI_FPR256,
  PMI_FPR512,
  PMI_FirstGPR = PMI_GPR32,
  PMI_LastGPR = PMI_GPR64,
  PMI_FirstFPR = PMI_FPR32,
  PMI_LastFPR = PMI_FPR512,
  PMI_Min = PMI_FirstGPR,
};

static unsigned getRegBankBaseIdxOffset(unsigned Size) {
  assert(Size && "0-sized type!!");
  // Make anything smaller than 32 gets 32
  Size = ((Size + 31) / 32) * 32;
  // 32 is 0, 64 is 1, 128 is 2, and so on.
  return Log2_32(Size) - /*Log2_32(32)=*/ 5;
}

RegisterBankInfo::PartialMapping PartMappings[] {
  /* StartIdx, Length, RegBank */
  // 0: GPR 32-bit value.
  {0, 32, GPRRegBank},
  // 1: GPR 64-bit value.
  {0, 64, GPRRegBank},
  // 2: FPR 32-bit value.
  {0, 32, FPRRegBank},
  // 3: FPR 64-bit value.
  {0, 64, FPRRegBank},
  // 4: FPR 128-bit value.
  {0, 128, FPRRegBank},
  // 5: FPR 256-bit value.
  {0, 256, FPRRegBank},
  // 6: FPR 512-bit value.
  {0, 512, FPRRegBank}
};

enum ValueMappingIdx {
  First3OpsIdx = 0,
  Last3OpsIdx = 18,
  DistanceBetweenRegBanks = 3,
  FirstCrossRegCpyIdx = 21,
  LastCrossRegCpyIdx = 27,
  DistanceBetweenCrossRegCpy = 2
};

// ValueMappings.
RegisterBankInfo::ValueMapping ValMappings[]{
    /* BreakDown, NumBreakDowns */
    // 3-operands instructions (all binary operations should end up with one of
    // those mapping).
    // 0: GPR 32-bit value. <-- This must match First3OpsIdx.
    {&PartMappings[PMI_GPR32 - PMI_Min], 1},
    {&PartMappings[PMI_GPR32 - PMI_Min], 1},
    {&PartMappings[PMI_GPR32 - PMI_Min], 1},
    // 3: GPR 64-bit value.
    {&PartMappings[PMI_GPR64 - PMI_Min], 1},
    {&PartMappings[PMI_GPR64 - PMI_Min], 1},
    {&PartMappings[PMI_GPR64 - PMI_Min], 1},
    // 6: FPR 32-bit value.
    {&PartMappings[PMI_FPR32 - PMI_Min], 1},
    {&PartMappings[PMI_FPR32 - PMI_Min], 1},
    {&PartMappings[PMI_FPR32 - PMI_Min], 1},
    // 9: FPR 64-bit value.
    {&PartMappings[PMI_FPR64 - PMI_Min], 1},
    {&PartMappings[PMI_FPR64 - PMI_Min], 1},
    {&PartMappings[PMI_FPR64 - PMI_Min], 1},
    // 12: FPR 128-bit value.
    {&PartMappings[PMI_FPR128 - PMI_Min], 1},
    {&PartMappings[PMI_FPR128 - PMI_Min], 1},
    {&PartMappings[PMI_FPR128 - PMI_Min], 1},
    // 15: FPR 256-bit value.
    {&PartMappings[PMI_FPR256 - PMI_Min], 1},
    {&PartMappings[PMI_FPR256 - PMI_Min], 1},
    {&PartMappings[PMI_FPR256 - PMI_Min], 1},
    // 18: FPR 512-bit value. <-- This must match Last3OpsIdx.
    {&PartMappings[PMI_FPR512 - PMI_Min], 1},
    {&PartMappings[PMI_FPR512 - PMI_Min], 1},
    {&PartMappings[PMI_FPR512 - PMI_Min], 1},
    // Cross register bank copies.
    // 21: GPR 32-bit value to FPR 32-bit value. <-- This must match
    //                                               FirstCrossRegCpyIdx.
    {&PartMappings[PMI_GPR32 - PMI_Min], 1},
    {&PartMappings[PMI_FPR32 - PMI_Min], 1},
    // 23: GPR 64-bit value to FPR 64-bit value.
    {&PartMappings[PMI_GPR64 - PMI_Min], 1},
    {&PartMappings[PMI_FPR64 - PMI_Min], 1},
    // 25: FPR 32-bit value to GPR 32-bit value.
    {&PartMappings[PMI_FPR32 - PMI_Min], 1},
    {&PartMappings[PMI_GPR32 - PMI_Min], 1},
    // 27: FPR 64-bit value to GPR 64-bit value. <-- This must match
    //                                               LastCrossRegCpyIdx.
    {&PartMappings[PMI_FPR64 - PMI_Min], 1},
    {&PartMappings[PMI_GPR64 - PMI_Min], 1}
};

/// Get the pointer to the ValueMapping representing the RegisterBank
/// at \p RBIdx with a size of \p Size.
///
/// The returned mapping works for instructions with the same kind of
/// operands for up to 3 operands.
///
/// \pre \p RBIdx != PartialMappingIdx::None
const RegisterBankInfo::ValueMapping *
getValueMapping(PartialMappingIdx RBIdx, unsigned Size) {
  assert(RBIdx != PartialMappingIdx::PMI_None && "No mapping needed for that");
  unsigned ValMappingIdx = First3OpsIdx +
                           (RBIdx - AArch64::PartialMappingIdx::PMI_Min +
                            getRegBankBaseIdxOffset(Size)) *
                               ValueMappingIdx::DistanceBetweenRegBanks;
  assert(ValMappingIdx >= AArch64::First3OpsIdx &&
         ValMappingIdx <= AArch64::Last3OpsIdx && "Mapping out of bound");

  return &ValMappings[ValMappingIdx];
}

/// Get the pointer to the ValueMapping of the operands of a copy
/// instruction from a GPR or FPR register to a GPR or FPR register
/// with a size of \p Size.
///
/// If \p DstIsGPR is true, the destination of the copy is on GPR,
/// otherwise it is on FPR. Same thing for \p SrcIsGPR.
const RegisterBankInfo::ValueMapping *
getCopyMapping(bool DstIsGPR, bool SrcIsGPR, unsigned Size) {
  PartialMappingIdx DstRBIdx = DstIsGPR ? PMI_FirstGPR : PMI_FirstFPR;
  PartialMappingIdx SrcRBIdx = SrcIsGPR ? PMI_FirstGPR : PMI_FirstFPR;
  if (DstRBIdx == SrcRBIdx)
    return getValueMapping(DstRBIdx, Size);
  assert(Size <= 64 && "GPR cannot handle that size");
  unsigned ValMappingIdx =
      FirstCrossRegCpyIdx +
      (DstRBIdx - PMI_Min + getRegBankBaseIdxOffset(Size)) *
          ValueMappingIdx::DistanceBetweenCrossRegCpy;
  assert(ValMappingIdx >= AArch64::FirstCrossRegCpyIdx &&
         ValMappingIdx <= AArch64::LastCrossRegCpyIdx &&
         "Mapping out of bound");
  return &ValMappings[ValMappingIdx];
}

} // End AArch64 namespace.
} // End llvm namespace.
