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