1 // Copyright 2018 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 #ifndef V8_CODEGEN_ARM64_REGISTER_ARM64_H_
6 #define V8_CODEGEN_ARM64_REGISTER_ARM64_H_
7 
8 #include "src/codegen/arm64/utils-arm64.h"
9 #include "src/codegen/register.h"
10 #include "src/codegen/reglist.h"
11 #include "src/common/globals.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 // -----------------------------------------------------------------------------
17 // Registers.
18 // clang-format off
19 #define GENERAL_REGISTER_CODE_LIST(R)                     \
20   R(0)  R(1)  R(2)  R(3)  R(4)  R(5)  R(6)  R(7)          \
21   R(8)  R(9)  R(10) R(11) R(12) R(13) R(14) R(15)         \
22   R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23)         \
23   R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
24 
25 #define GENERAL_REGISTERS(R)                              \
26   R(x0)  R(x1)  R(x2)  R(x3)  R(x4)  R(x5)  R(x6)  R(x7)  \
27   R(x8)  R(x9)  R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \
28   R(x16) R(x17) R(x18) R(x19) R(x20) R(x21) R(x22) R(x23) \
29   R(x24) R(x25) R(x26) R(x27) R(x28) R(x29) R(x30) R(x31)
30 
31 // x18 is the platform register and is reserved for the use of platform ABIs.
32 // It is known to be reserved by the OS at least on Windows and iOS.
33 #define ALLOCATABLE_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(x19) R(x20) R(x21) R(x22) R(x23) R(x24) R(x25) \
37   R(x27) R(x28)
38 
39 #define FLOAT_REGISTERS(V)                                \
40   V(s0)  V(s1)  V(s2)  V(s3)  V(s4)  V(s5)  V(s6)  V(s7)  \
41   V(s8)  V(s9)  V(s10) V(s11) V(s12) V(s13) V(s14) V(s15) \
42   V(s16) V(s17) V(s18) V(s19) V(s20) V(s21) V(s22) V(s23) \
43   V(s24) V(s25) V(s26) V(s27) V(s28) V(s29) V(s30) V(s31)
44 
45 #define DOUBLE_REGISTERS(R)                               \
46   R(d0)  R(d1)  R(d2)  R(d3)  R(d4)  R(d5)  R(d6)  R(d7)  \
47   R(d8)  R(d9)  R(d10) R(d11) R(d12) R(d13) R(d14) R(d15) \
48   R(d16) R(d17) R(d18) R(d19) R(d20) R(d21) R(d22) R(d23) \
49   R(d24) R(d25) R(d26) R(d27) R(d28) R(d29) R(d30) R(d31)
50 
51 #define SIMD128_REGISTERS(V)                              \
52   V(q0)  V(q1)  V(q2)  V(q3)  V(q4)  V(q5)  V(q6)  V(q7)  \
53   V(q8)  V(q9)  V(q10) V(q11) V(q12) V(q13) V(q14) V(q15) \
54   V(q16) V(q17) V(q18) V(q19) V(q20) V(q21) V(q22) V(q23) \
55   V(q24) V(q25) V(q26) V(q27) V(q28) V(q29) V(q30) V(q31)
56 
57 #define VECTOR_REGISTERS(V)                               \
58   V(v0)  V(v1)  V(v2)  V(v3)  V(v4)  V(v5)  V(v6)  V(v7)  \
59   V(v8)  V(v9)  V(v10) V(v11) V(v12) V(v13) V(v14) V(v15) \
60   V(v16) V(v17) V(v18) V(v19) V(v20) V(v21) V(v22) V(v23) \
61   V(v24) V(v25) V(v26) V(v27) V(v28) V(v29) V(v30) V(v31)
62 
63 // Register d29 could be allocated, but we keep an even length list here, in
64 // order to make stack alignment easier for save and restore.
65 #define ALLOCATABLE_DOUBLE_REGISTERS(R)                   \
66   R(d0)  R(d1)  R(d2)  R(d3)  R(d4)  R(d5)  R(d6)  R(d7)  \
67   R(d8)  R(d9)  R(d10) R(d11) R(d12) R(d13) R(d14) R(d16) \
68   R(d17) R(d18) R(d19) R(d20) R(d21) R(d22) R(d23) R(d24) \
69   R(d25) R(d26) R(d27) R(d28)
70 // clang-format on
71 
72 constexpr int kRegListSizeInBits = sizeof(RegList) * kBitsPerByte;
73 
74 // Some CPURegister methods can return Register and VRegister types, so we
75 // need to declare them in advance.
76 class Register;
77 class VRegister;
78 
79 enum RegisterCode {
80 #define REGISTER_CODE(R) kRegCode_##R,
81   GENERAL_REGISTERS(REGISTER_CODE)
82 #undef REGISTER_CODE
83       kRegAfterLast
84 };
85 
86 class CPURegister : public RegisterBase<CPURegister, kRegAfterLast> {
87  public:
88   enum RegisterType { kRegister, kVRegister, kNoRegister };
89 
no_reg()90   static constexpr CPURegister no_reg() {
91     return CPURegister{kCode_no_reg, 0, kNoRegister};
92   }
93 
Create(int code,int size,RegisterType type)94   static constexpr CPURegister Create(int code, int size, RegisterType type) {
95     CONSTEXPR_DCHECK(IsValid(code, size, type));
96     return CPURegister{code, size, type};
97   }
98 
type()99   RegisterType type() const { return reg_type_; }
SizeInBits()100   int SizeInBits() const {
101     DCHECK(is_valid());
102     return reg_size_;
103   }
SizeInBytes()104   int SizeInBytes() const {
105     DCHECK(is_valid());
106     DCHECK_EQ(SizeInBits() % 8, 0);
107     return reg_size_ / 8;
108   }
Is8Bits()109   bool Is8Bits() const {
110     DCHECK(is_valid());
111     return reg_size_ == 8;
112   }
Is16Bits()113   bool Is16Bits() const {
114     DCHECK(is_valid());
115     return reg_size_ == 16;
116   }
Is32Bits()117   bool Is32Bits() const {
118     DCHECK(is_valid());
119     return reg_size_ == 32;
120   }
Is64Bits()121   bool Is64Bits() const {
122     DCHECK(is_valid());
123     return reg_size_ == 64;
124   }
Is128Bits()125   bool Is128Bits() const {
126     DCHECK(is_valid());
127     return reg_size_ == 128;
128   }
IsNone()129   bool IsNone() const { return reg_type_ == kNoRegister; }
Aliases(const CPURegister & other)130   constexpr bool Aliases(const CPURegister& other) const {
131     return RegisterBase::operator==(other) && reg_type_ == other.reg_type_;
132   }
133 
134   constexpr bool operator==(const CPURegister& other) const {
135     return RegisterBase::operator==(other) && reg_size_ == other.reg_size_ &&
136            reg_type_ == other.reg_type_;
137   }
138   constexpr bool operator!=(const CPURegister& other) const {
139     return !operator==(other);
140   }
141 
142   bool IsZero() const;
143   bool IsSP() const;
144 
IsRegister()145   bool IsRegister() const { return reg_type_ == kRegister; }
IsVRegister()146   bool IsVRegister() const { return reg_type_ == kVRegister; }
147 
IsFPRegister()148   bool IsFPRegister() const { return IsS() || IsD(); }
149 
IsW()150   bool IsW() const { return IsRegister() && Is32Bits(); }
IsX()151   bool IsX() const { return IsRegister() && Is64Bits(); }
152 
153   // These assertions ensure that the size and type of the register are as
154   // described. They do not consider the number of lanes that make up a vector.
155   // So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD()
156   // does not imply Is1D() or Is8B().
157   // Check the number of lanes, ie. the format of the vector, using methods such
158   // as Is8B(), Is1D(), etc. in the VRegister class.
IsV()159   bool IsV() const { return IsVRegister(); }
IsB()160   bool IsB() const { return IsV() && Is8Bits(); }
IsH()161   bool IsH() const { return IsV() && Is16Bits(); }
IsS()162   bool IsS() const { return IsV() && Is32Bits(); }
IsD()163   bool IsD() const { return IsV() && Is64Bits(); }
IsQ()164   bool IsQ() const { return IsV() && Is128Bits(); }
165 
166   Register Reg() const;
167   VRegister VReg() const;
168 
169   Register X() const;
170   Register W() const;
171   VRegister V() const;
172   VRegister B() const;
173   VRegister H() const;
174   VRegister D() const;
175   VRegister S() const;
176   VRegister Q() const;
177 
178   bool IsSameSizeAndType(const CPURegister& other) const;
179 
180  protected:
181   int reg_size_;
182   RegisterType reg_type_;
183 
184 #if defined(V8_OS_WIN) && !defined(__clang__)
185   // MSVC has problem to parse template base class as friend class.
186   friend RegisterBase;
187 #else
188   friend class RegisterBase;
189 #endif
190 
CPURegister(int code,int size,RegisterType type)191   constexpr CPURegister(int code, int size, RegisterType type)
192       : RegisterBase(code), reg_size_(size), reg_type_(type) {}
193 
IsValidRegister(int code,int size)194   static constexpr bool IsValidRegister(int code, int size) {
195     return (size == kWRegSizeInBits || size == kXRegSizeInBits) &&
196            (code < kNumberOfRegisters || code == kSPRegInternalCode);
197   }
198 
IsValidVRegister(int code,int size)199   static constexpr bool IsValidVRegister(int code, int size) {
200     return (size == kBRegSizeInBits || size == kHRegSizeInBits ||
201             size == kSRegSizeInBits || size == kDRegSizeInBits ||
202             size == kQRegSizeInBits) &&
203            code < kNumberOfVRegisters;
204   }
205 
IsValid(int code,int size,RegisterType type)206   static constexpr bool IsValid(int code, int size, RegisterType type) {
207     return (type == kRegister && IsValidRegister(code, size)) ||
208            (type == kVRegister && IsValidVRegister(code, size));
209   }
210 
IsNone(int code,int size,RegisterType type)211   static constexpr bool IsNone(int code, int size, RegisterType type) {
212     return type == kNoRegister && code == 0 && size == 0;
213   }
214 };
215 
216 ASSERT_TRIVIALLY_COPYABLE(CPURegister);
217 
218 class Register : public CPURegister {
219  public:
no_reg()220   static constexpr Register no_reg() { return Register(CPURegister::no_reg()); }
221 
Create(int code,int size)222   static constexpr Register Create(int code, int size) {
223     return Register(CPURegister::Create(code, size, CPURegister::kRegister));
224   }
225 
226   static Register XRegFromCode(unsigned code);
227   static Register WRegFromCode(unsigned code);
228 
from_code(int code)229   static constexpr Register from_code(int code) {
230     // Always return an X register.
231     return Register::Create(code, kXRegSizeInBits);
232   }
233 
GetSpecialRegisterName(int code)234   static const char* GetSpecialRegisterName(int code) {
235     return (code == kSPRegInternalCode) ? "sp" : "UNKNOWN";
236   }
237 
238  private:
Register(const CPURegister & r)239   constexpr explicit Register(const CPURegister& r) : CPURegister(r) {}
240 };
241 
242 ASSERT_TRIVIALLY_COPYABLE(Register);
243 
244 constexpr bool kPadArguments = true;
245 constexpr bool kSimpleFPAliasing = true;
246 constexpr bool kSimdMaskRegisters = false;
247 
248 enum DoubleRegisterCode {
249 #define REGISTER_CODE(R) kDoubleCode_##R,
250   DOUBLE_REGISTERS(REGISTER_CODE)
251 #undef REGISTER_CODE
252       kDoubleAfterLast
253 };
254 
255 // Functions for handling NEON vector format information.
256 enum VectorFormat {
257   kFormatUndefined = 0xffffffff,
258   kFormat8B = NEON_8B,
259   kFormat16B = NEON_16B,
260   kFormat4H = NEON_4H,
261   kFormat8H = NEON_8H,
262   kFormat2S = NEON_2S,
263   kFormat4S = NEON_4S,
264   kFormat1D = NEON_1D,
265   kFormat2D = NEON_2D,
266 
267   // Scalar formats. We add the scalar bit to distinguish between scalar and
268   // vector enumerations; the bit is always set in the encoding of scalar ops
269   // and always clear for vector ops. Although kFormatD and kFormat1D appear
270   // to be the same, their meaning is subtly different. The first is a scalar
271   // operation, the second a vector operation that only affects one lane.
272   kFormatB = NEON_B | NEONScalar,
273   kFormatH = NEON_H | NEONScalar,
274   kFormatS = NEON_S | NEONScalar,
275   kFormatD = NEON_D | NEONScalar
276 };
277 
278 VectorFormat VectorFormatHalfWidth(VectorFormat vform);
279 VectorFormat VectorFormatDoubleWidth(VectorFormat vform);
280 VectorFormat VectorFormatDoubleLanes(VectorFormat vform);
281 VectorFormat VectorFormatHalfLanes(VectorFormat vform);
282 VectorFormat ScalarFormatFromLaneSize(int lanesize);
283 VectorFormat VectorFormatHalfWidthDoubleLanes(VectorFormat vform);
284 VectorFormat VectorFormatFillQ(int laneSize);
285 VectorFormat VectorFormatFillQ(VectorFormat vform);
286 VectorFormat ScalarFormatFromFormat(VectorFormat vform);
287 V8_EXPORT_PRIVATE unsigned RegisterSizeInBitsFromFormat(VectorFormat vform);
288 unsigned RegisterSizeInBytesFromFormat(VectorFormat vform);
289 int LaneSizeInBytesFromFormat(VectorFormat vform);
290 unsigned LaneSizeInBitsFromFormat(VectorFormat vform);
291 int LaneSizeInBytesLog2FromFormat(VectorFormat vform);
292 V8_EXPORT_PRIVATE int LaneCountFromFormat(VectorFormat vform);
293 int MaxLaneCountFromFormat(VectorFormat vform);
294 V8_EXPORT_PRIVATE bool IsVectorFormat(VectorFormat vform);
295 int64_t MaxIntFromFormat(VectorFormat vform);
296 int64_t MinIntFromFormat(VectorFormat vform);
297 uint64_t MaxUintFromFormat(VectorFormat vform);
298 
299 class VRegister : public CPURegister {
300  public:
no_reg()301   static constexpr VRegister no_reg() {
302     return VRegister(CPURegister::no_reg(), 0);
303   }
304 
305   static constexpr VRegister Create(int code, int size, int lane_count = 1) {
306     CONSTEXPR_DCHECK(IsValidLaneCount(lane_count));
307     return VRegister(CPURegister::Create(code, size, CPURegister::kVRegister),
308                      lane_count);
309   }
310 
Create(int reg_code,VectorFormat format)311   static VRegister Create(int reg_code, VectorFormat format) {
312     int reg_size = RegisterSizeInBitsFromFormat(format);
313     int reg_count = IsVectorFormat(format) ? LaneCountFromFormat(format) : 1;
314     return VRegister::Create(reg_code, reg_size, reg_count);
315   }
316 
317   static VRegister BRegFromCode(unsigned code);
318   static VRegister HRegFromCode(unsigned code);
319   static VRegister SRegFromCode(unsigned code);
320   static VRegister DRegFromCode(unsigned code);
321   static VRegister QRegFromCode(unsigned code);
322   static VRegister VRegFromCode(unsigned code);
323 
V8B()324   VRegister V8B() const {
325     return VRegister::Create(code(), kDRegSizeInBits, 8);
326   }
V16B()327   VRegister V16B() const {
328     return VRegister::Create(code(), kQRegSizeInBits, 16);
329   }
V4H()330   VRegister V4H() const {
331     return VRegister::Create(code(), kDRegSizeInBits, 4);
332   }
V8H()333   VRegister V8H() const {
334     return VRegister::Create(code(), kQRegSizeInBits, 8);
335   }
V2S()336   VRegister V2S() const {
337     return VRegister::Create(code(), kDRegSizeInBits, 2);
338   }
V4S()339   VRegister V4S() const {
340     return VRegister::Create(code(), kQRegSizeInBits, 4);
341   }
V2D()342   VRegister V2D() const {
343     return VRegister::Create(code(), kQRegSizeInBits, 2);
344   }
V1D()345   VRegister V1D() const {
346     return VRegister::Create(code(), kDRegSizeInBits, 1);
347   }
348 
Format(VectorFormat f)349   VRegister Format(VectorFormat f) const {
350     return VRegister::Create(code(), f);
351   }
352 
Is8B()353   bool Is8B() const { return (Is64Bits() && (lane_count_ == 8)); }
Is16B()354   bool Is16B() const { return (Is128Bits() && (lane_count_ == 16)); }
Is4H()355   bool Is4H() const { return (Is64Bits() && (lane_count_ == 4)); }
Is8H()356   bool Is8H() const { return (Is128Bits() && (lane_count_ == 8)); }
Is2S()357   bool Is2S() const { return (Is64Bits() && (lane_count_ == 2)); }
Is4S()358   bool Is4S() const { return (Is128Bits() && (lane_count_ == 4)); }
Is1D()359   bool Is1D() const { return (Is64Bits() && (lane_count_ == 1)); }
Is2D()360   bool Is2D() const { return (Is128Bits() && (lane_count_ == 2)); }
361 
362   // For consistency, we assert the number of lanes of these scalar registers,
363   // even though there are no vectors of equivalent total size with which they
364   // could alias.
Is1B()365   bool Is1B() const {
366     DCHECK(!(Is8Bits() && IsVector()));
367     return Is8Bits();
368   }
Is1H()369   bool Is1H() const {
370     DCHECK(!(Is16Bits() && IsVector()));
371     return Is16Bits();
372   }
Is1S()373   bool Is1S() const {
374     DCHECK(!(Is32Bits() && IsVector()));
375     return Is32Bits();
376   }
377 
IsLaneSizeB()378   bool IsLaneSizeB() const { return LaneSizeInBits() == kBRegSizeInBits; }
IsLaneSizeH()379   bool IsLaneSizeH() const { return LaneSizeInBits() == kHRegSizeInBits; }
IsLaneSizeS()380   bool IsLaneSizeS() const { return LaneSizeInBits() == kSRegSizeInBits; }
IsLaneSizeD()381   bool IsLaneSizeD() const { return LaneSizeInBits() == kDRegSizeInBits; }
382 
IsScalar()383   bool IsScalar() const { return lane_count_ == 1; }
IsVector()384   bool IsVector() const { return lane_count_ > 1; }
385 
IsSameFormat(const VRegister & other)386   bool IsSameFormat(const VRegister& other) const {
387     return (reg_size_ == other.reg_size_) && (lane_count_ == other.lane_count_);
388   }
389 
LaneCount()390   int LaneCount() const { return lane_count_; }
391 
LaneSizeInBytes()392   unsigned LaneSizeInBytes() const { return SizeInBytes() / lane_count_; }
393 
LaneSizeInBits()394   unsigned LaneSizeInBits() const { return LaneSizeInBytes() * 8; }
395 
396   static constexpr int kMaxNumRegisters = kNumberOfVRegisters;
397   STATIC_ASSERT(kMaxNumRegisters == kDoubleAfterLast);
398 
from_code(int code)399   static VRegister from_code(int code) {
400     // Always return a D register.
401     return VRegister::Create(code, kDRegSizeInBits);
402   }
403 
404  private:
405   int lane_count_;
406 
VRegister(const CPURegister & r,int lane_count)407   constexpr explicit VRegister(const CPURegister& r, int lane_count)
408       : CPURegister(r), lane_count_(lane_count) {}
409 
IsValidLaneCount(int lane_count)410   static constexpr bool IsValidLaneCount(int lane_count) {
411     return base::bits::IsPowerOfTwo(lane_count) && lane_count <= 16;
412   }
413 };
414 
415 ASSERT_TRIVIALLY_COPYABLE(VRegister);
416 
417 // No*Reg is used to indicate an unused argument, or an error case. Note that
418 // these all compare equal. The Register and VRegister variants are provided for
419 // convenience.
420 constexpr Register NoReg = Register::no_reg();
421 constexpr VRegister NoVReg = VRegister::no_reg();
422 constexpr CPURegister NoCPUReg = CPURegister::no_reg();
423 constexpr Register no_reg = NoReg;
424 constexpr VRegister no_dreg = NoVReg;
425 
426 #define DEFINE_REGISTER(register_class, name, ...) \
427   constexpr register_class name = register_class::Create(__VA_ARGS__)
428 #define ALIAS_REGISTER(register_class, alias, name) \
429   constexpr register_class alias = name
430 
431 #define DEFINE_REGISTERS(N)                            \
432   DEFINE_REGISTER(Register, w##N, N, kWRegSizeInBits); \
433   DEFINE_REGISTER(Register, x##N, N, kXRegSizeInBits);
434 GENERAL_REGISTER_CODE_LIST(DEFINE_REGISTERS)
435 #undef DEFINE_REGISTERS
436 
437 DEFINE_REGISTER(Register, wsp, kSPRegInternalCode, kWRegSizeInBits);
438 DEFINE_REGISTER(Register, sp, kSPRegInternalCode, kXRegSizeInBits);
439 
440 #define DEFINE_VREGISTERS(N)                            \
441   DEFINE_REGISTER(VRegister, b##N, N, kBRegSizeInBits); \
442   DEFINE_REGISTER(VRegister, h##N, N, kHRegSizeInBits); \
443   DEFINE_REGISTER(VRegister, s##N, N, kSRegSizeInBits); \
444   DEFINE_REGISTER(VRegister, d##N, N, kDRegSizeInBits); \
445   DEFINE_REGISTER(VRegister, q##N, N, kQRegSizeInBits); \
446   DEFINE_REGISTER(VRegister, v##N, N, kQRegSizeInBits);
447 GENERAL_REGISTER_CODE_LIST(DEFINE_VREGISTERS)
448 #undef DEFINE_VREGISTERS
449 
450 #undef DEFINE_REGISTER
451 
452 // Registers aliases.
453 ALIAS_REGISTER(VRegister, v8_, v8);  // Avoid conflicts with namespace v8.
454 ALIAS_REGISTER(Register, ip0, x16);
455 ALIAS_REGISTER(Register, ip1, x17);
456 ALIAS_REGISTER(Register, wip0, w16);
457 ALIAS_REGISTER(Register, wip1, w17);
458 // Root register.
459 ALIAS_REGISTER(Register, kRootRegister, x26);
460 ALIAS_REGISTER(Register, rr, x26);
461 // Context pointer register.
462 ALIAS_REGISTER(Register, cp, x27);
463 ALIAS_REGISTER(Register, fp, x29);
464 ALIAS_REGISTER(Register, lr, x30);
465 ALIAS_REGISTER(Register, xzr, x31);
466 ALIAS_REGISTER(Register, wzr, w31);
467 
468 // Register used for padding stack slots.
469 ALIAS_REGISTER(Register, padreg, x31);
470 
471 // Keeps the 0 double value.
472 ALIAS_REGISTER(VRegister, fp_zero, d15);
473 // MacroAssembler fixed V Registers.
474 // d29 is not part of ALLOCATABLE_DOUBLE_REGISTERS, so use 27 and 28.
475 ALIAS_REGISTER(VRegister, fp_fixed1, d27);
476 ALIAS_REGISTER(VRegister, fp_fixed2, d28);
477 
478 // MacroAssembler scratch V registers.
479 ALIAS_REGISTER(VRegister, fp_scratch, d30);
480 ALIAS_REGISTER(VRegister, fp_scratch1, d30);
481 ALIAS_REGISTER(VRegister, fp_scratch2, d31);
482 
483 #undef ALIAS_REGISTER
484 
485 // AreAliased returns true if any of the named registers overlap. Arguments set
486 // to NoReg are ignored. The system stack pointer may be specified.
487 V8_EXPORT_PRIVATE bool AreAliased(
488     const CPURegister& reg1, const CPURegister& reg2,
489     const CPURegister& reg3 = NoReg, const CPURegister& reg4 = NoReg,
490     const CPURegister& reg5 = NoReg, const CPURegister& reg6 = NoReg,
491     const CPURegister& reg7 = NoReg, const CPURegister& reg8 = NoReg);
492 
493 // AreSameSizeAndType returns true if all of the specified registers have the
494 // same size, and are of the same type. The system stack pointer may be
495 // specified. Arguments set to NoReg are ignored, as are any subsequent
496 // arguments. At least one argument (reg1) must be valid (not NoCPUReg).
497 V8_EXPORT_PRIVATE bool AreSameSizeAndType(
498     const CPURegister& reg1, const CPURegister& reg2 = NoCPUReg,
499     const CPURegister& reg3 = NoCPUReg, const CPURegister& reg4 = NoCPUReg,
500     const CPURegister& reg5 = NoCPUReg, const CPURegister& reg6 = NoCPUReg,
501     const CPURegister& reg7 = NoCPUReg, const CPURegister& reg8 = NoCPUReg);
502 
503 // AreSameFormat returns true if all of the specified VRegisters have the same
504 // vector format. Arguments set to NoVReg are ignored, as are any subsequent
505 // arguments. At least one argument (reg1) must be valid (not NoVReg).
506 bool AreSameFormat(const VRegister& reg1, const VRegister& reg2,
507                    const VRegister& reg3 = NoVReg,
508                    const VRegister& reg4 = NoVReg);
509 
510 // AreConsecutive returns true if all of the specified VRegisters are
511 // consecutive in the register file. Arguments may be set to NoVReg, and if so,
512 // subsequent arguments must also be NoVReg. At least one argument (reg1) must
513 // be valid (not NoVReg).
514 V8_EXPORT_PRIVATE bool AreConsecutive(const VRegister& reg1,
515                                       const VRegister& reg2,
516                                       const VRegister& reg3 = NoVReg,
517                                       const VRegister& reg4 = NoVReg);
518 
519 using FloatRegister = VRegister;
520 using DoubleRegister = VRegister;
521 using Simd128Register = VRegister;
522 
523 // -----------------------------------------------------------------------------
524 // Lists of registers.
525 class V8_EXPORT_PRIVATE CPURegList {
526  public:
527   template <typename... CPURegisters>
CPURegList(CPURegister reg0,CPURegisters...regs)528   explicit CPURegList(CPURegister reg0, CPURegisters... regs)
529       : list_(CPURegister::ListOf(reg0, regs...)),
530         size_(reg0.SizeInBits()),
531         type_(reg0.type()) {
532     DCHECK(AreSameSizeAndType(reg0, regs...));
533     DCHECK(is_valid());
534   }
535 
CPURegList(CPURegister::RegisterType type,int size,RegList list)536   CPURegList(CPURegister::RegisterType type, int size, RegList list)
537       : list_(list), size_(size), type_(type) {
538     DCHECK(is_valid());
539   }
540 
CPURegList(CPURegister::RegisterType type,int size,int first_reg,int last_reg)541   CPURegList(CPURegister::RegisterType type, int size, int first_reg,
542              int last_reg)
543       : size_(size), type_(type) {
544     DCHECK(
545         ((type == CPURegister::kRegister) && (last_reg < kNumberOfRegisters)) ||
546         ((type == CPURegister::kVRegister) &&
547          (last_reg < kNumberOfVRegisters)));
548     DCHECK(last_reg >= first_reg);
549     list_ = (1ULL << (last_reg + 1)) - 1;
550     list_ &= ~((1ULL << first_reg) - 1);
551     DCHECK(is_valid());
552   }
553 
type()554   CPURegister::RegisterType type() const {
555     return type_;
556   }
557 
list()558   RegList list() const {
559     return list_;
560   }
561 
set_list(RegList new_list)562   inline void set_list(RegList new_list) {
563     list_ = new_list;
564     DCHECK(is_valid());
565   }
566 
567   // Combine another CPURegList into this one. Registers that already exist in
568   // this list are left unchanged. The type and size of the registers in the
569   // 'other' list must match those in this list.
570   void Combine(const CPURegList& other);
571 
572   // Remove every register in the other CPURegList from this one. Registers that
573   // do not exist in this list are ignored. The type of the registers in the
574   // 'other' list must match those in this list.
575   void Remove(const CPURegList& other);
576 
577   // Variants of Combine and Remove which take CPURegisters.
578   void Combine(const CPURegister& other);
579   void Remove(const CPURegister& other1, const CPURegister& other2 = NoCPUReg,
580               const CPURegister& other3 = NoCPUReg,
581               const CPURegister& other4 = NoCPUReg);
582 
583   // Variants of Combine and Remove which take a single register by its code;
584   // the type and size of the register is inferred from this list.
585   void Combine(int code);
586   void Remove(int code);
587 
588   // Align the list to 16 bytes.
589   void Align();
590 
591   CPURegister PopLowestIndex();
592   CPURegister PopHighestIndex();
593 
594   // AAPCS64 callee-saved registers.
595   static CPURegList GetCalleeSaved(int size = kXRegSizeInBits);
596   static CPURegList GetCalleeSavedV(int size = kDRegSizeInBits);
597 
598   // AAPCS64 caller-saved registers. Note that this includes lr.
599   // TODO(all): Determine how we handle d8-d15 being callee-saved, but the top
600   // 64-bits being caller-saved.
601   static CPURegList GetCallerSaved(int size = kXRegSizeInBits);
602   static CPURegList GetCallerSavedV(int size = kDRegSizeInBits);
603 
IsEmpty()604   bool IsEmpty() const {
605     return list_ == 0;
606   }
607 
608   bool IncludesAliasOf(const CPURegister& other1,
609                        const CPURegister& other2 = NoCPUReg,
610                        const CPURegister& other3 = NoCPUReg,
611                        const CPURegister& other4 = NoCPUReg) const {
612     RegList list = 0;
613     if (!other1.IsNone() && (other1.type() == type_)) list |= other1.bit();
614     if (!other2.IsNone() && (other2.type() == type_)) list |= other2.bit();
615     if (!other3.IsNone() && (other3.type() == type_)) list |= other3.bit();
616     if (!other4.IsNone() && (other4.type() == type_)) list |= other4.bit();
617     return (list_ & list) != 0;
618   }
619 
Count()620   int Count() const {
621     return CountSetBits(list_, kRegListSizeInBits);
622   }
623 
RegisterSizeInBits()624   int RegisterSizeInBits() const {
625     return size_;
626   }
627 
RegisterSizeInBytes()628   int RegisterSizeInBytes() const {
629     int size_in_bits = RegisterSizeInBits();
630     DCHECK_EQ(size_in_bits % kBitsPerByte, 0);
631     return size_in_bits / kBitsPerByte;
632   }
633 
TotalSizeInBytes()634   int TotalSizeInBytes() const {
635     return RegisterSizeInBytes() * Count();
636   }
637 
638  private:
639   RegList list_;
640   int size_;
641   CPURegister::RegisterType type_;
642 
is_valid()643   bool is_valid() const {
644     constexpr RegList kValidRegisters{0x8000000ffffffff};
645     constexpr RegList kValidVRegisters{0x0000000ffffffff};
646     switch (type_) {
647       case CPURegister::kRegister:
648         return (list_ & kValidRegisters) == list_;
649       case CPURegister::kVRegister:
650         return (list_ & kValidVRegisters) == list_;
651       case CPURegister::kNoRegister:
652         return list_ == 0;
653       default:
654         UNREACHABLE();
655     }
656   }
657 };
658 
659 // AAPCS64 callee-saved registers.
660 #define kCalleeSaved CPURegList::GetCalleeSaved()
661 #define kCalleeSavedV CPURegList::GetCalleeSavedV()
662 
663 // AAPCS64 caller-saved registers. Note that this includes lr.
664 #define kCallerSaved CPURegList::GetCallerSaved()
665 #define kCallerSavedV CPURegList::GetCallerSavedV()
666 
667 // Define a {RegisterName} method for {Register} and {VRegister}.
668 DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
669 DEFINE_REGISTER_NAMES(VRegister, VECTOR_REGISTERS)
670 
671 // Give alias names to registers for calling conventions.
672 constexpr Register kReturnRegister0 = x0;
673 constexpr Register kReturnRegister1 = x1;
674 constexpr Register kReturnRegister2 = x2;
675 constexpr Register kJSFunctionRegister = x1;
676 constexpr Register kContextRegister = cp;
677 constexpr Register kAllocateSizeRegister = x1;
678 
679 constexpr Register kSpeculationPoisonRegister = x23;
680 
681 constexpr Register kInterpreterAccumulatorRegister = x0;
682 constexpr Register kInterpreterBytecodeOffsetRegister = x19;
683 constexpr Register kInterpreterBytecodeArrayRegister = x20;
684 constexpr Register kInterpreterDispatchTableRegister = x21;
685 
686 constexpr Register kJavaScriptCallArgCountRegister = x0;
687 constexpr Register kJavaScriptCallCodeStartRegister = x2;
688 constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
689 constexpr Register kJavaScriptCallNewTargetRegister = x3;
690 constexpr Register kJavaScriptCallExtraArg1Register = x2;
691 
692 constexpr Register kOffHeapTrampolineRegister = ip0;
693 constexpr Register kRuntimeCallFunctionRegister = x1;
694 constexpr Register kRuntimeCallArgCountRegister = x0;
695 constexpr Register kRuntimeCallArgvRegister = x11;
696 constexpr Register kWasmInstanceRegister = x7;
697 constexpr Register kWasmCompileLazyFuncIndexRegister = x8;
698 
699 constexpr DoubleRegister kFPReturnRegister0 = d0;
700 
701 }  // namespace internal
702 }  // namespace v8
703 
704 #endif  // V8_CODEGEN_ARM64_REGISTER_ARM64_H_
705