//===- AArch64GenRegisterBankInfo.def ----------------------------*- C++ -*-==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This file defines all the static objects used by AArch64RegisterBankInfo.
/// \todo This should be generated by TableGen.
//===----------------------------------------------------------------------===//

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

// ValueMappings.
RegisterBankInfo::ValueMapping AArch64GenRegisterBankInfo::ValMappings[]{
    /* BreakDown, NumBreakDowns */
    // 0: invalid
    {nullptr, 0},
    // 3-operands instructions (all binary operations should end up with one of
    // those mapping).
    // 1: FPR 16-bit value. <-- This must match First3OpsIdx.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR16 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR16 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR16 - PMI_Min], 1},
    // 4: FPR 32-bit value. <-- This must match First3OpsIdx.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
    // 7: FPR 64-bit value.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
    // 10: FPR 128-bit value.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR128 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR128 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR128 - PMI_Min], 1},
    // 13: FPR 256-bit value.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR256 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR256 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR256 - PMI_Min], 1},
    // 16: FPR 512-bit value.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR512 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR512 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR512 - PMI_Min], 1},
    // 19: GPR 32-bit value.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
    // 22: GPR 64-bit value. <-- This must match Last3OpsIdx.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
    // Cross register bank copies.
    // 25: FPR 16-bit value to GPR 16-bit. <-- This must match
    //                                         FirstCrossRegCpyIdx.
    // Note: This is the kind of copy we see with physical registers.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR16 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
    // 27: FPR 32-bit value to GPR 32-bit value.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
    // 29: FPR 64-bit value to GPR 64-bit value.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
    // 31: FPR 128-bit value to GPR 128-bit value (invalid)
    {nullptr, 1},
    {nullptr, 1},
    // 33: FPR 256-bit value to GPR 256-bit value (invalid)
    {nullptr, 1},
    {nullptr, 1},
    // 35: FPR 512-bit value to GPR 512-bit value (invalid)
    {nullptr, 1},
    {nullptr, 1},
    // 37: GPR 32-bit value to FPR 32-bit value.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
    // 39: GPR 64-bit value to FPR 64-bit value. <-- This must match
    //                                               LastCrossRegCpyIdx.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
    // 41: FPExt: 16 to 32. <-- This must match FPExt16To32Idx.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR16 - PMI_Min], 1},
    // 43: FPExt: 16 to 32. <-- This must match FPExt16To64Idx.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR16 - PMI_Min], 1},
    // 45: FPExt: 32 to 64. <-- This must match FPExt32To64Idx.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
    // 47: FPExt vector: 64 to 128. <-- This must match FPExt64To128Idx.
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR128 - PMI_Min], 1},
    {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
};

bool AArch64GenRegisterBankInfo::checkPartialMap(unsigned Idx,
                                                 unsigned ValStartIdx,
                                                 unsigned ValLength,
                                                 const RegisterBank &RB) {
  const PartialMapping &Map = PartMappings[Idx - PartialMappingIdx::PMI_Min];
  return Map.StartIdx == ValStartIdx && Map.Length == ValLength &&
         Map.RegBank == &RB;
}

bool AArch64GenRegisterBankInfo::checkValueMapImpl(unsigned Idx,
                                                   unsigned FirstInBank,
                                                   unsigned Size,
                                                   unsigned Offset) {
  unsigned PartialMapBaseIdx = Idx - PartialMappingIdx::PMI_Min;
  const ValueMapping &Map =
      AArch64GenRegisterBankInfo::getValueMapping((PartialMappingIdx)FirstInBank, Size)[Offset];
  return Map.BreakDown == &PartMappings[PartialMapBaseIdx] &&
         Map.NumBreakDowns == 1;
}

bool AArch64GenRegisterBankInfo::checkPartialMappingIdx(
    PartialMappingIdx FirstAlias, PartialMappingIdx LastAlias,
    ArrayRef<PartialMappingIdx> Order) {
  if (Order.front() != FirstAlias)
    return false;
  if (Order.back() != LastAlias)
    return false;
  if (Order.front() > Order.back())
    return false;

  PartialMappingIdx Previous = Order.front();
  bool First = true;
  for (const auto &Current : Order) {
    if (First) {
      First = false;
      continue;
    }
    if (Previous + 1 != Current)
      return false;
    Previous = Current;
  }
  return true;
}

