duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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