/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "managed_register_arm64.h"
#include "globals.h"

namespace art {
namespace arm64 {

// TODO: Define convention
//
// Do not use APCS callee saved regs for now. Use:
//  * [X0, X15]
//  * [W0, W15]
//  * [D0, D31]
//  * [S0, S31]
// static const int kNumberOfAvailableCoreRegisters = (X15 - X0) + 1;
// static const int kNumberOfAvailableWRegisters = (W15 - W0) + 1;
// static const int kNumberOfAvailableDRegisters = kNumberOfDRegisters;
// static const int kNumberOfAvailableSRegisters = kNumberOfSRegisters;

// Returns true if this managed-register overlaps the other managed-register.
// GP Register Bank:
//       31____0 W[n]
// 63__________0 X[n]
//
// FP Register Bank:
//       31____0 S[n]
// 63__________0 D[n]
bool Arm64ManagedRegister::Overlaps(const Arm64ManagedRegister& other) const {
  if (IsNoRegister() || other.IsNoRegister()) return false;
  if ((IsGPRegister() && other.IsGPRegister()) ||
      (IsFPRegister() && other.IsFPRegister())) {
    return (RegNo() == other.RegNo());
  }
  return false;
}

int Arm64ManagedRegister::RegNo() const {
  CHECK(!IsNoRegister());
  int no;
  if (IsCoreRegister()) {
    if (IsZeroRegister()) {
      no = static_cast<int>(X31);
    } else {
      no = static_cast<int>(AsCoreRegister());
    }
  } else if (IsWRegister()) {
    no = static_cast<int>(AsWRegister());
  } else if (IsDRegister()) {
    no = static_cast<int>(AsDRegister());
  } else if (IsSRegister()) {
    no = static_cast<int>(AsSRegister());
  } else {
    no = kNoRegister;
  }
  return no;
}

int Arm64ManagedRegister::RegIdLow() const {
  CHECK(IsCoreRegister() || IsDRegister());
  int low = RegNo();
  if (IsCoreRegister()) {
    low += kNumberOfCoreRegIds;
  } else if (IsDRegister()) {
    low += kNumberOfCoreRegIds + kNumberOfWRegIds + kNumberOfDRegIds;
  }
  return low;
}

// FIXME: Find better naming.
int Arm64ManagedRegister::RegIdHigh() const {
  CHECK(IsWRegister() || IsSRegister());
  int high = RegNo();
  if (IsSRegister()) {
    high += kNumberOfCoreRegIds + kNumberOfWRegIds;
  }
  return high;
}

void Arm64ManagedRegister::Print(std::ostream& os) const {
  if (!IsValidManagedRegister()) {
    os << "No Register";
  } else if (IsCoreRegister()) {
    os << "XCore: " << static_cast<int>(AsCoreRegister());
  } else if (IsWRegister()) {
    os << "WCore: " << static_cast<int>(AsWRegister());
  } else if (IsDRegister()) {
    os << "DRegister: " << static_cast<int>(AsDRegister());
  } else if (IsSRegister()) {
    os << "SRegister: " << static_cast<int>(AsSRegister());
  } else {
    os << "??: " << RegId();
  }
}

std::ostream& operator<<(std::ostream& os, const Arm64ManagedRegister& reg) {
  reg.Print(os);
  return os;
}

}  // namespace arm64
}  // namespace art
