registers-aarch64.cc (11628B)
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