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