/*
* Copyright (C) 2011 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.
*/
#ifndef ART_COMPILER_UTILS_ARM_MANAGED_REGISTER_ARM_H_
#define ART_COMPILER_UTILS_ARM_MANAGED_REGISTER_ARM_H_
#include <android-base/logging.h>
#include "constants_arm.h"
#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
// TODO(VIXL): Make VIXL compile with -Wshadow.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#include "aarch32/macro-assembler-aarch32.h"
#pragma GCC diagnostic pop
namespace art {
namespace arm {
// Values for register pairs.
enum RegisterPair {
R0_R1 = 0,
R2_R3 = 1,
R4_R5 = 2,
R6_R7 = 3,
R1_R2 = 4, // Dalvik style passing
kNumberOfRegisterPairs = 5,
kNoRegisterPair = -1,
};
std::ostream& operator<<(std::ostream& os, const RegisterPair& reg);
const int kNumberOfCoreRegIds = kNumberOfCoreRegisters;
const int kNumberOfCoreAllocIds = kNumberOfCoreRegisters;
const int kNumberOfSRegIds = kNumberOfSRegisters;
const int kNumberOfSAllocIds = kNumberOfSRegisters;
const int kNumberOfDRegIds = kNumberOfDRegisters;
const int kNumberOfOverlappingDRegIds = kNumberOfOverlappingDRegisters;
const int kNumberOfDAllocIds = kNumberOfDRegIds - kNumberOfOverlappingDRegIds;
const int kNumberOfPairRegIds = kNumberOfRegisterPairs;
const int kNumberOfRegIds = kNumberOfCoreRegIds + kNumberOfSRegIds +
kNumberOfDRegIds + kNumberOfPairRegIds;
const int kNumberOfAllocIds =
kNumberOfCoreAllocIds + kNumberOfSAllocIds + kNumberOfDAllocIds;
// Register ids map:
// [0..R[ core registers (enum Register)
// [R..S[ single precision VFP registers (enum SRegister)
// [S..D[ double precision VFP registers (enum DRegister)
// [D..P[ core register pairs (enum RegisterPair)
// where
// R = kNumberOfCoreRegIds
// S = R + kNumberOfSRegIds
// D = S + kNumberOfDRegIds
// P = D + kNumberOfRegisterPairs
// Allocation ids map:
// [0..R[ core registers (enum Register)
// [R..S[ single precision VFP registers (enum SRegister)
// [S..N[ non-overlapping double precision VFP registers (16-31 in enum
// DRegister, VFPv3-D32 only)
// where
// R = kNumberOfCoreAllocIds
// S = R + kNumberOfSAllocIds
// N = S + kNumberOfDAllocIds
// An instance of class 'ManagedRegister' represents a single ARM register or a
// pair of core ARM registers (enum RegisterPair). A single register is either a
// core register (enum Register), a VFP single precision register
// (enum SRegister), or a VFP double precision register (enum DRegister).
// 'ManagedRegister::NoRegister()' returns an invalid ManagedRegister.
// There is a one-to-one mapping between ManagedRegister and register id.
class ArmManagedRegister : public ManagedRegister {
public:
constexpr Register AsCoreRegister() const {
CHECK(IsCoreRegister());
return static_cast<Register>(id_);
}
vixl::aarch32::Register AsVIXLRegister() const {
CHECK(IsCoreRegister());
return vixl::aarch32::Register(id_);
}
constexpr SRegister AsSRegister() const {
CHECK(IsSRegister());
return static_cast<SRegister>(id_ - kNumberOfCoreRegIds);
}
vixl::aarch32::SRegister AsVIXLSRegister() const {
CHECK(IsSRegister());
return vixl::aarch32::SRegister(id_ - kNumberOfCoreRegIds);
}
constexpr DRegister AsDRegister() const {
CHECK(IsDRegister());
return static_cast<DRegister>(id_ - kNumberOfCoreRegIds - kNumberOfSRegIds);
}
vixl::aarch32::DRegister AsVIXLDRegister() const {
CHECK(IsDRegister());
return vixl::aarch32::DRegister(id_ - kNumberOfCoreRegIds - kNumberOfSRegIds);
}
constexpr SRegister AsOverlappingDRegisterLow() const {
CHECK(IsOverlappingDRegister());
DRegister d_reg = AsDRegister();
return static_cast<SRegister>(d_reg * 2);
}
constexpr SRegister AsOverlappingDRegisterHigh() const {
CHECK(IsOverlappingDRegister());
DRegister d_reg = AsDRegister();
return static_cast<SRegister>(d_reg * 2 + 1);
}
constexpr RegisterPair AsRegisterPair() const {
CHECK(IsRegisterPair());
Register reg_low = AsRegisterPairLow();
if (reg_low == R1) {
return R1_R2;
} else {
return static_cast<RegisterPair>(reg_low / 2);
}
}
constexpr Register AsRegisterPairLow() const {
CHECK(IsRegisterPair());
// Appropriate mapping of register ids allows to use AllocIdLow().
return FromRegId(AllocIdLow()).AsCoreRegister();
}
vixl::aarch32::Register AsVIXLRegisterPairLow() const {
return vixl::aarch32::Register(AsRegisterPairLow());
}
constexpr Register AsRegisterPairHigh() const {
CHECK(IsRegisterPair());
// Appropriate mapping of register ids allows to use AllocIdHigh().
return FromRegId(AllocIdHigh()).AsCoreRegister();
}
vixl::aarch32::Register AsVIXLRegisterPairHigh() const {
return vixl::aarch32::Register(AsRegisterPairHigh());
}
constexpr bool IsCoreRegister() const {
CHECK(IsValidManagedRegister());
return (0 <= id_) && (id_ < kNumberOfCoreRegIds);
}
constexpr bool IsSRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - kNumberOfCoreRegIds;
return (0 <= test) && (test < kNumberOfSRegIds);
}
constexpr bool IsDRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - (kNumberOfCoreRegIds + kNumberOfSRegIds);
return (0 <= test) && (test < kNumberOfDRegIds);
}
// Returns true if this DRegister overlaps SRegisters.
constexpr bool IsOverlappingDRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - (kNumberOfCoreRegIds + kNumberOfSRegIds);
return (0 <= test) && (test < kNumberOfOverlappingDRegIds);
}
constexpr bool IsRegisterPair() const {
CHECK(IsValidManagedRegister());
const int test =
id_ - (kNumberOfCoreRegIds + kNumberOfSRegIds + kNumberOfDRegIds);
return (0 <= test) && (test < kNumberOfPairRegIds);
}
constexpr bool IsSameType(ArmManagedRegister test) const {
CHECK(IsValidManagedRegister() && test.IsValidManagedRegister());
return
(IsCoreRegister() && test.IsCoreRegister()) ||
(IsSRegister() && test.IsSRegister()) ||
(IsDRegister() && test.IsDRegister()) ||
(IsRegisterPair() && test.IsRegisterPair());
}
// Returns true if the two managed-registers ('this' and 'other') overlap.
// Either managed-register may be the NoRegister. If both are the NoRegister
// then false is returned.
bool Overlaps(const ArmManagedRegister& other) const;
void Print(std::ostream& os) const;
static constexpr ArmManagedRegister FromCoreRegister(Register r) {
CHECK_NE(r, kNoRegister);
return FromRegId(r);
}
static constexpr ArmManagedRegister FromSRegister(SRegister r) {
CHECK_NE(r, kNoSRegister);
return FromRegId(r + kNumberOfCoreRegIds);
}
static constexpr ArmManagedRegister FromDRegister(DRegister r) {
CHECK_NE(r, kNoDRegister);
return FromRegId(r + (kNumberOfCoreRegIds + kNumberOfSRegIds));
}
static constexpr ArmManagedRegister FromRegisterPair(RegisterPair r) {
CHECK_NE(r, kNoRegisterPair);
return FromRegId(r + (kNumberOfCoreRegIds +
kNumberOfSRegIds + kNumberOfDRegIds));
}
// Return a RegisterPair consisting of Register r_low and r_low + 1.
static constexpr ArmManagedRegister FromCoreRegisterPair(Register r_low) {
if (r_low != R1) { // not the dalvik special case
CHECK_NE(r_low, kNoRegister);
CHECK_EQ(0, (r_low % 2));
const int r = r_low / 2;
CHECK_LT(r, kNumberOfPairRegIds);
return FromRegisterPair(static_cast<RegisterPair>(r));
} else {
return FromRegisterPair(R1_R2);
}
}
// Return a DRegister overlapping SRegister r_low and r_low + 1.
static constexpr ArmManagedRegister FromSRegisterPair(SRegister r_low) {
CHECK_NE(r_low, kNoSRegister);
CHECK_EQ(0, (r_low % 2));
const int r = r_low / 2;
CHECK_LT(r, kNumberOfOverlappingDRegIds);
return FromDRegister(static_cast<DRegister>(r));
}
private:
constexpr bool IsValidManagedRegister() const {
return (0 <= id_) && (id_ < kNumberOfRegIds);
}
int RegId() const {
CHECK(!IsNoRegister());
return id_;
}
int AllocId() const {
CHECK(IsValidManagedRegister() &&
!IsOverlappingDRegister() && !IsRegisterPair());
int r = id_;
if ((kNumberOfDAllocIds > 0) && IsDRegister()) { // VFPv3-D32 only.
r -= kNumberOfOverlappingDRegIds;
}
CHECK_LT(r, kNumberOfAllocIds);
return r;
}
int AllocIdLow() const;
int AllocIdHigh() const;
friend class ManagedRegister;
explicit constexpr ArmManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
static constexpr ArmManagedRegister FromRegId(int reg_id) {
ArmManagedRegister reg(reg_id);
CHECK(reg.IsValidManagedRegister());
return reg;
}
};
std::ostream& operator<<(std::ostream& os, const ArmManagedRegister& reg);
} // namespace arm
constexpr inline arm::ArmManagedRegister ManagedRegister::AsArm() const {
arm::ArmManagedRegister reg(id_);
CHECK(reg.IsNoRegister() || reg.IsValidManagedRegister());
return reg;
}
} // namespace art
#endif // ART_COMPILER_UTILS_ARM_MANAGED_REGISTER_ARM_H_