unsigned AArch64GenRegisterBankInfo::getRegBankBaseIdxOffset(unsigned RBIdx,
                                                             unsigned Size) {
  if (RBIdx == PMI_FirstGPR) {
    if (Size <= 32)
      return 0;
    if (Size <= 64)
      return 1;
    return -1;
  }
  if (RBIdx == PMI_FirstFPR) {
    if (Size <= 16)
      return 0;
    if (Size <= 32)
      return 1;
    if (Size <= 64)
      return 2;
    if (Size <= 128)
      return 3;
    if (Size <= 256)
      return 4;
    if (Size <= 512)
      return 5;
    return -1;
  }
  return -1;
}

const RegisterBankInfo::ValueMapping *
AArch64GenRegisterBankInfo::getValueMapping(PartialMappingIdx RBIdx,
                                            unsigned Size) {
  assert(RBIdx != PartialMappingIdx::PMI_None && "No mapping needed for that");
  unsigned BaseIdxOffset = getRegBankBaseIdxOffset(RBIdx, Size);
  if (BaseIdxOffset == -1u)
    return &ValMappings[InvalidIdx];

  unsigned ValMappingIdx =
      First3OpsIdx + (RBIdx - PartialMappingIdx::PMI_Min + BaseIdxOffset) *
                         ValueMappingIdx::DistanceBetweenRegBanks;
  assert(ValMappingIdx >= First3OpsIdx && ValMappingIdx <= Last3OpsIdx &&
         "Mapping out of bound");

  return &ValMappings[ValMappingIdx];
}

AArch64GenRegisterBankInfo::PartialMappingIdx
    AArch64GenRegisterBankInfo::BankIDToCopyMapIdx[]{
        PMI_None,     // CCR
        PMI_FirstFPR, // FPR
        PMI_FirstGPR, // GPR
    };

const RegisterBankInfo::ValueMapping *
AArch64GenRegisterBankInfo::getCopyMapping(unsigned DstBankID,
                                           unsigned SrcBankID, unsigned Size) {
  assert(DstBankID < AArch64::NumRegisterBanks && "Invalid bank ID");
  assert(SrcBankID < AArch64::NumRegisterBanks && "Invalid bank ID");
  PartialMappingIdx DstRBIdx = BankIDToCopyMapIdx[DstBankID];
  PartialMappingIdx SrcRBIdx = BankIDToCopyMapIdx[SrcBankID];
  assert(DstRBIdx != PMI_None && "No such mapping");
  assert(SrcRBIdx != PMI_None && "No such mapping");

  if (DstRBIdx == SrcRBIdx)
    return getValueMapping(DstRBIdx, Size);

  assert(Size <= 64 && "GPR cannot handle that size");
  unsigned ValMappingIdx =
      FirstCrossRegCpyIdx +
      (DstRBIdx - PMI_Min + getRegBankBaseIdxOffset(DstRBIdx, Size)) *
          ValueMappingIdx::DistanceBetweenCrossRegCpy;
  assert(ValMappingIdx >= FirstCrossRegCpyIdx &&
         ValMappingIdx <= LastCrossRegCpyIdx && "Mapping out of bound");
  return &ValMappings[ValMappingIdx];
}

const RegisterBankInfo::ValueMapping *
AArch64GenRegisterBankInfo::getFPExtMapping(unsigned DstSize,
                                         unsigned SrcSize) {
  // We support:
  // - For Scalar:
  //   - 16 to 32.
  //   - 16 to 64.
  //   - 32 to 64.
  // => FPR 16 to FPR 32|64
  // => FPR 32 to FPR 64
  // - For vectors:
  //   - v4f16 to v4f32
  //   - v2f32 to v2f64
  // => FPR 64 to FPR 128

  // Check that we have been asked sensible sizes.
  if (SrcSize == 16) {
    assert((DstSize == 32 || DstSize == 64) && "Unexpected half extension");
    if (DstSize == 32)
      return &ValMappings[FPExt16To32Idx];
    return &ValMappings[FPExt16To64Idx];
  }

  if (SrcSize == 32) {
    assert(DstSize == 64 && "Unexpected float extension");
    return &ValMappings[FPExt32To64Idx];
  }
  assert((SrcSize == 64 || DstSize == 128) && "Unexpected vector extension");
  return &ValMappings[FPExt64To128Idx];
}
} // End llvm namespace.
