1// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/register-configuration.h"
6#include "src/globals.h"
7#include "src/macro-assembler.h"
8
9namespace v8 {
10namespace internal {
11
12namespace {
13
14#define REGISTER_COUNT(R) 1 +
15static const int kMaxAllocatableGeneralRegisterCount =
16    ALLOCATABLE_GENERAL_REGISTERS(REGISTER_COUNT)0;
17static const int kMaxAllocatableDoubleRegisterCount =
18    ALLOCATABLE_DOUBLE_REGISTERS(REGISTER_COUNT)0;
19
20static const int kAllocatableGeneralCodes[] = {
21#define REGISTER_CODE(R) Register::kCode_##R,
22    ALLOCATABLE_GENERAL_REGISTERS(REGISTER_CODE)};
23#undef REGISTER_CODE
24
25static const int kAllocatableDoubleCodes[] = {
26#define REGISTER_CODE(R) DoubleRegister::kCode_##R,
27    ALLOCATABLE_DOUBLE_REGISTERS(REGISTER_CODE)};
28#undef REGISTER_CODE
29
30static const char* const kGeneralRegisterNames[] = {
31#define REGISTER_NAME(R) #R,
32    GENERAL_REGISTERS(REGISTER_NAME)
33#undef REGISTER_NAME
34};
35
36static const char* const kFloatRegisterNames[] = {
37#define REGISTER_NAME(R) #R,
38    FLOAT_REGISTERS(REGISTER_NAME)
39#undef REGISTER_NAME
40};
41
42static const char* const kDoubleRegisterNames[] = {
43#define REGISTER_NAME(R) #R,
44    DOUBLE_REGISTERS(REGISTER_NAME)
45#undef REGISTER_NAME
46};
47
48static const char* const kSimd128RegisterNames[] = {
49#define REGISTER_NAME(R) #R,
50    SIMD128_REGISTERS(REGISTER_NAME)
51#undef REGISTER_NAME
52};
53
54STATIC_ASSERT(RegisterConfiguration::kMaxGeneralRegisters >=
55              Register::kNumRegisters);
56STATIC_ASSERT(RegisterConfiguration::kMaxFPRegisters >=
57              FloatRegister::kMaxNumRegisters);
58STATIC_ASSERT(RegisterConfiguration::kMaxFPRegisters >=
59              DoubleRegister::kMaxNumRegisters);
60STATIC_ASSERT(RegisterConfiguration::kMaxFPRegisters >=
61              Simd128Register::kMaxNumRegisters);
62
63enum CompilerSelector { CRANKSHAFT, TURBOFAN };
64
65class ArchDefaultRegisterConfiguration : public RegisterConfiguration {
66 public:
67  explicit ArchDefaultRegisterConfiguration(CompilerSelector compiler)
68      : RegisterConfiguration(
69            Register::kNumRegisters, DoubleRegister::kMaxNumRegisters,
70#if V8_TARGET_ARCH_IA32
71            kMaxAllocatableGeneralRegisterCount,
72            kMaxAllocatableDoubleRegisterCount,
73#elif V8_TARGET_ARCH_X87
74            kMaxAllocatableGeneralRegisterCount,
75            compiler == TURBOFAN ? 1 : kMaxAllocatableDoubleRegisterCount,
76#elif V8_TARGET_ARCH_X64
77            kMaxAllocatableGeneralRegisterCount,
78            kMaxAllocatableDoubleRegisterCount,
79#elif V8_TARGET_ARCH_ARM
80            FLAG_enable_embedded_constant_pool
81                ? (kMaxAllocatableGeneralRegisterCount - 1)
82                : kMaxAllocatableGeneralRegisterCount,
83            CpuFeatures::IsSupported(VFP32DREGS)
84                ? kMaxAllocatableDoubleRegisterCount
85                : (ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(REGISTER_COUNT) 0),
86#elif V8_TARGET_ARCH_ARM64
87            kMaxAllocatableGeneralRegisterCount,
88            kMaxAllocatableDoubleRegisterCount,
89#elif V8_TARGET_ARCH_MIPS
90            kMaxAllocatableGeneralRegisterCount,
91            kMaxAllocatableDoubleRegisterCount,
92#elif V8_TARGET_ARCH_MIPS64
93            kMaxAllocatableGeneralRegisterCount,
94            kMaxAllocatableDoubleRegisterCount,
95#elif V8_TARGET_ARCH_PPC
96            kMaxAllocatableGeneralRegisterCount,
97            kMaxAllocatableDoubleRegisterCount,
98#elif V8_TARGET_ARCH_S390
99            kMaxAllocatableGeneralRegisterCount,
100            kMaxAllocatableDoubleRegisterCount,
101#else
102#error Unsupported target architecture.
103#endif
104            kAllocatableGeneralCodes, kAllocatableDoubleCodes,
105            kSimpleFPAliasing ? AliasingKind::OVERLAP : AliasingKind::COMBINE,
106            kGeneralRegisterNames, kFloatRegisterNames, kDoubleRegisterNames,
107            kSimd128RegisterNames) {
108  }
109};
110
111template <CompilerSelector compiler>
112struct RegisterConfigurationInitializer {
113  static void Construct(ArchDefaultRegisterConfiguration* config) {
114    new (config) ArchDefaultRegisterConfiguration(compiler);
115  }
116};
117
118static base::LazyInstance<ArchDefaultRegisterConfiguration,
119                          RegisterConfigurationInitializer<CRANKSHAFT>>::type
120    kDefaultRegisterConfigurationForCrankshaft = LAZY_INSTANCE_INITIALIZER;
121
122static base::LazyInstance<ArchDefaultRegisterConfiguration,
123                          RegisterConfigurationInitializer<TURBOFAN>>::type
124    kDefaultRegisterConfigurationForTurboFan = LAZY_INSTANCE_INITIALIZER;
125
126}  // namespace
127
128const RegisterConfiguration* RegisterConfiguration::Crankshaft() {
129  return &kDefaultRegisterConfigurationForCrankshaft.Get();
130}
131
132const RegisterConfiguration* RegisterConfiguration::Turbofan() {
133  return &kDefaultRegisterConfigurationForTurboFan.Get();
134}
135
136RegisterConfiguration::RegisterConfiguration(
137    int num_general_registers, int num_double_registers,
138    int num_allocatable_general_registers, int num_allocatable_double_registers,
139    const int* allocatable_general_codes, const int* allocatable_double_codes,
140    AliasingKind fp_aliasing_kind, const char* const* general_register_names,
141    const char* const* float_register_names,
142    const char* const* double_register_names,
143    const char* const* simd128_register_names)
144    : num_general_registers_(num_general_registers),
145      num_float_registers_(0),
146      num_double_registers_(num_double_registers),
147      num_simd128_registers_(0),
148      num_allocatable_general_registers_(num_allocatable_general_registers),
149      num_allocatable_float_registers_(0),
150      num_allocatable_double_registers_(num_allocatable_double_registers),
151      num_allocatable_simd128_registers_(0),
152      allocatable_general_codes_mask_(0),
153      allocatable_float_codes_mask_(0),
154      allocatable_double_codes_mask_(0),
155      allocatable_simd128_codes_mask_(0),
156      allocatable_general_codes_(allocatable_general_codes),
157      allocatable_double_codes_(allocatable_double_codes),
158      fp_aliasing_kind_(fp_aliasing_kind),
159      general_register_names_(general_register_names),
160      float_register_names_(float_register_names),
161      double_register_names_(double_register_names),
162      simd128_register_names_(simd128_register_names) {
163  DCHECK(num_general_registers_ <= RegisterConfiguration::kMaxGeneralRegisters);
164  DCHECK(num_double_registers_ <= RegisterConfiguration::kMaxFPRegisters);
165  for (int i = 0; i < num_allocatable_general_registers_; ++i) {
166    allocatable_general_codes_mask_ |= (1 << allocatable_general_codes_[i]);
167  }
168  for (int i = 0; i < num_allocatable_double_registers_; ++i) {
169    allocatable_double_codes_mask_ |= (1 << allocatable_double_codes_[i]);
170  }
171
172  if (fp_aliasing_kind_ == COMBINE) {
173    num_float_registers_ = num_double_registers_ * 2 <= kMaxFPRegisters
174                               ? num_double_registers_ * 2
175                               : kMaxFPRegisters;
176    num_allocatable_float_registers_ = 0;
177    for (int i = 0; i < num_allocatable_double_registers_; i++) {
178      int base_code = allocatable_double_codes_[i] * 2;
179      if (base_code >= kMaxFPRegisters) continue;
180      allocatable_float_codes_[num_allocatable_float_registers_++] = base_code;
181      allocatable_float_codes_[num_allocatable_float_registers_++] =
182          base_code + 1;
183      allocatable_float_codes_mask_ |= (0x3 << base_code);
184    }
185    num_simd128_registers_ = num_double_registers_ / 2;
186    num_allocatable_simd128_registers_ = 0;
187    int last_simd128_code = allocatable_double_codes_[0] / 2;
188    for (int i = 1; i < num_allocatable_double_registers_; i++) {
189      int next_simd128_code = allocatable_double_codes_[i] / 2;
190      // This scheme assumes allocatable_double_codes_ are strictly increasing.
191      DCHECK_GE(next_simd128_code, last_simd128_code);
192      if (last_simd128_code == next_simd128_code) {
193        allocatable_simd128_codes_[num_allocatable_simd128_registers_++] =
194            next_simd128_code;
195        allocatable_simd128_codes_mask_ |= (0x1 << next_simd128_code);
196      }
197      last_simd128_code = next_simd128_code;
198    }
199  } else {
200    DCHECK(fp_aliasing_kind_ == OVERLAP);
201    num_float_registers_ = num_simd128_registers_ = num_double_registers_;
202    num_allocatable_float_registers_ = num_allocatable_simd128_registers_ =
203        num_allocatable_double_registers_;
204    for (int i = 0; i < num_allocatable_float_registers_; ++i) {
205      allocatable_float_codes_[i] = allocatable_simd128_codes_[i] =
206          allocatable_double_codes_[i];
207    }
208    allocatable_float_codes_mask_ = allocatable_simd128_codes_mask_ =
209        allocatable_double_codes_mask_;
210  }
211}
212
213// Assert that kFloat32, kFloat64, and kSimd128 are consecutive values.
214STATIC_ASSERT(static_cast<int>(MachineRepresentation::kSimd128) ==
215              static_cast<int>(MachineRepresentation::kFloat64) + 1);
216STATIC_ASSERT(static_cast<int>(MachineRepresentation::kFloat64) ==
217              static_cast<int>(MachineRepresentation::kFloat32) + 1);
218
219int RegisterConfiguration::GetAliases(MachineRepresentation rep, int index,
220                                      MachineRepresentation other_rep,
221                                      int* alias_base_index) const {
222  DCHECK(fp_aliasing_kind_ == COMBINE);
223  DCHECK(IsFloatingPoint(rep) && IsFloatingPoint(other_rep));
224  if (rep == other_rep) {
225    *alias_base_index = index;
226    return 1;
227  }
228  int rep_int = static_cast<int>(rep);
229  int other_rep_int = static_cast<int>(other_rep);
230  if (rep_int > other_rep_int) {
231    int shift = rep_int - other_rep_int;
232    int base_index = index << shift;
233    if (base_index >= kMaxFPRegisters) {
234      // Alias indices would be out of FP register range.
235      return 0;
236    }
237    *alias_base_index = base_index;
238    return 1 << shift;
239  }
240  int shift = other_rep_int - rep_int;
241  *alias_base_index = index >> shift;
242  return 1;
243}
244
245bool RegisterConfiguration::AreAliases(MachineRepresentation rep, int index,
246                                       MachineRepresentation other_rep,
247                                       int other_index) const {
248  DCHECK(fp_aliasing_kind_ == COMBINE);
249  DCHECK(IsFloatingPoint(rep) && IsFloatingPoint(other_rep));
250  if (rep == other_rep) {
251    return index == other_index;
252  }
253  int rep_int = static_cast<int>(rep);
254  int other_rep_int = static_cast<int>(other_rep);
255  if (rep_int > other_rep_int) {
256    int shift = rep_int - other_rep_int;
257    return index == other_index >> shift;
258  }
259  int shift = other_rep_int - rep_int;
260  return index >> shift == other_index;
261}
262
263#undef REGISTER_COUNT
264
265}  // namespace internal
266}  // namespace v8
267