• 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/codegen/register-configuration.h"
6 
7 #include "src/base/lazy-instance.h"
8 #include "src/codegen/cpu-features.h"
9 #include "src/codegen/register.h"
10 #include "src/common/globals.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 namespace {
16 
17 #define REGISTER_COUNT(R) 1 +
18 static const int kMaxAllocatableGeneralRegisterCount =
19     ALLOCATABLE_GENERAL_REGISTERS(REGISTER_COUNT) 0;
20 static const int kMaxAllocatableDoubleRegisterCount =
21     ALLOCATABLE_DOUBLE_REGISTERS(REGISTER_COUNT) 0;
22 #if V8_TARGET_ARCH_RISCV64
23 static const int kMaxAllocatableSIMD128RegisterCount =
24     ALLOCATABLE_SIMD128_REGISTERS(REGISTER_COUNT) 0;
25 #endif
26 
27 static const int kAllocatableGeneralCodes[] = {
28 #define REGISTER_CODE(R) kRegCode_##R,
29     ALLOCATABLE_GENERAL_REGISTERS(REGISTER_CODE)};
30 #undef REGISTER_CODE
31 
32 #define REGISTER_CODE(R) kDoubleCode_##R,
33 static const int kAllocatableDoubleCodes[] = {
34     ALLOCATABLE_DOUBLE_REGISTERS(REGISTER_CODE)};
35 #if V8_TARGET_ARCH_ARM
36 static const int kAllocatableNoVFP32DoubleCodes[] = {
37     ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(REGISTER_CODE)};
38 #endif  // V8_TARGET_ARCH_ARM
39 #undef REGISTER_CODE
40 
41 #if V8_TARGET_ARCH_RISCV64
42 static const int kAllocatableSIMD128Codes[] = {
43 #define REGISTER_CODE(R) kVRCode_##R,
44     ALLOCATABLE_SIMD128_REGISTERS(REGISTER_CODE)};
45 #undef REGISTER_CODE
46 #endif  // V8_TARGET_ARCH_RISCV64
47 
48 STATIC_ASSERT(RegisterConfiguration::kMaxGeneralRegisters >=
49               Register::kNumRegisters);
50 STATIC_ASSERT(RegisterConfiguration::kMaxFPRegisters >=
51               FloatRegister::kNumRegisters);
52 STATIC_ASSERT(RegisterConfiguration::kMaxFPRegisters >=
53               DoubleRegister::kNumRegisters);
54 STATIC_ASSERT(RegisterConfiguration::kMaxFPRegisters >=
55               Simd128Register::kNumRegisters);
56 
get_num_simd128_registers()57 static int get_num_simd128_registers() {
58   return
59 #if V8_TARGET_ARCH_RISCV64
60       Simd128Register::kNumRegisters;
61 #else
62       0;
63 #endif  // V8_TARGET_ARCH_RISCV64
64 }
65 
66 // Callers on architectures other than Arm expect this to be be constant
67 // between build and runtime. Avoid adding variability on other platforms.
get_num_allocatable_double_registers()68 static int get_num_allocatable_double_registers() {
69   return
70 #if V8_TARGET_ARCH_IA32
71       kMaxAllocatableDoubleRegisterCount;
72 #elif V8_TARGET_ARCH_X64
73       kMaxAllocatableDoubleRegisterCount;
74 #elif V8_TARGET_ARCH_ARM
75       CpuFeatures::IsSupported(VFP32DREGS)
76           ? kMaxAllocatableDoubleRegisterCount
77           : (ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(REGISTER_COUNT) 0);
78 #elif V8_TARGET_ARCH_ARM64
79       kMaxAllocatableDoubleRegisterCount;
80 #elif V8_TARGET_ARCH_MIPS
81       kMaxAllocatableDoubleRegisterCount;
82 #elif V8_TARGET_ARCH_MIPS64
83       kMaxAllocatableDoubleRegisterCount;
84 #elif V8_TARGET_ARCH_LOONG64
85       kMaxAllocatableDoubleRegisterCount;
86 #elif V8_TARGET_ARCH_PPC
87       kMaxAllocatableDoubleRegisterCount;
88 #elif V8_TARGET_ARCH_PPC64
89       kMaxAllocatableDoubleRegisterCount;
90 #elif V8_TARGET_ARCH_S390
91       kMaxAllocatableDoubleRegisterCount;
92 #elif V8_TARGET_ARCH_RISCV64
93       kMaxAllocatableDoubleRegisterCount;
94 #else
95 #error Unsupported target architecture.
96 #endif
97 }
98 
99 #undef REGISTER_COUNT
100 
get_num_allocatable_simd128_registers()101 static int get_num_allocatable_simd128_registers() {
102   return
103 #if V8_TARGET_ARCH_RISCV64
104       kMaxAllocatableSIMD128RegisterCount;
105 #else
106       0;
107 #endif
108 }
109 
110 // Callers on architectures other than Arm expect this to be be constant
111 // between build and runtime. Avoid adding variability on other platforms.
get_allocatable_double_codes()112 static const int* get_allocatable_double_codes() {
113   return
114 #if V8_TARGET_ARCH_ARM
115       CpuFeatures::IsSupported(VFP32DREGS) ? kAllocatableDoubleCodes
116                                            : kAllocatableNoVFP32DoubleCodes;
117 #else
118       kAllocatableDoubleCodes;
119 #endif
120 }
121 
get_allocatable_simd128_codes()122 static const int* get_allocatable_simd128_codes() {
123   return
124 #if V8_TARGET_ARCH_RISCV64
125       kAllocatableSIMD128Codes;
126 #else
127       kAllocatableDoubleCodes;
128 #endif
129 }
130 
131 class ArchDefaultRegisterConfiguration : public RegisterConfiguration {
132  public:
ArchDefaultRegisterConfiguration()133   ArchDefaultRegisterConfiguration()
134       : RegisterConfiguration(
135             kFPAliasing, Register::kNumRegisters, DoubleRegister::kNumRegisters,
136             get_num_simd128_registers(), kMaxAllocatableGeneralRegisterCount,
137             get_num_allocatable_double_registers(),
138             get_num_allocatable_simd128_registers(), kAllocatableGeneralCodes,
139             get_allocatable_double_codes(), get_allocatable_simd128_codes()) {}
140 };
141 
142 DEFINE_LAZY_LEAKY_OBJECT_GETTER(ArchDefaultRegisterConfiguration,
143                                 GetDefaultRegisterConfiguration)
144 
145 // RestrictedRegisterConfiguration uses the subset of allocatable general
146 // registers the architecture support, which results into generating assembly
147 // to use less registers. Currently, it's only used by RecordWrite code stub.
148 class RestrictedRegisterConfiguration : public RegisterConfiguration {
149  public:
RestrictedRegisterConfiguration(int num_allocatable_general_registers,std::unique_ptr<int[]> allocatable_general_register_codes,std::unique_ptr<char const * []> allocatable_general_register_names)150   RestrictedRegisterConfiguration(
151       int num_allocatable_general_registers,
152       std::unique_ptr<int[]> allocatable_general_register_codes,
153       std::unique_ptr<char const*[]> allocatable_general_register_names)
154       : RegisterConfiguration(
155             kFPAliasing, Register::kNumRegisters, DoubleRegister::kNumRegisters,
156             get_num_simd128_registers(), num_allocatable_general_registers,
157             get_num_allocatable_double_registers(),
158             get_num_allocatable_simd128_registers(),
159             allocatable_general_register_codes.get(),
160             get_allocatable_double_codes(), get_allocatable_simd128_codes()),
161         allocatable_general_register_codes_(
162             std::move(allocatable_general_register_codes)),
163         allocatable_general_register_names_(
164             std::move(allocatable_general_register_names)) {
165     for (int i = 0; i < num_allocatable_general_registers; ++i) {
166       DCHECK(
167           IsAllocatableGeneralRegister(allocatable_general_register_codes_[i]));
168     }
169   }
170 
IsAllocatableGeneralRegister(int code)171   bool IsAllocatableGeneralRegister(int code) {
172     for (int i = 0; i < kMaxAllocatableGeneralRegisterCount; ++i) {
173       if (code == kAllocatableGeneralCodes[i]) {
174         return true;
175       }
176     }
177     return false;
178   }
179 
180  private:
181   std::unique_ptr<int[]> allocatable_general_register_codes_;
182   std::unique_ptr<char const*[]> allocatable_general_register_names_;
183 };
184 
185 }  // namespace
186 
Default()187 const RegisterConfiguration* RegisterConfiguration::Default() {
188   return GetDefaultRegisterConfiguration();
189 }
190 
RestrictGeneralRegisters(RegList registers)191 const RegisterConfiguration* RegisterConfiguration::RestrictGeneralRegisters(
192     RegList registers) {
193   int num = registers.Count();
194   std::unique_ptr<int[]> codes{new int[num]};
195   std::unique_ptr<char const* []> names { new char const*[num] };
196   int counter = 0;
197   for (int i = 0; i < Default()->num_allocatable_general_registers(); ++i) {
198     auto reg = Register::from_code(Default()->GetAllocatableGeneralCode(i));
199     if (registers.has(reg)) {
200       DCHECK(counter < num);
201       codes[counter] = reg.code();
202       names[counter] = RegisterName(Register::from_code(i));
203       counter++;
204     }
205   }
206 
207   return new RestrictedRegisterConfiguration(num, std::move(codes),
208                                              std::move(names));
209 }
210 
RegisterConfiguration(AliasingKind fp_aliasing_kind,int num_general_registers,int num_double_registers,int num_simd128_registers,int num_allocatable_general_registers,int num_allocatable_double_registers,int num_allocatable_simd128_registers,const int * allocatable_general_codes,const int * allocatable_double_codes,const int * independent_allocatable_simd128_codes)211 RegisterConfiguration::RegisterConfiguration(
212     AliasingKind fp_aliasing_kind, int num_general_registers,
213     int num_double_registers, int num_simd128_registers,
214     int num_allocatable_general_registers, int num_allocatable_double_registers,
215     int num_allocatable_simd128_registers, const int* allocatable_general_codes,
216     const int* allocatable_double_codes,
217     const int* independent_allocatable_simd128_codes)
218     : num_general_registers_(num_general_registers),
219       num_float_registers_(0),
220       num_double_registers_(num_double_registers),
221       num_simd128_registers_(num_simd128_registers),
222       num_allocatable_general_registers_(num_allocatable_general_registers),
223       num_allocatable_float_registers_(0),
224       num_allocatable_double_registers_(num_allocatable_double_registers),
225       num_allocatable_simd128_registers_(num_allocatable_simd128_registers),
226       allocatable_general_codes_mask_(0),
227       allocatable_float_codes_mask_(0),
228       allocatable_double_codes_mask_(0),
229       allocatable_simd128_codes_mask_(0),
230       allocatable_general_codes_(allocatable_general_codes),
231       allocatable_double_codes_(allocatable_double_codes),
232       fp_aliasing_kind_(fp_aliasing_kind) {
233   DCHECK_LE(num_general_registers_,
234             RegisterConfiguration::kMaxGeneralRegisters);
235   DCHECK_LE(num_double_registers_, RegisterConfiguration::kMaxFPRegisters);
236   for (int i = 0; i < num_allocatable_general_registers_; ++i) {
237     allocatable_general_codes_mask_ |= (1 << allocatable_general_codes_[i]);
238   }
239   for (int i = 0; i < num_allocatable_double_registers_; ++i) {
240     allocatable_double_codes_mask_ |= (1 << allocatable_double_codes_[i]);
241   }
242 
243   if (fp_aliasing_kind_ == AliasingKind::kCombine) {
244     num_float_registers_ = num_double_registers_ * 2 <= kMaxFPRegisters
245                                ? num_double_registers_ * 2
246                                : kMaxFPRegisters;
247     num_allocatable_float_registers_ = 0;
248     for (int i = 0; i < num_allocatable_double_registers_; i++) {
249       int base_code = allocatable_double_codes_[i] * 2;
250       if (base_code >= kMaxFPRegisters) continue;
251       allocatable_float_codes_[num_allocatable_float_registers_++] = base_code;
252       allocatable_float_codes_[num_allocatable_float_registers_++] =
253           base_code + 1;
254       allocatable_float_codes_mask_ |= (0x3 << base_code);
255     }
256     num_simd128_registers_ = num_double_registers_ / 2;
257     num_allocatable_simd128_registers_ = 0;
258     int last_simd128_code = allocatable_double_codes_[0] / 2;
259     for (int i = 1; i < num_allocatable_double_registers_; i++) {
260       int next_simd128_code = allocatable_double_codes_[i] / 2;
261       // This scheme assumes allocatable_double_codes_ are strictly increasing.
262       DCHECK_GE(next_simd128_code, last_simd128_code);
263       if (last_simd128_code == next_simd128_code) {
264         allocatable_simd128_codes_[num_allocatable_simd128_registers_++] =
265             next_simd128_code;
266         allocatable_simd128_codes_mask_ |= (0x1 << next_simd128_code);
267       }
268       last_simd128_code = next_simd128_code;
269     }
270   } else if (fp_aliasing_kind_ == AliasingKind::kOverlap) {
271     num_float_registers_ = num_simd128_registers_ = num_double_registers_;
272     num_allocatable_float_registers_ = num_allocatable_simd128_registers_ =
273         num_allocatable_double_registers_;
274     for (int i = 0; i < num_allocatable_float_registers_; ++i) {
275       allocatable_float_codes_[i] = allocatable_simd128_codes_[i] =
276           allocatable_double_codes_[i];
277     }
278     allocatable_float_codes_mask_ = allocatable_simd128_codes_mask_ =
279         allocatable_double_codes_mask_;
280   } else {
281     DCHECK_EQ(fp_aliasing_kind_, AliasingKind::kIndependent);
282     DCHECK_NE(independent_allocatable_simd128_codes, nullptr);
283     num_float_registers_ = num_double_registers_;
284     num_allocatable_float_registers_ = num_allocatable_double_registers_;
285     for (int i = 0; i < num_allocatable_float_registers_; ++i) {
286       allocatable_float_codes_[i] = allocatable_double_codes_[i];
287     }
288     allocatable_float_codes_mask_ = allocatable_double_codes_mask_;
289     for (int i = 0; i < num_allocatable_simd128_registers; i++) {
290       allocatable_simd128_codes_[i] = independent_allocatable_simd128_codes[i];
291     }
292     for (int i = 0; i < num_allocatable_simd128_registers_; ++i) {
293       allocatable_simd128_codes_mask_ |= (1 << allocatable_simd128_codes_[i]);
294     }
295   }
296 }
297 
298 // Assert that kFloat32, kFloat64, and kSimd128 are consecutive values.
299 STATIC_ASSERT(static_cast<int>(MachineRepresentation::kSimd128) ==
300               static_cast<int>(MachineRepresentation::kFloat64) + 1);
301 STATIC_ASSERT(static_cast<int>(MachineRepresentation::kFloat64) ==
302               static_cast<int>(MachineRepresentation::kFloat32) + 1);
303 
GetAliases(MachineRepresentation rep,int index,MachineRepresentation other_rep,int * alias_base_index) const304 int RegisterConfiguration::GetAliases(MachineRepresentation rep, int index,
305                                       MachineRepresentation other_rep,
306                                       int* alias_base_index) const {
307   DCHECK(fp_aliasing_kind_ == AliasingKind::kCombine);
308   DCHECK(IsFloatingPoint(rep) && IsFloatingPoint(other_rep));
309   if (rep == other_rep) {
310     *alias_base_index = index;
311     return 1;
312   }
313   int rep_int = static_cast<int>(rep);
314   int other_rep_int = static_cast<int>(other_rep);
315   if (rep_int > other_rep_int) {
316     int shift = rep_int - other_rep_int;
317     int base_index = index << shift;
318     if (base_index >= kMaxFPRegisters) {
319       // Alias indices would be out of FP register range.
320       return 0;
321     }
322     *alias_base_index = base_index;
323     return 1 << shift;
324   }
325   int shift = other_rep_int - rep_int;
326   *alias_base_index = index >> shift;
327   return 1;
328 }
329 
AreAliases(MachineRepresentation rep,int index,MachineRepresentation other_rep,int other_index) const330 bool RegisterConfiguration::AreAliases(MachineRepresentation rep, int index,
331                                        MachineRepresentation other_rep,
332                                        int other_index) const {
333   DCHECK(fp_aliasing_kind_ == AliasingKind::kCombine);
334   DCHECK(IsFloatingPoint(rep) && IsFloatingPoint(other_rep));
335   if (rep == other_rep) {
336     return index == other_index;
337   }
338   int rep_int = static_cast<int>(rep);
339   int other_rep_int = static_cast<int>(other_rep);
340   if (rep_int > other_rep_int) {
341     int shift = rep_int - other_rep_int;
342     return index == other_index >> shift;
343   }
344   int shift = other_rep_int - rep_int;
345   return index >> shift == other_index;
346 }
347 
348 }  // namespace internal
349 }  // namespace v8
350