• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
9 namespace v8 {
10 namespace internal {
11 
12 namespace {
13 
14 #define REGISTER_COUNT(R) 1 +
15 static const int kMaxAllocatableGeneralRegisterCount =
16     ALLOCATABLE_GENERAL_REGISTERS(REGISTER_COUNT)0;
17 static const int kMaxAllocatableDoubleRegisterCount =
18     ALLOCATABLE_DOUBLE_REGISTERS(REGISTER_COUNT)0;
19 
20 static const int kAllocatableGeneralCodes[] = {
21 #define REGISTER_CODE(R) kRegCode_##R,
22     ALLOCATABLE_GENERAL_REGISTERS(REGISTER_CODE)};
23 #undef REGISTER_CODE
24 
25 #define REGISTER_CODE(R) kDoubleCode_##R,
26 static const int kAllocatableDoubleCodes[] = {
27     ALLOCATABLE_DOUBLE_REGISTERS(REGISTER_CODE)};
28 #if V8_TARGET_ARCH_ARM
29 static const int kAllocatableNoVFP32DoubleCodes[] = {
30     ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(REGISTER_CODE)};
31 #endif  // V8_TARGET_ARCH_ARM
32 #undef REGISTER_CODE
33 
34 static const char* const kGeneralRegisterNames[] = {
35 #define REGISTER_NAME(R) #R,
36     GENERAL_REGISTERS(REGISTER_NAME)
37 #undef REGISTER_NAME
38 };
39 
40 static const char* const kFloatRegisterNames[] = {
41 #define REGISTER_NAME(R) #R,
42     FLOAT_REGISTERS(REGISTER_NAME)
43 #undef REGISTER_NAME
44 };
45 
46 static const char* const kDoubleRegisterNames[] = {
47 #define REGISTER_NAME(R) #R,
48     DOUBLE_REGISTERS(REGISTER_NAME)
49 #undef REGISTER_NAME
50 };
51 
52 static const char* const kSimd128RegisterNames[] = {
53 #define REGISTER_NAME(R) #R,
54     SIMD128_REGISTERS(REGISTER_NAME)
55 #undef REGISTER_NAME
56 };
57 
58 STATIC_ASSERT(RegisterConfiguration::kMaxGeneralRegisters >=
59               Register::kNumRegisters);
60 STATIC_ASSERT(RegisterConfiguration::kMaxFPRegisters >=
61               FloatRegister::kNumRegisters);
62 STATIC_ASSERT(RegisterConfiguration::kMaxFPRegisters >=
63               DoubleRegister::kNumRegisters);
64 STATIC_ASSERT(RegisterConfiguration::kMaxFPRegisters >=
65               Simd128Register::kNumRegisters);
66 
get_num_allocatable_double_registers()67 static int get_num_allocatable_double_registers() {
68   return
69 #if V8_TARGET_ARCH_IA32
70       kMaxAllocatableDoubleRegisterCount;
71 #elif V8_TARGET_ARCH_X64
72       kMaxAllocatableDoubleRegisterCount;
73 #elif V8_TARGET_ARCH_ARM
74       CpuFeatures::IsSupported(VFP32DREGS)
75           ? kMaxAllocatableDoubleRegisterCount
76           : (ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(REGISTER_COUNT) 0);
77 #elif V8_TARGET_ARCH_ARM64
78       kMaxAllocatableDoubleRegisterCount;
79 #elif V8_TARGET_ARCH_MIPS
80       kMaxAllocatableDoubleRegisterCount;
81 #elif V8_TARGET_ARCH_MIPS64
82       kMaxAllocatableDoubleRegisterCount;
83 #elif V8_TARGET_ARCH_PPC
84       kMaxAllocatableDoubleRegisterCount;
85 #elif V8_TARGET_ARCH_S390
86       kMaxAllocatableDoubleRegisterCount;
87 #else
88 #error Unsupported target architecture.
89 #endif
90 }
91 
get_allocatable_double_codes()92 static const int* get_allocatable_double_codes() {
93   return
94 #if V8_TARGET_ARCH_ARM
95       CpuFeatures::IsSupported(VFP32DREGS) ? kAllocatableDoubleCodes
96                                            : kAllocatableNoVFP32DoubleCodes;
97 #else
98       kAllocatableDoubleCodes;
99 #endif
100 }
101 
102 class ArchDefaultRegisterConfiguration : public RegisterConfiguration {
103  public:
ArchDefaultRegisterConfiguration()104   ArchDefaultRegisterConfiguration()
105       : RegisterConfiguration(
106             Register::kNumRegisters, DoubleRegister::kNumRegisters,
107             kMaxAllocatableGeneralRegisterCount,
108             get_num_allocatable_double_registers(), kAllocatableGeneralCodes,
109             get_allocatable_double_codes(),
110             kSimpleFPAliasing ? AliasingKind::OVERLAP : AliasingKind::COMBINE,
111             kGeneralRegisterNames, kFloatRegisterNames, kDoubleRegisterNames,
112             kSimd128RegisterNames) {}
113 };
114 
115 struct RegisterConfigurationInitializer {
Constructv8::internal::__anone4b9c64c0111::RegisterConfigurationInitializer116   static void Construct(void* config) {
117     new (config) ArchDefaultRegisterConfiguration();
118   }
119 };
120 
121 static base::LazyInstance<ArchDefaultRegisterConfiguration,
122                           RegisterConfigurationInitializer>::type
123     kDefaultRegisterConfiguration = LAZY_INSTANCE_INITIALIZER;
124 
125 // Allocatable registers with the masking register removed.
126 class ArchDefaultPoisoningRegisterConfiguration : public RegisterConfiguration {
127  public:
ArchDefaultPoisoningRegisterConfiguration()128   ArchDefaultPoisoningRegisterConfiguration()
129       : RegisterConfiguration(
130             Register::kNumRegisters, DoubleRegister::kNumRegisters,
131             kMaxAllocatableGeneralRegisterCount - 1,
132             get_num_allocatable_double_registers(),
133             InitializeGeneralRegisterCodes(), get_allocatable_double_codes(),
134             kSimpleFPAliasing ? AliasingKind::OVERLAP : AliasingKind::COMBINE,
135             kGeneralRegisterNames, kFloatRegisterNames, kDoubleRegisterNames,
136             kSimd128RegisterNames) {}
137 
138  private:
InitializeGeneralRegisterCodes()139   static const int* InitializeGeneralRegisterCodes() {
140     int filtered_index = 0;
141     for (int i = 0; i < kMaxAllocatableGeneralRegisterCount; ++i) {
142       if (kAllocatableGeneralCodes[i] != kSpeculationPoisonRegister.code()) {
143         allocatable_general_codes_[filtered_index] =
144             kAllocatableGeneralCodes[i];
145         filtered_index++;
146       }
147     }
148     DCHECK_EQ(filtered_index, kMaxAllocatableGeneralRegisterCount - 1);
149     return allocatable_general_codes_;
150   }
151 
152   static int
153       allocatable_general_codes_[kMaxAllocatableGeneralRegisterCount - 1];
154 };
155 
156 int ArchDefaultPoisoningRegisterConfiguration::allocatable_general_codes_
157     [kMaxAllocatableGeneralRegisterCount - 1];
158 
159 struct PoisoningRegisterConfigurationInitializer {
Constructv8::internal::__anone4b9c64c0111::PoisoningRegisterConfigurationInitializer160   static void Construct(void* config) {
161     new (config) ArchDefaultPoisoningRegisterConfiguration();
162   }
163 };
164 
165 static base::LazyInstance<ArchDefaultPoisoningRegisterConfiguration,
166                           PoisoningRegisterConfigurationInitializer>::type
167     kDefaultPoisoningRegisterConfiguration = LAZY_INSTANCE_INITIALIZER;
168 
169 #if defined(V8_TARGET_ARCH_IA32) && defined(V8_EMBEDDED_BUILTINS)
170 // Allocatable registers with the root register removed.
171 // TODO(v8:6666): Once all builtins have been migrated, we could remove this
172 // configuration and remove kRootRegister from ALLOCATABLE_GENERAL_REGISTERS
173 // instead.
174 class ArchPreserveRootIA32RegisterConfiguration : public RegisterConfiguration {
175  public:
ArchPreserveRootIA32RegisterConfiguration()176   ArchPreserveRootIA32RegisterConfiguration()
177       : RegisterConfiguration(
178             Register::kNumRegisters, DoubleRegister::kNumRegisters,
179             kMaxAllocatableGeneralRegisterCount - 1,
180             get_num_allocatable_double_registers(),
181             InitializeGeneralRegisterCodes(), get_allocatable_double_codes(),
182             kSimpleFPAliasing ? AliasingKind::OVERLAP : AliasingKind::COMBINE,
183             kGeneralRegisterNames, kFloatRegisterNames, kDoubleRegisterNames,
184             kSimd128RegisterNames) {}
185 
186  private:
InitializeGeneralRegisterCodes()187   static const int* InitializeGeneralRegisterCodes() {
188     int filtered_index = 0;
189     for (int i = 0; i < kMaxAllocatableGeneralRegisterCount; ++i) {
190       if (kAllocatableGeneralCodes[i] != kRootRegister.code()) {
191         allocatable_general_codes_[filtered_index] =
192             kAllocatableGeneralCodes[i];
193         filtered_index++;
194       }
195     }
196     DCHECK_EQ(filtered_index, kMaxAllocatableGeneralRegisterCount - 1);
197     return allocatable_general_codes_;
198   }
199 
200   static int
201       allocatable_general_codes_[kMaxAllocatableGeneralRegisterCount - 1];
202 };
203 
204 int ArchPreserveRootIA32RegisterConfiguration::allocatable_general_codes_
205     [kMaxAllocatableGeneralRegisterCount - 1];
206 
207 struct PreserveRootIA32RegisterConfigurationInitializer {
Constructv8::internal::__anone4b9c64c0111::PreserveRootIA32RegisterConfigurationInitializer208   static void Construct(void* config) {
209     new (config) ArchPreserveRootIA32RegisterConfiguration();
210   }
211 };
212 
213 static base::LazyInstance<ArchPreserveRootIA32RegisterConfiguration,
214                           PreserveRootIA32RegisterConfigurationInitializer>::
215     type kPreserveRootIA32RegisterConfiguration = LAZY_INSTANCE_INITIALIZER;
216 #endif  // defined(V8_TARGET_ARCH_IA32) && defined(V8_EMBEDDED_BUILTINS)
217 
218 // RestrictedRegisterConfiguration uses the subset of allocatable general
219 // registers the architecture support, which results into generating assembly
220 // to use less registers. Currently, it's only used by RecordWrite code stub.
221 class RestrictedRegisterConfiguration : public RegisterConfiguration {
222  public:
RestrictedRegisterConfiguration(int num_allocatable_general_registers,std::unique_ptr<int[]> allocatable_general_register_codes,std::unique_ptr<char const * []> allocatable_general_register_names)223   RestrictedRegisterConfiguration(
224       int num_allocatable_general_registers,
225       std::unique_ptr<int[]> allocatable_general_register_codes,
226       std::unique_ptr<char const* []> allocatable_general_register_names)
227       : RegisterConfiguration(
228             Register::kNumRegisters, DoubleRegister::kNumRegisters,
229             num_allocatable_general_registers,
230             get_num_allocatable_double_registers(),
231             allocatable_general_register_codes.get(),
232             get_allocatable_double_codes(),
233             kSimpleFPAliasing ? AliasingKind::OVERLAP : AliasingKind::COMBINE,
234             kGeneralRegisterNames, kFloatRegisterNames, kDoubleRegisterNames,
235             kSimd128RegisterNames),
236         allocatable_general_register_codes_(
237             std::move(allocatable_general_register_codes)),
238         allocatable_general_register_names_(
239             std::move(allocatable_general_register_names)) {
240     for (int i = 0; i < num_allocatable_general_registers; ++i) {
241       DCHECK(
242           IsAllocatableGeneralRegister(allocatable_general_register_codes_[i]));
243     }
244   }
245 
IsAllocatableGeneralRegister(int code)246   bool IsAllocatableGeneralRegister(int code) {
247     for (int i = 0; i < kMaxAllocatableGeneralRegisterCount; ++i) {
248       if (code == kAllocatableGeneralCodes[i]) {
249         return true;
250       }
251     }
252     return false;
253   }
254 
255  private:
256   std::unique_ptr<int[]> allocatable_general_register_codes_;
257   std::unique_ptr<char const* []> allocatable_general_register_names_;
258 };
259 
260 }  // namespace
261 
Default()262 const RegisterConfiguration* RegisterConfiguration::Default() {
263   return &kDefaultRegisterConfiguration.Get();
264 }
265 
Poisoning()266 const RegisterConfiguration* RegisterConfiguration::Poisoning() {
267   return &kDefaultPoisoningRegisterConfiguration.Get();
268 }
269 
270 #if defined(V8_TARGET_ARCH_IA32) && defined(V8_EMBEDDED_BUILTINS)
PreserveRootIA32()271 const RegisterConfiguration* RegisterConfiguration::PreserveRootIA32() {
272   return &kPreserveRootIA32RegisterConfiguration.Get();
273 }
274 #endif  // defined(V8_TARGET_ARCH_IA32) && defined(V8_EMBEDDED_BUILTINS)
275 
RestrictGeneralRegisters(RegList registers)276 const RegisterConfiguration* RegisterConfiguration::RestrictGeneralRegisters(
277     RegList registers) {
278   int num = NumRegs(registers);
279   std::unique_ptr<int[]> codes{new int[num]};
280   std::unique_ptr<char const* []> names { new char const*[num] };
281   int counter = 0;
282   for (int i = 0; i < Default()->num_allocatable_general_registers(); ++i) {
283     auto reg = Register::from_code(Default()->GetAllocatableGeneralCode(i));
284     if (reg.bit() & registers) {
285       DCHECK(counter < num);
286       codes[counter] = reg.code();
287       names[counter] = Default()->GetGeneralRegisterName(i);
288       counter++;
289     }
290   }
291 
292   return new RestrictedRegisterConfiguration(num, std::move(codes),
293                                              std::move(names));
294 }
295 
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,const char * const * simd128_register_names)296 RegisterConfiguration::RegisterConfiguration(
297     int num_general_registers, int num_double_registers,
298     int num_allocatable_general_registers, int num_allocatable_double_registers,
299     const int* allocatable_general_codes, const int* allocatable_double_codes,
300     AliasingKind fp_aliasing_kind, const char* const* general_register_names,
301     const char* const* float_register_names,
302     const char* const* double_register_names,
303     const char* const* simd128_register_names)
304     : num_general_registers_(num_general_registers),
305       num_float_registers_(0),
306       num_double_registers_(num_double_registers),
307       num_simd128_registers_(0),
308       num_allocatable_general_registers_(num_allocatable_general_registers),
309       num_allocatable_float_registers_(0),
310       num_allocatable_double_registers_(num_allocatable_double_registers),
311       num_allocatable_simd128_registers_(0),
312       allocatable_general_codes_mask_(0),
313       allocatable_float_codes_mask_(0),
314       allocatable_double_codes_mask_(0),
315       allocatable_simd128_codes_mask_(0),
316       allocatable_general_codes_(allocatable_general_codes),
317       allocatable_double_codes_(allocatable_double_codes),
318       fp_aliasing_kind_(fp_aliasing_kind),
319       general_register_names_(general_register_names),
320       float_register_names_(float_register_names),
321       double_register_names_(double_register_names),
322       simd128_register_names_(simd128_register_names) {
323   DCHECK_LE(num_general_registers_,
324             RegisterConfiguration::kMaxGeneralRegisters);
325   DCHECK_LE(num_double_registers_, RegisterConfiguration::kMaxFPRegisters);
326   for (int i = 0; i < num_allocatable_general_registers_; ++i) {
327     allocatable_general_codes_mask_ |= (1 << allocatable_general_codes_[i]);
328   }
329   for (int i = 0; i < num_allocatable_double_registers_; ++i) {
330     allocatable_double_codes_mask_ |= (1 << allocatable_double_codes_[i]);
331   }
332 
333   if (fp_aliasing_kind_ == COMBINE) {
334     num_float_registers_ = num_double_registers_ * 2 <= kMaxFPRegisters
335                                ? num_double_registers_ * 2
336                                : kMaxFPRegisters;
337     num_allocatable_float_registers_ = 0;
338     for (int i = 0; i < num_allocatable_double_registers_; i++) {
339       int base_code = allocatable_double_codes_[i] * 2;
340       if (base_code >= kMaxFPRegisters) continue;
341       allocatable_float_codes_[num_allocatable_float_registers_++] = base_code;
342       allocatable_float_codes_[num_allocatable_float_registers_++] =
343           base_code + 1;
344       allocatable_float_codes_mask_ |= (0x3 << base_code);
345     }
346     num_simd128_registers_ = num_double_registers_ / 2;
347     num_allocatable_simd128_registers_ = 0;
348     int last_simd128_code = allocatable_double_codes_[0] / 2;
349     for (int i = 1; i < num_allocatable_double_registers_; i++) {
350       int next_simd128_code = allocatable_double_codes_[i] / 2;
351       // This scheme assumes allocatable_double_codes_ are strictly increasing.
352       DCHECK_GE(next_simd128_code, last_simd128_code);
353       if (last_simd128_code == next_simd128_code) {
354         allocatable_simd128_codes_[num_allocatable_simd128_registers_++] =
355             next_simd128_code;
356         allocatable_simd128_codes_mask_ |= (0x1 << next_simd128_code);
357       }
358       last_simd128_code = next_simd128_code;
359     }
360   } else {
361     DCHECK(fp_aliasing_kind_ == OVERLAP);
362     num_float_registers_ = num_simd128_registers_ = num_double_registers_;
363     num_allocatable_float_registers_ = num_allocatable_simd128_registers_ =
364         num_allocatable_double_registers_;
365     for (int i = 0; i < num_allocatable_float_registers_; ++i) {
366       allocatable_float_codes_[i] = allocatable_simd128_codes_[i] =
367           allocatable_double_codes_[i];
368     }
369     allocatable_float_codes_mask_ = allocatable_simd128_codes_mask_ =
370         allocatable_double_codes_mask_;
371   }
372 }
373 
GetGeneralOrSpecialRegisterName(int code) const374 const char* RegisterConfiguration::GetGeneralOrSpecialRegisterName(
375     int code) const {
376   if (code < num_general_registers_) return GetGeneralRegisterName(code);
377   return Assembler::GetSpecialRegisterName(code);
378 }
379 
380 // Assert that kFloat32, kFloat64, and kSimd128 are consecutive values.
381 STATIC_ASSERT(static_cast<int>(MachineRepresentation::kSimd128) ==
382               static_cast<int>(MachineRepresentation::kFloat64) + 1);
383 STATIC_ASSERT(static_cast<int>(MachineRepresentation::kFloat64) ==
384               static_cast<int>(MachineRepresentation::kFloat32) + 1);
385 
GetAliases(MachineRepresentation rep,int index,MachineRepresentation other_rep,int * alias_base_index) const386 int RegisterConfiguration::GetAliases(MachineRepresentation rep, int index,
387                                       MachineRepresentation other_rep,
388                                       int* alias_base_index) const {
389   DCHECK(fp_aliasing_kind_ == COMBINE);
390   DCHECK(IsFloatingPoint(rep) && IsFloatingPoint(other_rep));
391   if (rep == other_rep) {
392     *alias_base_index = index;
393     return 1;
394   }
395   int rep_int = static_cast<int>(rep);
396   int other_rep_int = static_cast<int>(other_rep);
397   if (rep_int > other_rep_int) {
398     int shift = rep_int - other_rep_int;
399     int base_index = index << shift;
400     if (base_index >= kMaxFPRegisters) {
401       // Alias indices would be out of FP register range.
402       return 0;
403     }
404     *alias_base_index = base_index;
405     return 1 << shift;
406   }
407   int shift = other_rep_int - rep_int;
408   *alias_base_index = index >> shift;
409   return 1;
410 }
411 
AreAliases(MachineRepresentation rep,int index,MachineRepresentation other_rep,int other_index) const412 bool RegisterConfiguration::AreAliases(MachineRepresentation rep, int index,
413                                        MachineRepresentation other_rep,
414                                        int other_index) const {
415   DCHECK(fp_aliasing_kind_ == COMBINE);
416   DCHECK(IsFloatingPoint(rep) && IsFloatingPoint(other_rep));
417   if (rep == other_rep) {
418     return index == other_index;
419   }
420   int rep_int = static_cast<int>(rep);
421   int other_rep_int = static_cast<int>(other_rep);
422   if (rep_int > other_rep_int) {
423     int shift = rep_int - other_rep_int;
424     return index == other_index >> shift;
425   }
426   int shift = other_rep_int - rep_int;
427   return index >> shift == other_index;
428 }
429 
430 }  // namespace internal
431 }  // namespace v8
432