Line data Source code
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 :
67 : static int get_num_allocatable_general_registers() {
68 : return
69 : #if V8_TARGET_ARCH_IA32
70 : kMaxAllocatableGeneralRegisterCount;
71 : #elif V8_TARGET_ARCH_X64
72 : kMaxAllocatableGeneralRegisterCount;
73 : #elif V8_TARGET_ARCH_ARM
74 : kMaxAllocatableGeneralRegisterCount;
75 : #elif V8_TARGET_ARCH_ARM64
76 : kMaxAllocatableGeneralRegisterCount;
77 : #elif V8_TARGET_ARCH_MIPS
78 : kMaxAllocatableGeneralRegisterCount;
79 : #elif V8_TARGET_ARCH_MIPS64
80 : kMaxAllocatableGeneralRegisterCount;
81 : #elif V8_TARGET_ARCH_PPC
82 : kMaxAllocatableGeneralRegisterCount;
83 : #elif V8_TARGET_ARCH_S390
84 : kMaxAllocatableGeneralRegisterCount;
85 : #else
86 : #error Unsupported target architecture.
87 : #endif
88 : }
89 :
90 : static int get_num_allocatable_double_registers() {
91 : return
92 : #if V8_TARGET_ARCH_IA32
93 : kMaxAllocatableDoubleRegisterCount;
94 : #elif V8_TARGET_ARCH_X64
95 : kMaxAllocatableDoubleRegisterCount;
96 : #elif V8_TARGET_ARCH_ARM
97 : CpuFeatures::IsSupported(VFP32DREGS)
98 : ? kMaxAllocatableDoubleRegisterCount
99 : : (ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(REGISTER_COUNT) 0);
100 : #elif V8_TARGET_ARCH_ARM64
101 : kMaxAllocatableDoubleRegisterCount;
102 : #elif V8_TARGET_ARCH_MIPS
103 : kMaxAllocatableDoubleRegisterCount;
104 : #elif V8_TARGET_ARCH_MIPS64
105 : kMaxAllocatableDoubleRegisterCount;
106 : #elif V8_TARGET_ARCH_PPC
107 : kMaxAllocatableDoubleRegisterCount;
108 : #elif V8_TARGET_ARCH_S390
109 : kMaxAllocatableDoubleRegisterCount;
110 : #else
111 : #error Unsupported target architecture.
112 : #endif
113 : }
114 :
115 : static const int* get_allocatable_double_codes() {
116 : return
117 : #if V8_TARGET_ARCH_ARM
118 : CpuFeatures::IsSupported(VFP32DREGS) ? kAllocatableDoubleCodes
119 : : kAllocatableNoVFP32DoubleCodes;
120 : #else
121 : kAllocatableDoubleCodes;
122 : #endif
123 : }
124 :
125 0 : class ArchDefaultRegisterConfiguration : public RegisterConfiguration {
126 : public:
127 25595 : ArchDefaultRegisterConfiguration()
128 : : RegisterConfiguration(
129 : Register::kNumRegisters, DoubleRegister::kNumRegisters,
130 : get_num_allocatable_general_registers(),
131 : get_num_allocatable_double_registers(), kAllocatableGeneralCodes,
132 : get_allocatable_double_codes(),
133 : kSimpleFPAliasing ? AliasingKind::OVERLAP : AliasingKind::COMBINE,
134 : kGeneralRegisterNames, kFloatRegisterNames, kDoubleRegisterNames,
135 25595 : kSimd128RegisterNames) {}
136 : };
137 :
138 : struct RegisterConfigurationInitializer {
139 : static void Construct(void* config) {
140 25595 : new (config) ArchDefaultRegisterConfiguration();
141 : }
142 : };
143 :
144 : static base::LazyInstance<ArchDefaultRegisterConfiguration,
145 : RegisterConfigurationInitializer>::type
146 : kDefaultRegisterConfiguration = LAZY_INSTANCE_INITIALIZER;
147 :
148 : // RestrictedRegisterConfiguration uses the subset of allocatable general
149 : // registers the architecture support, which results into generating assembly
150 : // to use less registers. Currently, it's only used by RecordWrite code stub.
151 258 : class RestrictedRegisterConfiguration : public RegisterConfiguration {
152 : public:
153 86 : RestrictedRegisterConfiguration(
154 : int num_allocatable_general_registers,
155 : std::unique_ptr<int[]> allocatable_general_register_codes,
156 : std::unique_ptr<char const* []> allocatable_general_register_names)
157 : : RegisterConfiguration(
158 : Register::kNumRegisters, DoubleRegister::kNumRegisters,
159 : num_allocatable_general_registers,
160 : get_num_allocatable_double_registers(),
161 : allocatable_general_register_codes.get(),
162 : get_allocatable_double_codes(),
163 : kSimpleFPAliasing ? AliasingKind::OVERLAP : AliasingKind::COMBINE,
164 : allocatable_general_register_names.get(), kFloatRegisterNames,
165 : kDoubleRegisterNames, kSimd128RegisterNames),
166 : allocatable_general_register_codes_(
167 : std::move(allocatable_general_register_codes)),
168 : allocatable_general_register_names_(
169 86 : std::move(allocatable_general_register_names)) {
170 : for (int i = 0; i < num_allocatable_general_registers; ++i) {
171 : DCHECK(
172 : IsAllocatableGeneralRegister(allocatable_general_register_codes_[i]));
173 : }
174 86 : }
175 :
176 : bool IsAllocatableGeneralRegister(int code) {
177 : for (int i = 0; i < kMaxAllocatableGeneralRegisterCount; ++i) {
178 : if (code == kAllocatableGeneralCodes[i]) {
179 : return true;
180 : }
181 : }
182 : return false;
183 : }
184 :
185 : private:
186 : std::unique_ptr<int[]> allocatable_general_register_codes_;
187 : std::unique_ptr<char const* []> allocatable_general_register_names_;
188 : };
189 :
190 : } // namespace
191 :
192 2923409 : const RegisterConfiguration* RegisterConfiguration::Default() {
193 2923417 : return &kDefaultRegisterConfiguration.Get();
194 : }
195 :
196 86 : const RegisterConfiguration* RegisterConfiguration::RestrictGeneralRegisters(
197 : RegList registers) {
198 : int num = NumRegs(registers);
199 86 : std::unique_ptr<int[]> codes{new int[num]};
200 86 : std::unique_ptr<char const* []> names { new char const*[num] };
201 : int counter = 0;
202 2236 : for (int i = 0; i < Default()->num_allocatable_general_registers(); ++i) {
203 1032 : auto reg = Register::from_code(Default()->GetAllocatableGeneralCode(i));
204 1032 : if (reg.bit() & registers) {
205 : DCHECK(counter < num);
206 1148 : codes[counter] = reg.code();
207 1148 : names[counter] = Default()->GetGeneralRegisterName(i);
208 574 : counter++;
209 : }
210 : }
211 :
212 : return new RestrictedRegisterConfiguration(num, std::move(codes),
213 258 : std::move(names));
214 : }
215 :
216 25735 : RegisterConfiguration::RegisterConfiguration(
217 : int num_general_registers, int num_double_registers,
218 : int num_allocatable_general_registers, int num_allocatable_double_registers,
219 : const int* allocatable_general_codes, const int* allocatable_double_codes,
220 : AliasingKind fp_aliasing_kind, const char* const* general_register_names,
221 : const char* const* float_register_names,
222 : const char* const* double_register_names,
223 : const char* const* simd128_register_names)
224 : : num_general_registers_(num_general_registers),
225 : num_float_registers_(0),
226 : num_double_registers_(num_double_registers),
227 : num_simd128_registers_(0),
228 : num_allocatable_general_registers_(num_allocatable_general_registers),
229 : num_allocatable_float_registers_(0),
230 : num_allocatable_double_registers_(num_allocatable_double_registers),
231 : num_allocatable_simd128_registers_(0),
232 : allocatable_general_codes_mask_(0),
233 : allocatable_float_codes_mask_(0),
234 : allocatable_double_codes_mask_(0),
235 : allocatable_simd128_codes_mask_(0),
236 : allocatable_general_codes_(allocatable_general_codes),
237 : allocatable_double_codes_(allocatable_double_codes),
238 : fp_aliasing_kind_(fp_aliasing_kind),
239 : general_register_names_(general_register_names),
240 : float_register_names_(float_register_names),
241 : double_register_names_(double_register_names),
242 25735 : simd128_register_names_(simd128_register_names) {
243 : DCHECK_LE(num_general_registers_,
244 : RegisterConfiguration::kMaxGeneralRegisters);
245 : DCHECK_LE(num_double_registers_, RegisterConfiguration::kMaxFPRegisters);
246 333860 : for (int i = 0; i < num_allocatable_general_registers_; ++i) {
247 308125 : allocatable_general_codes_mask_ |= (1 << allocatable_general_codes_[i]);
248 : }
249 385627 : for (int i = 0; i < num_allocatable_double_registers_; ++i) {
250 385627 : allocatable_double_codes_mask_ |= (1 << allocatable_double_codes_[i]);
251 : }
252 :
253 25735 : if (fp_aliasing_kind_ == COMBINE) {
254 : num_float_registers_ = num_double_registers_ * 2 <= kMaxFPRegisters
255 1 : ? num_double_registers_ * 2
256 1 : : kMaxFPRegisters;
257 : num_allocatable_float_registers_ = 0;
258 4 : for (int i = 0; i < num_allocatable_double_registers_; i++) {
259 3 : int base_code = allocatable_double_codes_[i] * 2;
260 3 : if (base_code >= kMaxFPRegisters) continue;
261 2 : allocatable_float_codes_[num_allocatable_float_registers_++] = base_code;
262 2 : allocatable_float_codes_[num_allocatable_float_registers_++] =
263 2 : base_code + 1;
264 2 : allocatable_float_codes_mask_ |= (0x3 << base_code);
265 : }
266 1 : num_simd128_registers_ = num_double_registers_ / 2;
267 : num_allocatable_simd128_registers_ = 0;
268 1 : int last_simd128_code = allocatable_double_codes_[0] / 2;
269 3 : for (int i = 1; i < num_allocatable_double_registers_; i++) {
270 2 : int next_simd128_code = allocatable_double_codes_[i] / 2;
271 : // This scheme assumes allocatable_double_codes_ are strictly increasing.
272 : DCHECK_GE(next_simd128_code, last_simd128_code);
273 2 : if (last_simd128_code == next_simd128_code) {
274 1 : allocatable_simd128_codes_[num_allocatable_simd128_registers_++] =
275 1 : next_simd128_code;
276 1 : allocatable_simd128_codes_mask_ |= (0x1 << next_simd128_code);
277 : }
278 : last_simd128_code = next_simd128_code;
279 : }
280 : } else {
281 : DCHECK(fp_aliasing_kind_ == OVERLAP);
282 25734 : num_float_registers_ = num_simd128_registers_ = num_double_registers_;
283 : num_allocatable_float_registers_ = num_allocatable_simd128_registers_ =
284 25734 : num_allocatable_double_registers_;
285 411358 : for (int i = 0; i < num_allocatable_float_registers_; ++i) {
286 : allocatable_float_codes_[i] = allocatable_simd128_codes_[i] =
287 385624 : allocatable_double_codes_[i];
288 : }
289 : allocatable_float_codes_mask_ = allocatable_simd128_codes_mask_ =
290 25734 : allocatable_double_codes_mask_;
291 : }
292 25735 : }
293 :
294 : // Assert that kFloat32, kFloat64, and kSimd128 are consecutive values.
295 : STATIC_ASSERT(static_cast<int>(MachineRepresentation::kSimd128) ==
296 : static_cast<int>(MachineRepresentation::kFloat64) + 1);
297 : STATIC_ASSERT(static_cast<int>(MachineRepresentation::kFloat64) ==
298 : static_cast<int>(MachineRepresentation::kFloat32) + 1);
299 :
300 12 : int RegisterConfiguration::GetAliases(MachineRepresentation rep, int index,
301 : MachineRepresentation other_rep,
302 : int* alias_base_index) const {
303 : DCHECK(fp_aliasing_kind_ == COMBINE);
304 : DCHECK(IsFloatingPoint(rep) && IsFloatingPoint(other_rep));
305 12 : if (rep == other_rep) {
306 2 : *alias_base_index = index;
307 2 : return 1;
308 : }
309 : int rep_int = static_cast<int>(rep);
310 : int other_rep_int = static_cast<int>(other_rep);
311 10 : if (rep_int > other_rep_int) {
312 6 : int shift = rep_int - other_rep_int;
313 6 : int base_index = index << shift;
314 6 : if (base_index >= kMaxFPRegisters) {
315 : // Alias indices would be out of FP register range.
316 : return 0;
317 : }
318 3 : *alias_base_index = base_index;
319 3 : return 1 << shift;
320 : }
321 4 : int shift = other_rep_int - rep_int;
322 4 : *alias_base_index = index >> shift;
323 4 : return 1;
324 : }
325 :
326 34 : bool RegisterConfiguration::AreAliases(MachineRepresentation rep, int index,
327 : MachineRepresentation other_rep,
328 : int other_index) const {
329 : DCHECK(fp_aliasing_kind_ == COMBINE);
330 : DCHECK(IsFloatingPoint(rep) && IsFloatingPoint(other_rep));
331 34 : if (rep == other_rep) {
332 6 : return index == other_index;
333 : }
334 : int rep_int = static_cast<int>(rep);
335 : int other_rep_int = static_cast<int>(other_rep);
336 28 : if (rep_int > other_rep_int) {
337 16 : int shift = rep_int - other_rep_int;
338 16 : return index == other_index >> shift;
339 : }
340 12 : int shift = other_rep_int - rep_int;
341 12 : return index >> shift == other_index;
342 : }
343 :
344 : } // namespace internal
345 : } // namespace v8
|