// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/register-configuration.h" #include "src/globals.h" #include "src/macro-assembler.h" namespace v8 { namespace internal { namespace { #define REGISTER_COUNT(R) 1 + static const int kMaxAllocatableGeneralRegisterCount = ALLOCATABLE_GENERAL_REGISTERS(REGISTER_COUNT)0; static const int kMaxAllocatableDoubleRegisterCount = ALLOCATABLE_DOUBLE_REGISTERS(REGISTER_COUNT)0; static const int kAllocatableGeneralCodes[] = { #define REGISTER_CODE(R) Register::kCode_##R, ALLOCATABLE_GENERAL_REGISTERS(REGISTER_CODE)}; #undef REGISTER_CODE static const int kAllocatableDoubleCodes[] = { #define REGISTER_CODE(R) DoubleRegister::kCode_##R, ALLOCATABLE_DOUBLE_REGISTERS(REGISTER_CODE)}; #undef REGISTER_CODE static const char* const kGeneralRegisterNames[] = { #define REGISTER_NAME(R) #R, GENERAL_REGISTERS(REGISTER_NAME) #undef REGISTER_NAME }; static const char* const kFloatRegisterNames[] = { #define REGISTER_NAME(R) #R, FLOAT_REGISTERS(REGISTER_NAME) #undef REGISTER_NAME }; static const char* const kDoubleRegisterNames[] = { #define REGISTER_NAME(R) #R, DOUBLE_REGISTERS(REGISTER_NAME) #undef REGISTER_NAME }; STATIC_ASSERT(RegisterConfiguration::kMaxGeneralRegisters >= Register::kNumRegisters); STATIC_ASSERT(RegisterConfiguration::kMaxFPRegisters >= DoubleRegister::kMaxNumRegisters); enum CompilerSelector { CRANKSHAFT, TURBOFAN }; class ArchDefaultRegisterConfiguration : public RegisterConfiguration { public: explicit ArchDefaultRegisterConfiguration(CompilerSelector compiler) : RegisterConfiguration( Register::kNumRegisters, DoubleRegister::kMaxNumRegisters, #if V8_TARGET_ARCH_IA32 kMaxAllocatableGeneralRegisterCount, kMaxAllocatableDoubleRegisterCount, #elif V8_TARGET_ARCH_X87 kMaxAllocatableGeneralRegisterCount, compiler == TURBOFAN ? 1 : kMaxAllocatableDoubleRegisterCount, #elif V8_TARGET_ARCH_X64 kMaxAllocatableGeneralRegisterCount, kMaxAllocatableDoubleRegisterCount, #elif V8_TARGET_ARCH_ARM FLAG_enable_embedded_constant_pool ? (kMaxAllocatableGeneralRegisterCount - 1) : kMaxAllocatableGeneralRegisterCount, CpuFeatures::IsSupported(VFP32DREGS) ? kMaxAllocatableDoubleRegisterCount : (ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(REGISTER_COUNT) 0), #elif V8_TARGET_ARCH_ARM64 kMaxAllocatableGeneralRegisterCount, kMaxAllocatableDoubleRegisterCount, #elif V8_TARGET_ARCH_MIPS kMaxAllocatableGeneralRegisterCount, kMaxAllocatableDoubleRegisterCount, #elif V8_TARGET_ARCH_MIPS64 kMaxAllocatableGeneralRegisterCount, kMaxAllocatableDoubleRegisterCount, #elif V8_TARGET_ARCH_PPC kMaxAllocatableGeneralRegisterCount, kMaxAllocatableDoubleRegisterCount, #elif V8_TARGET_ARCH_S390 kMaxAllocatableGeneralRegisterCount, kMaxAllocatableDoubleRegisterCount, #else #error Unsupported target architecture. #endif kAllocatableGeneralCodes, kAllocatableDoubleCodes, kSimpleFPAliasing ? AliasingKind::OVERLAP : AliasingKind::COMBINE, kGeneralRegisterNames, kFloatRegisterNames, kDoubleRegisterNames) { } }; template struct RegisterConfigurationInitializer { static void Construct(ArchDefaultRegisterConfiguration* config) { new (config) ArchDefaultRegisterConfiguration(compiler); } }; static base::LazyInstance>::type kDefaultRegisterConfigurationForCrankshaft = LAZY_INSTANCE_INITIALIZER; static base::LazyInstance>::type kDefaultRegisterConfigurationForTurboFan = LAZY_INSTANCE_INITIALIZER; } // namespace const RegisterConfiguration* RegisterConfiguration::Crankshaft() { return &kDefaultRegisterConfigurationForCrankshaft.Get(); } const RegisterConfiguration* RegisterConfiguration::Turbofan() { return &kDefaultRegisterConfigurationForTurboFan.Get(); } RegisterConfiguration::RegisterConfiguration( int num_general_registers, int num_double_registers, int num_allocatable_general_registers, int num_allocatable_double_registers, const int* allocatable_general_codes, const int* allocatable_double_codes, AliasingKind fp_aliasing_kind, const char* const* general_register_names, const char* const* float_register_names, const char* const* double_register_names) : num_general_registers_(num_general_registers), num_float_registers_(0), num_double_registers_(num_double_registers), num_allocatable_general_registers_(num_allocatable_general_registers), num_allocatable_double_registers_(num_allocatable_double_registers), num_allocatable_float_registers_(0), allocatable_general_codes_mask_(0), allocatable_double_codes_mask_(0), allocatable_float_codes_mask_(0), allocatable_general_codes_(allocatable_general_codes), allocatable_double_codes_(allocatable_double_codes), fp_aliasing_kind_(fp_aliasing_kind), general_register_names_(general_register_names), float_register_names_(float_register_names), double_register_names_(double_register_names) { DCHECK(num_general_registers_ <= RegisterConfiguration::kMaxGeneralRegisters); DCHECK(num_double_registers_ <= RegisterConfiguration::kMaxFPRegisters); for (int i = 0; i < num_allocatable_general_registers_; ++i) { allocatable_general_codes_mask_ |= (1 << allocatable_general_codes_[i]); } for (int i = 0; i < num_allocatable_double_registers_; ++i) { allocatable_double_codes_mask_ |= (1 << allocatable_double_codes_[i]); } if (fp_aliasing_kind_ == COMBINE) { num_float_registers_ = num_double_registers_ * 2 <= kMaxFPRegisters ? num_double_registers_ * 2 : kMaxFPRegisters; num_allocatable_float_registers_ = 0; for (int i = 0; i < num_allocatable_double_registers_; i++) { int base_code = allocatable_double_codes_[i] * 2; if (base_code >= kMaxFPRegisters) continue; allocatable_float_codes_[num_allocatable_float_registers_++] = base_code; allocatable_float_codes_[num_allocatable_float_registers_++] = base_code + 1; allocatable_float_codes_mask_ |= (0x3 << base_code); } } else { DCHECK(fp_aliasing_kind_ == OVERLAP); num_float_registers_ = num_double_registers_; num_allocatable_float_registers_ = num_allocatable_double_registers_; for (int i = 0; i < num_allocatable_float_registers_; ++i) { allocatable_float_codes_[i] = allocatable_double_codes_[i]; } allocatable_float_codes_mask_ = allocatable_double_codes_mask_; } } int RegisterConfiguration::GetAliases(MachineRepresentation rep, int index, MachineRepresentation other_rep, int* alias_base_index) const { DCHECK(fp_aliasing_kind_ == COMBINE); DCHECK(rep == MachineRepresentation::kFloat32 || rep == MachineRepresentation::kFloat64); DCHECK(other_rep == MachineRepresentation::kFloat32 || other_rep == MachineRepresentation::kFloat64); if (rep == other_rep) { *alias_base_index = index; return 1; } if (rep == MachineRepresentation::kFloat32) { DCHECK(other_rep == MachineRepresentation::kFloat64); DCHECK(index < num_allocatable_float_registers_); *alias_base_index = index / 2; return 1; } DCHECK(rep == MachineRepresentation::kFloat64); DCHECK(other_rep == MachineRepresentation::kFloat32); if (index * 2 >= kMaxFPRegisters) { // Alias indices are out of float register range. return 0; } *alias_base_index = index * 2; return 2; } bool RegisterConfiguration::AreAliases(MachineRepresentation rep, int index, MachineRepresentation other_rep, int other_index) const { DCHECK(fp_aliasing_kind_ == COMBINE); DCHECK(rep == MachineRepresentation::kFloat32 || rep == MachineRepresentation::kFloat64); DCHECK(other_rep == MachineRepresentation::kFloat32 || other_rep == MachineRepresentation::kFloat64); if (rep == other_rep) { return index == other_index; } if (rep == MachineRepresentation::kFloat32) { DCHECK(other_rep == MachineRepresentation::kFloat64); return index / 2 == other_index; } DCHECK(rep == MachineRepresentation::kFloat64); DCHECK(other_rep == MachineRepresentation::kFloat32); if (index * 2 >= kMaxFPRegisters) { // Alias indices are out of float register range. return false; } return index == other_index / 2; } #undef REGISTER_COUNT } // namespace internal } // namespace v8