Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/vixl/src/aarch64/registers-aarch64.cc
6242 views
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 "registers-aarch64.h"
28
29
#include <sstream>
30
#include <string>
31
32
namespace vixl {
33
namespace aarch64 {
34
35
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
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
83
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
90
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
98
bool CPURegister::IsValidFPRegister() const {
99
return IsValidVRegister() && IsFPRegister();
100
}
101
102
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
110
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
120
bool CPURegister::IsValid() const {
121
return IsValidRegister() || IsValidVRegister() || IsValidZRegister() ||
122
IsValidPRegister();
123
}
124
125
// Most coercions 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 coercions 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
V(1, Q)
158
#define VIXL_DEFINE_CPUREG_NEON_COERCION(LANES, LANE_TYPE) \
159
VRegister VRegister::V##LANES##LANE_TYPE() const { \
160
VIXL_ASSERT(IsVRegister()); \
161
return VRegister(GetCode(), LANES * k##LANE_TYPE##RegSize, LANES); \
162
}
163
VIXL_CPUREG_NEON_COERCION_LIST(VIXL_DEFINE_CPUREG_NEON_COERCION)
164
#undef VIXL_CPUREG_NEON_COERCION_LIST
165
#undef VIXL_DEFINE_CPUREG_NEON_COERCION
166
167
// Semantic type coercion for sdot and udot.
168
// TODO: Use the qualifiers_ field to distinguish this from ::S().
169
VRegister VRegister::S4B() const {
170
VIXL_ASSERT(IsVRegister());
171
return SRegister(GetCode());
172
}
173
174
bool AreAliased(const CPURegister& reg1,
175
const CPURegister& reg2,
176
const CPURegister& reg3,
177
const CPURegister& reg4,
178
const CPURegister& reg5,
179
const CPURegister& reg6,
180
const CPURegister& reg7,
181
const CPURegister& reg8) {
182
int number_of_valid_regs = 0;
183
int number_of_valid_vregs = 0;
184
int number_of_valid_pregs = 0;
185
186
RegList unique_regs = 0;
187
RegList unique_vregs = 0;
188
RegList unique_pregs = 0;
189
190
const CPURegister regs[] = {reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8};
191
192
for (size_t i = 0; i < ArrayLength(regs); i++) {
193
switch (regs[i].GetBank()) {
194
case CPURegister::kRRegisterBank:
195
number_of_valid_regs++;
196
unique_regs |= regs[i].GetBit();
197
break;
198
case CPURegister::kVRegisterBank:
199
number_of_valid_vregs++;
200
unique_vregs |= regs[i].GetBit();
201
break;
202
case CPURegister::kPRegisterBank:
203
number_of_valid_pregs++;
204
unique_pregs |= regs[i].GetBit();
205
break;
206
case CPURegister::kNoRegisterBank:
207
VIXL_ASSERT(regs[i].IsNone());
208
break;
209
}
210
}
211
212
int number_of_unique_regs = CountSetBits(unique_regs);
213
int number_of_unique_vregs = CountSetBits(unique_vregs);
214
int number_of_unique_pregs = CountSetBits(unique_pregs);
215
216
VIXL_ASSERT(number_of_valid_regs >= number_of_unique_regs);
217
VIXL_ASSERT(number_of_valid_vregs >= number_of_unique_vregs);
218
VIXL_ASSERT(number_of_valid_pregs >= number_of_unique_pregs);
219
220
return (number_of_valid_regs != number_of_unique_regs) ||
221
(number_of_valid_vregs != number_of_unique_vregs) ||
222
(number_of_valid_pregs != number_of_unique_pregs);
223
}
224
225
bool AreSameSizeAndType(const CPURegister& reg1,
226
const CPURegister& reg2,
227
const CPURegister& reg3,
228
const CPURegister& reg4,
229
const CPURegister& reg5,
230
const CPURegister& reg6,
231
const CPURegister& reg7,
232
const CPURegister& reg8) {
233
VIXL_ASSERT(reg1.IsValid());
234
bool match = true;
235
match &= !reg2.IsValid() || reg2.IsSameSizeAndType(reg1);
236
match &= !reg3.IsValid() || reg3.IsSameSizeAndType(reg1);
237
match &= !reg4.IsValid() || reg4.IsSameSizeAndType(reg1);
238
match &= !reg5.IsValid() || reg5.IsSameSizeAndType(reg1);
239
match &= !reg6.IsValid() || reg6.IsSameSizeAndType(reg1);
240
match &= !reg7.IsValid() || reg7.IsSameSizeAndType(reg1);
241
match &= !reg8.IsValid() || reg8.IsSameSizeAndType(reg1);
242
return match;
243
}
244
245
bool AreEven(const CPURegister& reg1,
246
const CPURegister& reg2,
247
const CPURegister& reg3,
248
const CPURegister& reg4,
249
const CPURegister& reg5,
250
const CPURegister& reg6,
251
const CPURegister& reg7,
252
const CPURegister& reg8) {
253
VIXL_ASSERT(reg1.IsValid());
254
bool even = (reg1.GetCode() % 2) == 0;
255
even &= !reg2.IsValid() || ((reg2.GetCode() % 2) == 0);
256
even &= !reg3.IsValid() || ((reg3.GetCode() % 2) == 0);
257
even &= !reg4.IsValid() || ((reg4.GetCode() % 2) == 0);
258
even &= !reg5.IsValid() || ((reg5.GetCode() % 2) == 0);
259
even &= !reg6.IsValid() || ((reg6.GetCode() % 2) == 0);
260
even &= !reg7.IsValid() || ((reg7.GetCode() % 2) == 0);
261
even &= !reg8.IsValid() || ((reg8.GetCode() % 2) == 0);
262
return even;
263
}
264
265
bool AreConsecutive(const CPURegister& reg1,
266
const CPURegister& reg2,
267
const CPURegister& reg3,
268
const CPURegister& reg4) {
269
VIXL_ASSERT(reg1.IsValid());
270
271
if (!reg2.IsValid()) {
272
return true;
273
} else if (reg2.GetCode() !=
274
((reg1.GetCode() + 1) % (reg1.GetMaxCode() + 1))) {
275
return false;
276
}
277
278
if (!reg3.IsValid()) {
279
return true;
280
} else if (reg3.GetCode() !=
281
((reg2.GetCode() + 1) % (reg1.GetMaxCode() + 1))) {
282
return false;
283
}
284
285
if (!reg4.IsValid()) {
286
return true;
287
} else if (reg4.GetCode() !=
288
((reg3.GetCode() + 1) % (reg1.GetMaxCode() + 1))) {
289
return false;
290
}
291
292
return true;
293
}
294
295
bool AreSameFormat(const CPURegister& reg1,
296
const CPURegister& reg2,
297
const CPURegister& reg3,
298
const CPURegister& reg4) {
299
VIXL_ASSERT(reg1.IsValid());
300
bool match = true;
301
match &= !reg2.IsValid() || reg2.IsSameFormat(reg1);
302
match &= !reg3.IsValid() || reg3.IsSameFormat(reg1);
303
match &= !reg4.IsValid() || reg4.IsSameFormat(reg1);
304
return match;
305
}
306
307
bool AreSameLaneSize(const CPURegister& reg1,
308
const CPURegister& reg2,
309
const CPURegister& reg3,
310
const CPURegister& reg4) {
311
VIXL_ASSERT(reg1.IsValid());
312
bool match = true;
313
match &=
314
!reg2.IsValid() || (reg2.GetLaneSizeInBits() == reg1.GetLaneSizeInBits());
315
match &=
316
!reg3.IsValid() || (reg3.GetLaneSizeInBits() == reg1.GetLaneSizeInBits());
317
match &=
318
!reg4.IsValid() || (reg4.GetLaneSizeInBits() == reg1.GetLaneSizeInBits());
319
return match;
320
}
321
} // namespace aarch64
322
} // namespace vixl
323
324