• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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_REGLIST_ARM64_H_
6 #define V8_CODEGEN_ARM64_REGLIST_ARM64_H_
7 
8 #include "src/codegen/arm64/utils-arm64.h"
9 #include "src/codegen/register-arch.h"
10 #include "src/codegen/reglist-base.h"
11 #include "src/common/globals.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 using RegList = RegListBase<Register>;
17 using DoubleRegList = RegListBase<DoubleRegister>;
18 ASSERT_TRIVIALLY_COPYABLE(RegList);
19 ASSERT_TRIVIALLY_COPYABLE(DoubleRegList);
20 
21 constexpr int kRegListSizeInBits = sizeof(RegList) * kBitsPerByte;
22 
23 // -----------------------------------------------------------------------------
24 // Lists of registers.
25 class V8_EXPORT_PRIVATE CPURegList {
26  public:
27   template <typename... CPURegisters>
CPURegList(CPURegister reg0,CPURegisters...regs)28   explicit CPURegList(CPURegister reg0, CPURegisters... regs)
29       : list_(((uint64_t{1} << reg0.code()) | ... |
30                (regs.is_valid() ? uint64_t{1} << regs.code() : 0))),
31         size_(reg0.SizeInBits()),
32         type_(reg0.type()) {
33     DCHECK(AreSameSizeAndType(reg0, regs...));
34     DCHECK(is_valid());
35   }
36 
CPURegList(int size,RegList list)37   CPURegList(int size, RegList list)
38       : list_(list.bits()), size_(size), type_(CPURegister::kRegister) {
39     DCHECK(is_valid());
40   }
41 
CPURegList(int size,DoubleRegList list)42   CPURegList(int size, DoubleRegList list)
43       : list_(list.bits()), size_(size), type_(CPURegister::kVRegister) {
44     DCHECK(is_valid());
45   }
46 
CPURegList(CPURegister::RegisterType type,int size,int first_reg,int last_reg)47   CPURegList(CPURegister::RegisterType type, int size, int first_reg,
48              int last_reg)
49       : size_(size), type_(type) {
50     DCHECK(
51         ((type == CPURegister::kRegister) && (last_reg < kNumberOfRegisters)) ||
52         ((type == CPURegister::kVRegister) &&
53          (last_reg < kNumberOfVRegisters)));
54     DCHECK(last_reg >= first_reg);
55     list_ = (1ULL << (last_reg + 1)) - 1;
56     list_ &= ~((1ULL << first_reg) - 1);
57     DCHECK(is_valid());
58   }
59 
type()60   CPURegister::RegisterType type() const { return type_; }
61 
bits()62   uint64_t bits() const { return list_; }
63 
set_bits(uint64_t new_bits)64   inline void set_bits(uint64_t new_bits) {
65     list_ = new_bits;
66     DCHECK(is_valid());
67   }
68 
69   // Combine another CPURegList into this one. Registers that already exist in
70   // this list are left unchanged. The type and size of the registers in the
71   // 'other' list must match those in this list.
72   void Combine(const CPURegList& other);
73 
74   // Remove every register in the other CPURegList from this one. Registers that
75   // do not exist in this list are ignored. The type of the registers in the
76   // 'other' list must match those in this list.
77   void Remove(const CPURegList& other);
78 
79   // Variants of Combine and Remove which take CPURegisters.
80   void Combine(const CPURegister& other);
81   void Remove(const CPURegister& other1, const CPURegister& other2 = NoCPUReg,
82               const CPURegister& other3 = NoCPUReg,
83               const CPURegister& other4 = NoCPUReg);
84 
85   // Variants of Combine and Remove which take a single register by its code;
86   // the type and size of the register is inferred from this list.
87   void Combine(int code);
88   void Remove(int code);
89 
90   // Align the list to 16 bytes.
91   void Align();
92 
93   CPURegister PopLowestIndex();
94   CPURegister PopHighestIndex();
95 
96   // AAPCS64 callee-saved registers.
97   static CPURegList GetCalleeSaved(int size = kXRegSizeInBits);
98   static CPURegList GetCalleeSavedV(int size = kDRegSizeInBits);
99 
100   // AAPCS64 caller-saved registers. Note that this includes lr.
101   // TODO(all): Determine how we handle d8-d15 being callee-saved, but the top
102   // 64-bits being caller-saved.
103   static CPURegList GetCallerSaved(int size = kXRegSizeInBits);
104   static CPURegList GetCallerSavedV(int size = kDRegSizeInBits);
105 
IsEmpty()106   bool IsEmpty() const { return list_ == 0; }
107 
108   bool IncludesAliasOf(const CPURegister& other1,
109                        const CPURegister& other2 = NoCPUReg,
110                        const CPURegister& other3 = NoCPUReg,
111                        const CPURegister& other4 = NoCPUReg) const {
112     uint64_t list = 0;
113     if (!other1.IsNone() && (other1.type() == type_)) {
114       list |= (uint64_t{1} << other1.code());
115     }
116     if (!other2.IsNone() && (other2.type() == type_)) {
117       list |= (uint64_t{1} << other2.code());
118     }
119     if (!other3.IsNone() && (other3.type() == type_)) {
120       list |= (uint64_t{1} << other3.code());
121     }
122     if (!other4.IsNone() && (other4.type() == type_)) {
123       list |= (uint64_t{1} << other4.code());
124     }
125     return (list_ & list) != 0;
126   }
127 
Count()128   int Count() const { return CountSetBits(list_, kRegListSizeInBits); }
129 
RegisterSizeInBits()130   int RegisterSizeInBits() const { return size_; }
131 
RegisterSizeInBytes()132   int RegisterSizeInBytes() const {
133     int size_in_bits = RegisterSizeInBits();
134     DCHECK_EQ(size_in_bits % kBitsPerByte, 0);
135     return size_in_bits / kBitsPerByte;
136   }
137 
TotalSizeInBytes()138   int TotalSizeInBytes() const { return RegisterSizeInBytes() * Count(); }
139 
140  private:
141   uint64_t list_;
142   int size_;
143   CPURegister::RegisterType type_;
144 
is_valid()145   bool is_valid() const {
146     constexpr uint64_t kValidRegisters{0x8000000ffffffff};
147     constexpr uint64_t kValidVRegisters{0x0000000ffffffff};
148     switch (type_) {
149       case CPURegister::kRegister:
150         return (list_ & kValidRegisters) == list_;
151       case CPURegister::kVRegister:
152         return (list_ & kValidVRegisters) == list_;
153       case CPURegister::kNoRegister:
154         return list_ == 0;
155       default:
156         UNREACHABLE();
157     }
158   }
159 };
160 
161 // AAPCS64 callee-saved registers.
162 #define kCalleeSaved CPURegList::GetCalleeSaved()
163 #define kCalleeSavedV CPURegList::GetCalleeSavedV()
164 
165 // AAPCS64 caller-saved registers. Note that this includes lr.
166 #define kCallerSaved CPURegList::GetCallerSaved()
167 #define kCallerSavedV CPURegList::GetCallerSavedV()
168 
169 }  // namespace internal
170 }  // namespace v8
171 
172 #endif  // V8_CODEGEN_ARM64_REGLIST_ARM64_H_
173