OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_ARM64_ASSEMBLER_ARM64_H_ | 5 #ifndef V8_ARM64_ASSEMBLER_ARM64_H_ |
6 #define V8_ARM64_ASSEMBLER_ARM64_H_ | 6 #define V8_ARM64_ASSEMBLER_ARM64_H_ |
7 | 7 |
8 #include <deque> | 8 #include <deque> |
9 #include <list> | 9 #include <list> |
10 #include <map> | 10 #include <map> |
11 #include <vector> | 11 #include <vector> |
12 | 12 |
13 #include "src/arm64/instructions-arm64.h" | 13 #include "src/arm64/instructions-arm64.h" |
14 #include "src/assembler.h" | 14 #include "src/assembler.h" |
15 #include "src/compiler.h" | 15 #include "src/compiler.h" |
16 #include "src/globals.h" | 16 #include "src/globals.h" |
17 #include "src/utils.h" | 17 #include "src/utils.h" |
18 | 18 |
19 | 19 |
20 namespace v8 { | 20 namespace v8 { |
21 namespace internal { | 21 namespace internal { |
22 | 22 |
23 | 23 |
24 // ----------------------------------------------------------------------------- | 24 // ----------------------------------------------------------------------------- |
25 // Registers. | 25 // Registers. |
26 #define REGISTER_CODE_LIST(R) \ | 26 // clang-format off |
27 R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \ | 27 #define GENERAL_REGISTER_CODE_LIST(R) \ |
28 R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \ | 28 R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \ |
29 R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \ | 29 R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \ |
30 R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31) | 30 R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \ |
| 31 R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31) |
31 | 32 |
| 33 #define GENERAL_REGISTERS(R) \ |
| 34 R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \ |
| 35 R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \ |
| 36 R(x16) R(x17) R(x18) R(x19) R(x20) R(x21) R(x22) R(x23) \ |
| 37 R(x24) R(x25) R(x26) R(x27) R(x28) R(x29) R(x30) R(x31) |
| 38 |
| 39 #define ALLOCATABLE_GENERAL_REGISTERS(R) \ |
| 40 R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \ |
| 41 R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \ |
| 42 R(x18) R(x19) R(x20) R(x21) R(x22) R(x23) R(x24) R(x27) |
| 43 |
| 44 #define DOUBLE_REGISTERS(R) \ |
| 45 R(d0) R(d1) R(d2) R(d3) R(d4) R(d5) R(d6) R(d7) \ |
| 46 R(d8) R(d9) R(d10) R(d11) R(d12) R(d13) R(d14) R(d15) \ |
| 47 R(d16) R(d17) R(d18) R(d19) R(d20) R(d21) R(d22) R(d23) \ |
| 48 R(d24) R(d25) R(d26) R(d27) R(d28) R(d29) R(d30) R(d31) |
| 49 |
| 50 #define ALLOCATABLE_DOUBLE_REGISTERS(R) \ |
| 51 R(d0) R(d1) R(d2) R(d3) R(d4) R(d5) R(d6) R(d7) \ |
| 52 R(d8) R(d9) R(d10) R(d11) R(d12) R(d13) R(d14) R(d16) \ |
| 53 R(d17) R(d18) R(d19) R(d20) R(d21) R(d22) R(d23) R(d24) \ |
| 54 R(d25) R(d26) R(d27) R(d28) |
| 55 // clang-format on |
32 | 56 |
33 static const int kRegListSizeInBits = sizeof(RegList) * kBitsPerByte; | 57 static const int kRegListSizeInBits = sizeof(RegList) * kBitsPerByte; |
34 | 58 |
35 | 59 |
36 // Some CPURegister methods can return Register and FPRegister types, so we | 60 // Some CPURegister methods can return Register and FPRegister types, so we |
37 // need to declare them in advance. | 61 // need to declare them in advance. |
38 struct Register; | 62 struct Register; |
39 struct FPRegister; | 63 struct FPRegister; |
40 | 64 |
41 | 65 |
42 struct CPURegister { | 66 struct CPURegister { |
| 67 enum Code { |
| 68 #define REGISTER_CODE(R) kCode_##R, |
| 69 GENERAL_REGISTERS(REGISTER_CODE) |
| 70 #undef REGISTER_CODE |
| 71 kAfterLast, |
| 72 kCode_no_reg = -1 |
| 73 }; |
| 74 |
43 enum RegisterType { | 75 enum RegisterType { |
44 // The kInvalid value is used to detect uninitialized static instances, | 76 // The kInvalid value is used to detect uninitialized static instances, |
45 // which are always zero-initialized before any constructors are called. | 77 // which are always zero-initialized before any constructors are called. |
46 kInvalid = 0, | 78 kInvalid = 0, |
47 kRegister, | 79 kRegister, |
48 kFPRegister, | 80 kFPRegister, |
49 kNoRegister | 81 kNoRegister |
50 }; | 82 }; |
51 | 83 |
52 static CPURegister Create(unsigned code, unsigned size, RegisterType type) { | 84 static CPURegister Create(unsigned code, unsigned size, RegisterType type) { |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 DCHECK(IsValidOrNone()); | 142 DCHECK(IsValidOrNone()); |
111 } | 143 } |
112 | 144 |
113 Register(const Register& r) { // NOLINT(runtime/explicit) | 145 Register(const Register& r) { // NOLINT(runtime/explicit) |
114 reg_code = r.reg_code; | 146 reg_code = r.reg_code; |
115 reg_size = r.reg_size; | 147 reg_size = r.reg_size; |
116 reg_type = r.reg_type; | 148 reg_type = r.reg_type; |
117 DCHECK(IsValidOrNone()); | 149 DCHECK(IsValidOrNone()); |
118 } | 150 } |
119 | 151 |
| 152 const char* ToString(); |
| 153 bool IsAllocatable() const; |
120 bool IsValid() const { | 154 bool IsValid() const { |
121 DCHECK(IsRegister() || IsNone()); | 155 DCHECK(IsRegister() || IsNone()); |
122 return IsValidRegister(); | 156 return IsValidRegister(); |
123 } | 157 } |
124 | 158 |
125 static Register XRegFromCode(unsigned code); | 159 static Register XRegFromCode(unsigned code); |
126 static Register WRegFromCode(unsigned code); | 160 static Register WRegFromCode(unsigned code); |
127 | 161 |
128 // Start of V8 compatibility section --------------------- | 162 // Start of V8 compatibility section --------------------- |
129 // These memebers are necessary for compilation. | 163 // These memebers are necessary for compilation. |
130 // A few of them may be unused for now. | 164 // A few of them may be unused for now. |
131 | 165 |
132 static const int kNumRegisters = kNumberOfRegisters; | 166 static const int kNumRegisters = kNumberOfRegisters; |
| 167 STATIC_ASSERT(kNumRegisters == Code::kAfterLast); |
133 static int NumRegisters() { return kNumRegisters; } | 168 static int NumRegisters() { return kNumRegisters; } |
134 | 169 |
135 // We allow crankshaft to use the following registers: | 170 // We allow crankshaft to use the following registers: |
136 // - x0 to x15 | 171 // - x0 to x15 |
137 // - x18 to x24 | 172 // - x18 to x24 |
138 // - x27 (also context) | 173 // - x27 (also context) |
139 // | 174 // |
140 // TODO(all): Register x25 is currently free and could be available for | 175 // TODO(all): Register x25 is currently free and could be available for |
141 // crankshaft, but we don't use it as we might use it as a per function | 176 // crankshaft, but we don't use it as we might use it as a per function |
142 // literal pool pointer in the future. | 177 // literal pool pointer in the future. |
143 // | 178 // |
144 // TODO(all): Consider storing cp in x25 to have only two ranges. | 179 // TODO(all): Consider storing cp in x25 to have only two ranges. |
145 // We split allocatable registers in three ranges called | 180 // We split allocatable registers in three ranges called |
146 // - "low range" | 181 // - "low range" |
147 // - "high range" | 182 // - "high range" |
148 // - "context" | 183 // - "context" |
149 static const unsigned kAllocatableLowRangeBegin = 0; | |
150 static const unsigned kAllocatableLowRangeEnd = 15; | |
151 static const unsigned kAllocatableHighRangeBegin = 18; | |
152 static const unsigned kAllocatableHighRangeEnd = 24; | |
153 static const unsigned kAllocatableContext = 27; | |
154 | |
155 // Gap between low and high ranges. | |
156 static const int kAllocatableRangeGapSize = | |
157 (kAllocatableHighRangeBegin - kAllocatableLowRangeEnd) - 1; | |
158 | |
159 static const int kMaxNumAllocatableRegisters = | |
160 (kAllocatableLowRangeEnd - kAllocatableLowRangeBegin + 1) + | |
161 (kAllocatableHighRangeEnd - kAllocatableHighRangeBegin + 1) + 1; // cp | |
162 static int NumAllocatableRegisters() { return kMaxNumAllocatableRegisters; } | |
163 | |
164 // Return true if the register is one that crankshaft can allocate. | |
165 bool IsAllocatable() const { | |
166 return ((reg_code == kAllocatableContext) || | |
167 (reg_code <= kAllocatableLowRangeEnd) || | |
168 ((reg_code >= kAllocatableHighRangeBegin) && | |
169 (reg_code <= kAllocatableHighRangeEnd))); | |
170 } | |
171 | |
172 static Register FromAllocationIndex(unsigned index) { | |
173 DCHECK(index < static_cast<unsigned>(NumAllocatableRegisters())); | |
174 // cp is the last allocatable register. | |
175 if (index == (static_cast<unsigned>(NumAllocatableRegisters() - 1))) { | |
176 return from_code(kAllocatableContext); | |
177 } | |
178 | |
179 // Handle low and high ranges. | |
180 return (index <= kAllocatableLowRangeEnd) | |
181 ? from_code(index) | |
182 : from_code(index + kAllocatableRangeGapSize); | |
183 } | |
184 | |
185 static const char* AllocationIndexToString(int index) { | |
186 DCHECK((index >= 0) && (index < NumAllocatableRegisters())); | |
187 DCHECK((kAllocatableLowRangeBegin == 0) && | |
188 (kAllocatableLowRangeEnd == 15) && | |
189 (kAllocatableHighRangeBegin == 18) && | |
190 (kAllocatableHighRangeEnd == 24) && | |
191 (kAllocatableContext == 27)); | |
192 const char* const names[] = { | |
193 "x0", "x1", "x2", "x3", "x4", | |
194 "x5", "x6", "x7", "x8", "x9", | |
195 "x10", "x11", "x12", "x13", "x14", | |
196 "x15", "x18", "x19", "x20", "x21", | |
197 "x22", "x23", "x24", "x27", | |
198 }; | |
199 return names[index]; | |
200 } | |
201 | |
202 static int ToAllocationIndex(Register reg) { | |
203 DCHECK(reg.IsAllocatable()); | |
204 unsigned code = reg.code(); | |
205 if (code == kAllocatableContext) { | |
206 return NumAllocatableRegisters() - 1; | |
207 } | |
208 | |
209 return (code <= kAllocatableLowRangeEnd) | |
210 ? code | |
211 : code - kAllocatableRangeGapSize; | |
212 } | |
213 | 184 |
214 static Register from_code(int code) { | 185 static Register from_code(int code) { |
215 // Always return an X register. | 186 // Always return an X register. |
216 return Register::Create(code, kXRegSizeInBits); | 187 return Register::Create(code, kXRegSizeInBits); |
217 } | 188 } |
218 | 189 |
219 // End of V8 compatibility section ----------------------- | 190 // End of V8 compatibility section ----------------------- |
220 }; | 191 }; |
221 | 192 |
222 | 193 |
223 struct FPRegister : public CPURegister { | 194 struct FPRegister : public CPURegister { |
| 195 enum Code { |
| 196 #define REGISTER_CODE(R) kCode_##R, |
| 197 DOUBLE_REGISTERS(REGISTER_CODE) |
| 198 #undef REGISTER_CODE |
| 199 kAfterLast, |
| 200 kCode_no_reg = -1 |
| 201 }; |
| 202 |
224 static FPRegister Create(unsigned code, unsigned size) { | 203 static FPRegister Create(unsigned code, unsigned size) { |
225 return FPRegister( | 204 return FPRegister( |
226 CPURegister::Create(code, size, CPURegister::kFPRegister)); | 205 CPURegister::Create(code, size, CPURegister::kFPRegister)); |
227 } | 206 } |
228 | 207 |
229 FPRegister() { | 208 FPRegister() { |
230 reg_code = 0; | 209 reg_code = 0; |
231 reg_size = 0; | 210 reg_size = 0; |
232 reg_type = CPURegister::kNoRegister; | 211 reg_type = CPURegister::kNoRegister; |
233 } | 212 } |
234 | 213 |
235 explicit FPRegister(const CPURegister& r) { | 214 explicit FPRegister(const CPURegister& r) { |
236 reg_code = r.reg_code; | 215 reg_code = r.reg_code; |
237 reg_size = r.reg_size; | 216 reg_size = r.reg_size; |
238 reg_type = r.reg_type; | 217 reg_type = r.reg_type; |
239 DCHECK(IsValidOrNone()); | 218 DCHECK(IsValidOrNone()); |
240 } | 219 } |
241 | 220 |
242 FPRegister(const FPRegister& r) { // NOLINT(runtime/explicit) | 221 FPRegister(const FPRegister& r) { // NOLINT(runtime/explicit) |
243 reg_code = r.reg_code; | 222 reg_code = r.reg_code; |
244 reg_size = r.reg_size; | 223 reg_size = r.reg_size; |
245 reg_type = r.reg_type; | 224 reg_type = r.reg_type; |
246 DCHECK(IsValidOrNone()); | 225 DCHECK(IsValidOrNone()); |
247 } | 226 } |
248 | 227 |
| 228 const char* ToString(); |
| 229 bool IsAllocatable() const; |
249 bool IsValid() const { | 230 bool IsValid() const { |
250 DCHECK(IsFPRegister() || IsNone()); | 231 DCHECK(IsFPRegister() || IsNone()); |
251 return IsValidFPRegister(); | 232 return IsValidFPRegister(); |
252 } | 233 } |
253 | 234 |
254 static FPRegister SRegFromCode(unsigned code); | 235 static FPRegister SRegFromCode(unsigned code); |
255 static FPRegister DRegFromCode(unsigned code); | 236 static FPRegister DRegFromCode(unsigned code); |
256 | 237 |
257 // Start of V8 compatibility section --------------------- | 238 // Start of V8 compatibility section --------------------- |
258 static const int kMaxNumRegisters = kNumberOfFPRegisters; | 239 static const int kMaxNumRegisters = kNumberOfFPRegisters; |
| 240 STATIC_ASSERT(kMaxNumRegisters == Code::kAfterLast); |
259 | 241 |
260 // Crankshaft can use all the FP registers except: | 242 // Crankshaft can use all the FP registers except: |
261 // - d15 which is used to keep the 0 double value | 243 // - d15 which is used to keep the 0 double value |
262 // - d30 which is used in crankshaft as a double scratch register | 244 // - d30 which is used in crankshaft as a double scratch register |
263 // - d31 which is used in the MacroAssembler as a double scratch register | 245 // - d31 which is used in the MacroAssembler as a double scratch register |
264 static const unsigned kAllocatableLowRangeBegin = 0; | |
265 static const unsigned kAllocatableLowRangeEnd = 14; | |
266 static const unsigned kAllocatableHighRangeBegin = 16; | |
267 static const unsigned kAllocatableHighRangeEnd = 28; | |
268 | |
269 static const RegList kAllocatableFPRegisters = 0x1fff7fff; | |
270 | |
271 // Gap between low and high ranges. | |
272 static const int kAllocatableRangeGapSize = | |
273 (kAllocatableHighRangeBegin - kAllocatableLowRangeEnd) - 1; | |
274 | |
275 static const int kMaxNumAllocatableRegisters = | |
276 (kAllocatableLowRangeEnd - kAllocatableLowRangeBegin + 1) + | |
277 (kAllocatableHighRangeEnd - kAllocatableHighRangeBegin + 1); | |
278 static int NumAllocatableRegisters() { return kMaxNumAllocatableRegisters; } | |
279 | |
280 // TODO(turbofan): Proper float32 support. | |
281 static int NumAllocatableAliasedRegisters() { | |
282 return NumAllocatableRegisters(); | |
283 } | |
284 | |
285 // Return true if the register is one that crankshaft can allocate. | |
286 bool IsAllocatable() const { | |
287 return (Bit() & kAllocatableFPRegisters) != 0; | |
288 } | |
289 | |
290 static FPRegister FromAllocationIndex(unsigned int index) { | |
291 DCHECK(index < static_cast<unsigned>(NumAllocatableRegisters())); | |
292 | |
293 return (index <= kAllocatableLowRangeEnd) | |
294 ? from_code(index) | |
295 : from_code(index + kAllocatableRangeGapSize); | |
296 } | |
297 | |
298 static const char* AllocationIndexToString(int index) { | |
299 DCHECK((index >= 0) && (index < NumAllocatableRegisters())); | |
300 DCHECK((kAllocatableLowRangeBegin == 0) && | |
301 (kAllocatableLowRangeEnd == 14) && | |
302 (kAllocatableHighRangeBegin == 16) && | |
303 (kAllocatableHighRangeEnd == 28)); | |
304 const char* const names[] = { | |
305 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", | |
306 "d8", "d9", "d10", "d11", "d12", "d13", "d14", | |
307 "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", | |
308 "d24", "d25", "d26", "d27", "d28" | |
309 }; | |
310 return names[index]; | |
311 } | |
312 | |
313 static int ToAllocationIndex(FPRegister reg) { | |
314 DCHECK(reg.IsAllocatable()); | |
315 unsigned code = reg.code(); | |
316 | |
317 return (code <= kAllocatableLowRangeEnd) | |
318 ? code | |
319 : code - kAllocatableRangeGapSize; | |
320 } | |
321 | |
322 static FPRegister from_code(int code) { | 246 static FPRegister from_code(int code) { |
323 // Always return a D register. | 247 // Always return a D register. |
324 return FPRegister::Create(code, kDRegSizeInBits); | 248 return FPRegister::Create(code, kDRegSizeInBits); |
325 } | 249 } |
326 // End of V8 compatibility section ----------------------- | 250 // End of V8 compatibility section ----------------------- |
327 }; | 251 }; |
328 | 252 |
329 | 253 |
330 STATIC_ASSERT(sizeof(CPURegister) == sizeof(Register)); | 254 STATIC_ASSERT(sizeof(CPURegister) == sizeof(Register)); |
331 STATIC_ASSERT(sizeof(CPURegister) == sizeof(FPRegister)); | 255 STATIC_ASSERT(sizeof(CPURegister) == sizeof(FPRegister)); |
(...skipping 22 matching lines...) Expand all Loading... |
354 INITIALIZE_REGISTER(CPURegister, NoCPUReg, 0, 0, CPURegister::kNoRegister); | 278 INITIALIZE_REGISTER(CPURegister, NoCPUReg, 0, 0, CPURegister::kNoRegister); |
355 | 279 |
356 // v8 compatibility. | 280 // v8 compatibility. |
357 INITIALIZE_REGISTER(Register, no_reg, 0, 0, CPURegister::kNoRegister); | 281 INITIALIZE_REGISTER(Register, no_reg, 0, 0, CPURegister::kNoRegister); |
358 | 282 |
359 #define DEFINE_REGISTERS(N) \ | 283 #define DEFINE_REGISTERS(N) \ |
360 INITIALIZE_REGISTER(Register, w##N, N, \ | 284 INITIALIZE_REGISTER(Register, w##N, N, \ |
361 kWRegSizeInBits, CPURegister::kRegister); \ | 285 kWRegSizeInBits, CPURegister::kRegister); \ |
362 INITIALIZE_REGISTER(Register, x##N, N, \ | 286 INITIALIZE_REGISTER(Register, x##N, N, \ |
363 kXRegSizeInBits, CPURegister::kRegister); | 287 kXRegSizeInBits, CPURegister::kRegister); |
364 REGISTER_CODE_LIST(DEFINE_REGISTERS) | 288 GENERAL_REGISTER_CODE_LIST(DEFINE_REGISTERS) |
365 #undef DEFINE_REGISTERS | 289 #undef DEFINE_REGISTERS |
366 | 290 |
367 INITIALIZE_REGISTER(Register, wcsp, kSPRegInternalCode, kWRegSizeInBits, | 291 INITIALIZE_REGISTER(Register, wcsp, kSPRegInternalCode, kWRegSizeInBits, |
368 CPURegister::kRegister); | 292 CPURegister::kRegister); |
369 INITIALIZE_REGISTER(Register, csp, kSPRegInternalCode, kXRegSizeInBits, | 293 INITIALIZE_REGISTER(Register, csp, kSPRegInternalCode, kXRegSizeInBits, |
370 CPURegister::kRegister); | 294 CPURegister::kRegister); |
371 | 295 |
372 #define DEFINE_FPREGISTERS(N) \ | 296 #define DEFINE_FPREGISTERS(N) \ |
373 INITIALIZE_REGISTER(FPRegister, s##N, N, \ | 297 INITIALIZE_REGISTER(FPRegister, s##N, N, \ |
374 kSRegSizeInBits, CPURegister::kFPRegister); \ | 298 kSRegSizeInBits, CPURegister::kFPRegister); \ |
375 INITIALIZE_REGISTER(FPRegister, d##N, N, \ | 299 INITIALIZE_REGISTER(FPRegister, d##N, N, \ |
376 kDRegSizeInBits, CPURegister::kFPRegister); | 300 kDRegSizeInBits, CPURegister::kFPRegister); |
377 REGISTER_CODE_LIST(DEFINE_FPREGISTERS) | 301 GENERAL_REGISTER_CODE_LIST(DEFINE_FPREGISTERS) |
378 #undef DEFINE_FPREGISTERS | 302 #undef DEFINE_FPREGISTERS |
379 | 303 |
380 #undef INITIALIZE_REGISTER | 304 #undef INITIALIZE_REGISTER |
381 | 305 |
382 // Registers aliases. | 306 // Registers aliases. |
383 ALIAS_REGISTER(Register, ip0, x16); | 307 ALIAS_REGISTER(Register, ip0, x16); |
384 ALIAS_REGISTER(Register, ip1, x17); | 308 ALIAS_REGISTER(Register, ip1, x17); |
385 ALIAS_REGISTER(Register, wip0, w16); | 309 ALIAS_REGISTER(Register, wip0, w16); |
386 ALIAS_REGISTER(Register, wip1, w17); | 310 ALIAS_REGISTER(Register, wip1, w17); |
387 // Root register. | 311 // Root register. |
(...skipping 1905 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2293 public: | 2217 public: |
2294 explicit EnsureSpace(Assembler* assembler) { | 2218 explicit EnsureSpace(Assembler* assembler) { |
2295 assembler->CheckBufferSpace(); | 2219 assembler->CheckBufferSpace(); |
2296 } | 2220 } |
2297 }; | 2221 }; |
2298 | 2222 |
2299 } // namespace internal | 2223 } // namespace internal |
2300 } // namespace v8 | 2224 } // namespace v8 |
2301 | 2225 |
2302 #endif // V8_ARM64_ASSEMBLER_ARM64_H_ | 2226 #endif // V8_ARM64_ASSEMBLER_ARM64_H_ |
OLD | NEW |