1 // Copyright 2019, VIXL authors
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright notice,
8 // this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright notice,
10 // this list of conditions and the following disclaimer in the documentation
11 // and/or other materials provided with the distribution.
12 // * Neither the name of ARM Limited nor the names of its contributors may be
13 // used to endorse or promote products derived from this software without
14 // specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 #include <sstream>
28 #include <string>
29
30 #include "registers-aarch64.h"
31
32 namespace vixl {
33 namespace aarch64 {
34
GetArchitecturalName() const35 std::string CPURegister::GetArchitecturalName() const {
36 std::ostringstream name;
37 if (IsZRegister()) {
38 name << 'z' << GetCode();
39 if (HasLaneSize()) {
40 name << '.' << GetLaneSizeSymbol();
41 }
42 } else if (IsPRegister()) {
43 name << 'p' << GetCode();
44 if (HasLaneSize()) {
45 name << '.' << GetLaneSizeSymbol();
46 }
47 switch (qualifiers_) {
48 case kNoQualifiers:
49 break;
50 case kMerging:
51 name << "/m";
52 break;
53 case kZeroing:
54 name << "/z";
55 break;
56 }
57 } else {
58 VIXL_UNIMPLEMENTED();
59 }
60 return name.str();
61 }
62
GetMaxCodeFor(CPURegister::RegisterBank bank)63 unsigned CPURegister::GetMaxCodeFor(CPURegister::RegisterBank bank) {
64 switch (bank) {
65 case kNoRegisterBank:
66 return 0;
67 case kRRegisterBank:
68 return Register::GetMaxCode();
69 case kVRegisterBank:
70 #ifdef VIXL_HAS_CONSTEXPR
71 VIXL_STATIC_ASSERT(VRegister::GetMaxCode() == ZRegister::GetMaxCode());
72 #else
73 VIXL_ASSERT(VRegister::GetMaxCode() == ZRegister::GetMaxCode());
74 #endif
75 return VRegister::GetMaxCode();
76 case kPRegisterBank:
77 return PRegister::GetMaxCode();
78 }
79 VIXL_UNREACHABLE();
80 return 0;
81 }
82
IsValidRegister() const83 bool CPURegister::IsValidRegister() const {
84 return ((code_ < kNumberOfRegisters) || (code_ == kSPRegInternalCode)) &&
85 (bank_ == kRRegisterBank) &&
86 ((size_ == kEncodedWRegSize) || (size_ == kEncodedXRegSize)) &&
87 (qualifiers_ == kNoQualifiers) && (lane_size_ == size_);
88 }
89
IsValidVRegister() const90 bool CPURegister::IsValidVRegister() const {
91 VIXL_STATIC_ASSERT(kEncodedBRegSize < kEncodedQRegSize);
92 return (code_ < kNumberOfVRegisters) && (bank_ == kVRegisterBank) &&
93 ((size_ >= kEncodedBRegSize) && (size_ <= kEncodedQRegSize)) &&
94 (qualifiers_ == kNoQualifiers) &&
95 (lane_size_ != kEncodedUnknownSize) && (lane_size_ <= size_);
96 }
97
IsValidFPRegister() const98 bool CPURegister::IsValidFPRegister() const {
99 return IsValidVRegister() && IsFPRegister();
100 }
101
IsValidZRegister() const102 bool CPURegister::IsValidZRegister() const {
103 VIXL_STATIC_ASSERT(kEncodedBRegSize < kEncodedQRegSize);
104 // Z registers are valid with or without a lane size, so we don't need to
105 // check lane_size_.
106 return (code_ < kNumberOfZRegisters) && (bank_ == kVRegisterBank) &&
107 (size_ == kEncodedUnknownSize) && (qualifiers_ == kNoQualifiers);
108 }
109
IsValidPRegister() const110 bool CPURegister::IsValidPRegister() const {
111 VIXL_STATIC_ASSERT(kEncodedBRegSize < kEncodedQRegSize);
112 // P registers are valid with or without a lane size, so we don't need to
113 // check lane_size_.
114 return (code_ < kNumberOfPRegisters) && (bank_ == kPRegisterBank) &&
115 (size_ == kEncodedUnknownSize) &&
116 ((qualifiers_ == kNoQualifiers) || (qualifiers_ == kMerging) ||
117 (qualifiers_ == kZeroing));
118 }
119
IsValid() const120 bool CPURegister::IsValid() const {
121 return IsValidRegister() || IsValidVRegister() || IsValidZRegister() ||
122 IsValidPRegister();
123 }
124
125 // Most coersions simply invoke the necessary constructor.
126 #define VIXL_CPUREG_COERCION_LIST(U) \
127 U(Register, W, R) \
128 U(Register, X, R) \
129 U(VRegister, B, V) \
130 U(VRegister, H, V) \
131 U(VRegister, S, V) \
132 U(VRegister, D, V) \
133 U(VRegister, Q, V) \
134 U(VRegister, V, V) \
135 U(ZRegister, Z, V) \
136 U(PRegister, P, P)
137 #define VIXL_DEFINE_CPUREG_COERCION(RET_TYPE, CTOR_TYPE, BANK) \
138 RET_TYPE CPURegister::CTOR_TYPE() const { \
139 VIXL_ASSERT(GetBank() == k##BANK##RegisterBank); \
140 return CTOR_TYPE##Register(GetCode()); \
141 }
142 VIXL_CPUREG_COERCION_LIST(VIXL_DEFINE_CPUREG_COERCION)
143 #undef VIXL_CPUREG_COERCION_LIST
144 #undef VIXL_DEFINE_CPUREG_COERCION
145
146 // NEON lane-format coersions always return VRegisters.
147 #define VIXL_CPUREG_NEON_COERCION_LIST(V) \
148 V(8, B) \
149 V(16, B) \
150 V(2, H) \
151 V(4, H) \
152 V(8, H) \
153 V(2, S) \
154 V(4, S) \
155 V(1, D) \
156 V(2, D)
157 #define VIXL_DEFINE_CPUREG_NEON_COERCION(LANES, LANE_TYPE) \
158 VRegister VRegister::V##LANES##LANE_TYPE() const { \
159 VIXL_ASSERT(IsVRegister()); \
160 return VRegister(GetCode(), LANES * k##LANE_TYPE##RegSize, LANES); \
161 }
VIXL_CPUREG_NEON_COERCION_LIST(VIXL_DEFINE_CPUREG_NEON_COERCION)162 VIXL_CPUREG_NEON_COERCION_LIST(VIXL_DEFINE_CPUREG_NEON_COERCION)
163 #undef VIXL_CPUREG_NEON_COERCION_LIST
164 #undef VIXL_DEFINE_CPUREG_NEON_COERCION
165
166 // Semantic type coersion for sdot and udot.
167 // TODO: Use the qualifiers_ field to distinguish this from ::S().
168 VRegister VRegister::S4B() const {
169 VIXL_ASSERT(IsVRegister());
170 return SRegister(GetCode());
171 }
172
AreAliased(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4,const CPURegister & reg5,const CPURegister & reg6,const CPURegister & reg7,const CPURegister & reg8)173 bool AreAliased(const CPURegister& reg1,
174 const CPURegister& reg2,
175 const CPURegister& reg3,
176 const CPURegister& reg4,
177 const CPURegister& reg5,
178 const CPURegister& reg6,
179 const CPURegister& reg7,
180 const CPURegister& reg8) {
181 int number_of_valid_regs = 0;
182 int number_of_valid_vregs = 0;
183 int number_of_valid_pregs = 0;
184
185 RegList unique_regs = 0;
186 RegList unique_vregs = 0;
187 RegList unique_pregs = 0;
188
189 const CPURegister regs[] = {reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8};
190
191 for (size_t i = 0; i < ArrayLength(regs); i++) {
192 switch (regs[i].GetBank()) {
193 case CPURegister::kRRegisterBank:
194 number_of_valid_regs++;
195 unique_regs |= regs[i].GetBit();
196 break;
197 case CPURegister::kVRegisterBank:
198 number_of_valid_vregs++;
199 unique_vregs |= regs[i].GetBit();
200 break;
201 case CPURegister::kPRegisterBank:
202 number_of_valid_pregs++;
203 unique_pregs |= regs[i].GetBit();
204 break;
205 case CPURegister::kNoRegisterBank:
206 VIXL_ASSERT(regs[i].IsNone());
207 break;
208 }
209 }
210
211 int number_of_unique_regs = CountSetBits(unique_regs);
212 int number_of_unique_vregs = CountSetBits(unique_vregs);
213 int number_of_unique_pregs = CountSetBits(unique_pregs);
214
215 VIXL_ASSERT(number_of_valid_regs >= number_of_unique_regs);
216 VIXL_ASSERT(number_of_valid_vregs >= number_of_unique_vregs);
217 VIXL_ASSERT(number_of_valid_pregs >= number_of_unique_pregs);
218
219 return (number_of_valid_regs != number_of_unique_regs) ||
220 (number_of_valid_vregs != number_of_unique_vregs) ||
221 (number_of_valid_pregs != number_of_unique_pregs);
222 }
223
AreSameSizeAndType(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4,const CPURegister & reg5,const CPURegister & reg6,const CPURegister & reg7,const CPURegister & reg8)224 bool AreSameSizeAndType(const CPURegister& reg1,
225 const CPURegister& reg2,
226 const CPURegister& reg3,
227 const CPURegister& reg4,
228 const CPURegister& reg5,
229 const CPURegister& reg6,
230 const CPURegister& reg7,
231 const CPURegister& reg8) {
232 VIXL_ASSERT(reg1.IsValid());
233 bool match = true;
234 match &= !reg2.IsValid() || reg2.IsSameSizeAndType(reg1);
235 match &= !reg3.IsValid() || reg3.IsSameSizeAndType(reg1);
236 match &= !reg4.IsValid() || reg4.IsSameSizeAndType(reg1);
237 match &= !reg5.IsValid() || reg5.IsSameSizeAndType(reg1);
238 match &= !reg6.IsValid() || reg6.IsSameSizeAndType(reg1);
239 match &= !reg7.IsValid() || reg7.IsSameSizeAndType(reg1);
240 match &= !reg8.IsValid() || reg8.IsSameSizeAndType(reg1);
241 return match;
242 }
243
AreEven(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4,const CPURegister & reg5,const CPURegister & reg6,const CPURegister & reg7,const CPURegister & reg8)244 bool AreEven(const CPURegister& reg1,
245 const CPURegister& reg2,
246 const CPURegister& reg3,
247 const CPURegister& reg4,
248 const CPURegister& reg5,
249 const CPURegister& reg6,
250 const CPURegister& reg7,
251 const CPURegister& reg8) {
252 VIXL_ASSERT(reg1.IsValid());
253 bool even = (reg1.GetCode() % 2) == 0;
254 even &= !reg2.IsValid() || ((reg2.GetCode() % 2) == 0);
255 even &= !reg3.IsValid() || ((reg3.GetCode() % 2) == 0);
256 even &= !reg4.IsValid() || ((reg4.GetCode() % 2) == 0);
257 even &= !reg5.IsValid() || ((reg5.GetCode() % 2) == 0);
258 even &= !reg6.IsValid() || ((reg6.GetCode() % 2) == 0);
259 even &= !reg7.IsValid() || ((reg7.GetCode() % 2) == 0);
260 even &= !reg8.IsValid() || ((reg8.GetCode() % 2) == 0);
261 return even;
262 }
263
AreConsecutive(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4)264 bool AreConsecutive(const CPURegister& reg1,
265 const CPURegister& reg2,
266 const CPURegister& reg3,
267 const CPURegister& reg4) {
268 VIXL_ASSERT(reg1.IsValid());
269
270 if (!reg2.IsValid()) {
271 return true;
272 } else if (reg2.GetCode() !=
273 ((reg1.GetCode() + 1) % (reg1.GetMaxCode() + 1))) {
274 return false;
275 }
276
277 if (!reg3.IsValid()) {
278 return true;
279 } else if (reg3.GetCode() !=
280 ((reg2.GetCode() + 1) % (reg1.GetMaxCode() + 1))) {
281 return false;
282 }
283
284 if (!reg4.IsValid()) {
285 return true;
286 } else if (reg4.GetCode() !=
287 ((reg3.GetCode() + 1) % (reg1.GetMaxCode() + 1))) {
288 return false;
289 }
290
291 return true;
292 }
293
AreSameFormat(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4)294 bool AreSameFormat(const CPURegister& reg1,
295 const CPURegister& reg2,
296 const CPURegister& reg3,
297 const CPURegister& reg4) {
298 VIXL_ASSERT(reg1.IsValid());
299 bool match = true;
300 match &= !reg2.IsValid() || reg2.IsSameFormat(reg1);
301 match &= !reg3.IsValid() || reg3.IsSameFormat(reg1);
302 match &= !reg4.IsValid() || reg4.IsSameFormat(reg1);
303 return match;
304 }
305
AreSameLaneSize(const CPURegister & reg1,const CPURegister & reg2,const CPURegister & reg3,const CPURegister & reg4)306 bool AreSameLaneSize(const CPURegister& reg1,
307 const CPURegister& reg2,
308 const CPURegister& reg3,
309 const CPURegister& reg4) {
310 VIXL_ASSERT(reg1.IsValid());
311 bool match = true;
312 match &=
313 !reg2.IsValid() || (reg2.GetLaneSizeInBits() == reg1.GetLaneSizeInBits());
314 match &=
315 !reg3.IsValid() || (reg3.GetLaneSizeInBits() == reg1.GetLaneSizeInBits());
316 match &=
317 !reg4.IsValid() || (reg4.GetLaneSizeInBits() == reg1.GetLaneSizeInBits());
318 return match;
319 }
320 }
321 } // namespace vixl::aarch64
322