//===- AMDGPUGenRegisterBankInfo.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 AMDGPURegisterBankInfo.
/// \todo This should be generated by TableGen.
//===----------------------------------------------------------------------===//

namespace llvm {
namespace AMDGPU {

enum PartialMappingIdx {
  None = - 1,
  PM_SGPR1  = 2,
  PM_SGPR16 = 6,
  PM_SGPR32 = 7,
  PM_SGPR64 = 8,
  PM_SGPR128 = 9,
  PM_SGPR256 = 10,
  PM_SGPR512 = 11,
  PM_VGPR1  = 12,
  PM_VGPR16 = 16,
  PM_VGPR32 = 17,
  PM_VGPR64 = 18,
  PM_VGPR128 = 19,
  PM_VGPR256 = 20,
  PM_VGPR512 = 21,
  PM_SGPR96 = 22,
  PM_VGPR96 = 23
};

const RegisterBankInfo::PartialMapping PartMappings[] {
  // StartIdx, Length, RegBank
  {0, 1,  SCCRegBank},
  {0, 1,  VCCRegBank},

  {0, 1,  SGPRRegBank}, // SGPR begin
  {0, 16, SGPRRegBank},
  {0, 32, SGPRRegBank},
  {0, 64, SGPRRegBank},
  {0, 128, SGPRRegBank},
  {0, 256, SGPRRegBank},
  {0, 512, SGPRRegBank},

  {0, 1,  VGPRRegBank}, // VGPR begin
  {0, 16, VGPRRegBank},
  {0, 32, VGPRRegBank},
  {0, 64, VGPRRegBank},
  {0, 128, VGPRRegBank},
  {0, 256, VGPRRegBank},
  {0, 512, VGPRRegBank},
  {0, 96, SGPRRegBank},
  {0, 96, VGPRRegBank},
};

const RegisterBankInfo::ValueMapping ValMappings[] {
  // SCC
  {&PartMappings[0], 1},

  // VCC
  {&PartMappings[1], 1},

  // SGPRs
  {&PartMappings[2], 1},
  {nullptr, 0}, // Illegal power of 2 sizes
  {nullptr, 0},
  {nullptr, 0},
  {&PartMappings[3], 1},
  {&PartMappings[4], 1},
  {&PartMappings[5], 1},
  {&PartMappings[6], 1},
  {&PartMappings[7], 1},
  {&PartMappings[8], 1},

    // VGPRs
  {&PartMappings[9], 1},
  {nullptr, 0},
  {nullptr, 0},
  {nullptr, 0},
  {&PartMappings[10], 1},
  {&PartMappings[11], 1},
  {&PartMappings[12], 1},
  {&PartMappings[13], 1},
  {&PartMappings[14], 1},
  {&PartMappings[15], 1},
  {&PartMappings[16], 1},
  {&PartMappings[17], 1}
};

const RegisterBankInfo::PartialMapping SGPROnly64BreakDown[] {
  {0, 32, SGPRRegBank}, // 32-bit op
  {0, 32, SGPRRegBank}, // 2x32-bit op
  {32, 32, SGPRRegBank},
  {0, 64, SGPRRegBank}, // <2x32-bit> op

  {0, 32, VGPRRegBank}, // 32-bit op
  {0, 32, VGPRRegBank}, // 2x32-bit op
  {32, 32, VGPRRegBank},
};


// For some instructions which can operate 64-bit only for the scalar version.
const RegisterBankInfo::ValueMapping ValMappingsSGPR64OnlyVGPR32[] {
  /*32-bit sgpr*/     {&SGPROnly64BreakDown[0], 1},
  /*2 x 32-bit sgpr*/ {&SGPROnly64BreakDown[1], 2},
  /*64-bit sgpr */    {&SGPROnly64BreakDown[3], 1},

  /*32-bit vgpr*/     {&SGPROnly64BreakDown[4], 1},
  /*2 x 32-bit vgpr*/ {&SGPROnly64BreakDown[5], 2}
};

enum ValueMappingIdx {
  SCCStartIdx = 0,
  SGPRStartIdx = 2,
  VGPRStartIdx = 12
};

const RegisterBankInfo::ValueMapping *getValueMapping(unsigned BankID,
                                                      unsigned Size) {
  unsigned Idx;
  switch (Size) {
  case 1:
    if (BankID == AMDGPU::SCCRegBankID)
      return &ValMappings[0];
    if (BankID == AMDGPU::VCCRegBankID)
      return &ValMappings[1];

    // 1-bit values not from a compare etc.
    Idx = BankID == AMDGPU::SGPRRegBankID ? PM_SGPR1 : PM_VGPR1;
    break;
  case 96:
    assert(BankID != AMDGPU::VCCRegBankID);
    Idx = BankID == AMDGPU::SGPRRegBankID ? PM_SGPR96 : PM_VGPR96;
    break;
  default:
    assert(BankID != AMDGPU::VCCRegBankID);
    Idx = BankID == AMDGPU::VGPRRegBankID ? VGPRStartIdx : SGPRStartIdx;
    Idx += Log2_32_Ceil(Size);
    break;
  }

  assert(Log2_32_Ceil(Size) == Log2_32_Ceil(ValMappings[Idx].BreakDown->Length));
  assert(BankID == ValMappings[Idx].BreakDown->RegBank->getID());

  return &ValMappings[Idx];
}

const RegisterBankInfo::ValueMapping *getValueMappingSGPR64Only(unsigned BankID,
                                                                unsigned Size) {
  if (Size != 64)
    return getValueMapping(BankID, Size);

  if (BankID == AMDGPU::VGPRRegBankID)
    return &ValMappingsSGPR64OnlyVGPR32[4];

  assert(BankID == AMDGPU::SGPRRegBankID);
  return &ValMappingsSGPR64OnlyVGPR32[2];
}

const RegisterBankInfo::PartialMapping LoadSGPROnlyBreakDown[] {
  /* 256-bit load */    {0, 256, SGPRRegBank},
  /* 512-bit load */    {0, 512, SGPRRegBank},
  /* 8 32-bit loads */  {0, 32, VGPRRegBank}, {32, 32, VGPRRegBank},
                        {64, 32, VGPRRegBank}, {96, 32, VGPRRegBank},
                        {128, 32, VGPRRegBank}, {160, 32, VGPRRegBank},
                        {192, 32, VGPRRegBank}, {224, 32, VGPRRegBank},
  /* 16 32-bit loads */ {0, 32, VGPRRegBank}, {32, 32, VGPRRegBank},
                        {64, 32, VGPRRegBank}, {96, 32, VGPRRegBank},
                        {128, 32, VGPRRegBank}, {160, 32, VGPRRegBank},
                        {192, 32, VGPRRegBank}, {224, 32, VGPRRegBank},
                        {256, 32, VGPRRegBank}, {288, 32, VGPRRegBank},
                        {320, 32, VGPRRegBank}, {352, 32, VGPRRegBank},
                        {384, 32, VGPRRegBank}, {416, 32, VGPRRegBank},
                        {448, 32, VGPRRegBank}, {480, 32, VGPRRegBank},
  /* 4 64-bit loads */  {0, 64, VGPRRegBank}, {64, 64, VGPRRegBank},
                        {128, 64, VGPRRegBank}, {192, 64, VGPRRegBank},
  /* 8 64-bit loads */  {0, 64, VGPRRegBank}, {64, 64, VGPRRegBank},
                        {128, 64, VGPRRegBank}, {192, 64, VGPRRegBank},
                        {256, 64, VGPRRegBank}, {320, 64, VGPRRegBank},
                        {384, 64, VGPRRegBank}, {448, 64, VGPRRegBank},

  /* FIXME: The generic register bank select does not support complex
   * break downs where the number of vector elements does not equal the
   * number of breakdowns.
   * FIXME: register bank select now tries to handle complex break downs,
   * but it emits an illegal instruction:
   * %1:vgpr(<8 x s32>) = G_CONCAT_VECTORS %2:vgpr(s128), %3:vgpr(s128)
   */
  /* 2 128-bit loads */ {0, 128, VGPRRegBank}, {128, 128, VGPRRegBank},
  /* 4 128-bit loads */ {0, 128, VGPRRegBank}, {128, 128, VGPRRegBank},
                        {256, 128, VGPRRegBank}, {384, 128, VGPRRegBank}
};

const RegisterBankInfo::ValueMapping ValMappingsLoadSGPROnly[] {
  /* 256-bit load */     {&LoadSGPROnlyBreakDown[0], 1},
  /* 512-bit load */     {&LoadSGPROnlyBreakDown[1], 1},
  /* <8 x i32> load  */  {&LoadSGPROnlyBreakDown[2], 8},
  /* <16 x i32> load */  {&LoadSGPROnlyBreakDown[10], 16},
  /* <4 x i64> load */   {&LoadSGPROnlyBreakDown[26], 4},
  /* <8 x i64> load */   {&LoadSGPROnlyBreakDown[30], 8}
};

const RegisterBankInfo::ValueMapping *
getValueMappingLoadSGPROnly(unsigned BankID, LLT SizeTy) {
  unsigned Size = SizeTy.getSizeInBits();
  if (Size < 256 || BankID == AMDGPU::SGPRRegBankID)
    return getValueMapping(BankID, Size);

  assert((Size == 256 || Size == 512) && BankID == AMDGPU::VGPRRegBankID);

  // Default to using the non-split ValueMappings, we will use these if
  // the register bank is SGPR or if we don't know how to handle the vector
  // type.
  unsigned Idx = Size == 256 ? 0 : 1;

  // We need to split this load if it has a vgpr pointer.
  if (BankID == AMDGPU::VGPRRegBankID) {
    if (SizeTy == LLT::vector(8, 32))
      Idx = 2;
    else if (SizeTy == LLT::vector(16, 32))
      Idx = 3;
    else if (SizeTy == LLT::vector(4, 64))
      Idx = 4;
    else if (SizeTy == LLT::vector(8, 64))
      Idx = 5;
  }

  return &ValMappingsLoadSGPROnly[Idx];
}


} // End AMDGPU namespace.
} // End llvm namespace.
