// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// This file contains few helpful marker types that can be used with
// MakeLocationSummaryFromEmitter and InvokeEmitter to simplify writing
// of ARM code.

#ifndef RUNTIME_VM_COMPILER_BACKEND_LOCATIONS_HELPERS_ARM_H_
#define RUNTIME_VM_COMPILER_BACKEND_LOCATIONS_HELPERS_ARM_H_

#if defined(DART_PRECOMPILED_RUNTIME)
#error "AOT runtime should not use compiler sources (including header files)"
#endif  // defined(DART_PRECOMPILED_RUNTIME)

namespace dart {

// QRegisterView is a wrapper around QRegister that provides helpers for
// accessing S and D components.
class QRegisterView {
 public:
  explicit QRegisterView(QRegister reg) : reg_(reg) {}

  operator QRegister() const { return reg_; }

  inline DRegister d(intptr_t i) const {
    ASSERT(0 <= i && i < 2);
    return static_cast<DRegister>(reg_ * 2 + i);
  }

  inline SRegister s(intptr_t i) const {
    ASSERT(0 <= i && i < 4);
    ASSERT(reg_ <= Q7);
    return static_cast<SRegister>(reg_ * 4 + i);
  }

 private:
  QRegister reg_;
};

// FixedQRegisterView<r> is a handy replacement for Fixed<QRegister, r> that
// provides helpers for accessing S and D components.
//
// Note: this class is provided because Fixed<QRegisterView, r> is not a valid
// type.
template <QRegister reg>
class FixedQRegisterView {
 public:
  inline DRegister d(intptr_t i) const {
    return static_cast<DRegister>(reg * 2 + i);
  }

  inline SRegister s(intptr_t i) const {
    return static_cast<SRegister>(reg * 4 + i);
  }

  operator QRegister() const { return reg; }
};

template <>
struct LocationTrait<QRegisterView> {
  static constexpr bool kIsTemp = false;

  static QRegisterView Unwrap(const Location& loc) {
    return QRegisterView(loc.fpu_reg());
  }

  template <intptr_t arity, intptr_t index>
  static QRegisterView UnwrapInput(LocationSummary* locs) {
    return Unwrap(locs->in(index));
  }

  template <intptr_t arity, intptr_t index>
  static void SetInputConstraint(LocationSummary* locs) {
    locs->set_in(index, ToConstraint());
  }

  static Location ToConstraint() { return Location::RequiresFpuRegister(); }
};

template <QRegister reg>
struct LocationTrait<FixedQRegisterView<reg> > {
  static constexpr bool kIsTemp = false;

  static FixedQRegisterView<reg> Unwrap(const Location& loc) {
    ASSERT(LocationTrait<QRegister>::Unwrap(loc) == reg);
    return FixedQRegisterView<reg>();
  }

  template <intptr_t arity, intptr_t index>
  static FixedQRegisterView<reg> UnwrapInput(LocationSummary* locs) {
    return Unwrap(locs->in(index));
  }

  template <intptr_t arity, intptr_t index>
  static void SetInputConstraint(LocationSummary* locs) {
    locs->set_in(index, ToConstraint());
  }

  static Location ToConstraint() { return Location::FpuRegisterLocation(reg); }
};

}  // namespace dart

#endif  // RUNTIME_VM_COMPILER_BACKEND_LOCATIONS_HELPERS_ARM_H_
