LCOV - code coverage report
Current view: top level - src/wasm/baseline - liftoff-register.h (source / functions) Hit Total Coverage
Test: app.info Lines: 26 33 78.8 %
Date: 2019-04-17 Functions: 1 2 50.0 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #ifndef V8_WASM_BASELINE_LIFTOFF_REGISTER_H_
       6             : #define V8_WASM_BASELINE_LIFTOFF_REGISTER_H_
       7             : 
       8             : #include <iosfwd>
       9             : #include <memory>
      10             : 
      11             : #include "src/base/bits.h"
      12             : #include "src/wasm/baseline/liftoff-assembler-defs.h"
      13             : #include "src/wasm/wasm-opcodes.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : namespace wasm {
      18             : 
      19             : static constexpr bool kNeedI64RegPair = kSystemPointerSize == 4;
      20             : 
      21             : enum RegClass : uint8_t {
      22             :   kGpReg,
      23             :   kFpReg,
      24             :   // {kGpRegPair} equals {kNoReg} if {kNeedI64RegPair} is false.
      25             :   kGpRegPair,
      26             :   kNoReg = kGpRegPair + kNeedI64RegPair
      27             : };
      28             : 
      29             : enum RegPairHalf : uint8_t { kLowWord = 0, kHighWord = 1 };
      30             : 
      31             : static inline constexpr bool needs_reg_pair(ValueType type) {
      32             :   return kNeedI64RegPair && type == kWasmI64;
      33             : }
      34             : 
      35             : // TODO(clemensh): Use a switch once we require C++14 support.
      36             : static inline constexpr RegClass reg_class_for(ValueType type) {
      37             :   return needs_reg_pair(type)  // i64 on 32 bit
      38             :              ? kGpRegPair
      39      798083 :              : type == kWasmI32 || type == kWasmI64  // int types
      40             :                    ? kGpReg
      41      150994 :                    : type == kWasmF32 || type == kWasmF64  // float types
      42             :                          ? kFpReg
      43      949077 :                          : kNoReg;  // other (unsupported) types
      44             : }
      45             : 
      46             : // Maximum code of a gp cache register.
      47             : static constexpr int kMaxGpRegCode =
      48             :     8 * sizeof(kLiftoffAssemblerGpCacheRegs) -
      49             :     base::bits::CountLeadingZeros(kLiftoffAssemblerGpCacheRegs) - 1;
      50             : // Maximum code of an fp cache register.
      51             : static constexpr int kMaxFpRegCode =
      52             :     8 * sizeof(kLiftoffAssemblerFpCacheRegs) -
      53             :     base::bits::CountLeadingZeros(kLiftoffAssemblerFpCacheRegs) - 1;
      54             : // LiftoffRegister encodes both gp and fp in a unified index space.
      55             : // [0 .. kMaxGpRegCode] encodes gp registers,
      56             : // [kMaxGpRegCode+1 .. kMaxGpRegCode + kMaxFpRegCode] encodes fp registers.
      57             : // I64 values on 32 bit platforms are stored in two registers, both encoded in
      58             : // the same LiftoffRegister value.
      59             : static constexpr int kAfterMaxLiftoffGpRegCode = kMaxGpRegCode + 1;
      60             : static constexpr int kAfterMaxLiftoffFpRegCode =
      61             :     kAfterMaxLiftoffGpRegCode + kMaxFpRegCode + 1;
      62             : static constexpr int kAfterMaxLiftoffRegCode = kAfterMaxLiftoffFpRegCode;
      63             : static constexpr int kBitsPerLiftoffRegCode =
      64             :     32 - base::bits::CountLeadingZeros<uint32_t>(kAfterMaxLiftoffRegCode - 1);
      65             : static constexpr int kBitsPerGpRegCode =
      66             :     32 - base::bits::CountLeadingZeros<uint32_t>(kMaxGpRegCode);
      67             : static constexpr int kBitsPerGpRegPair = 1 + 2 * kBitsPerGpRegCode;
      68             : 
      69             : class LiftoffRegister {
      70             :   static constexpr int needed_bits =
      71             :       Max(kNeedI64RegPair ? kBitsPerGpRegPair : 0, kBitsPerLiftoffRegCode);
      72             :   using storage_t = std::conditional<
      73             :       needed_bits <= 8, uint8_t,
      74             :       std::conditional<needed_bits <= 16, uint16_t, uint32_t>::type>::type;
      75             : 
      76             :   static_assert(8 * sizeof(storage_t) >= needed_bits,
      77             :                 "chosen type is big enough");
      78             :   // Check for smallest required data type being chosen.
      79             :   // Special case for uint8_t as there are no smaller types.
      80             :   static_assert((8 * sizeof(storage_t) < 2 * needed_bits) ||
      81             :                     (sizeof(storage_t) == sizeof(uint8_t)),
      82             :                 "chosen type is small enough");
      83             : 
      84             :  public:
      85             :   explicit LiftoffRegister(Register reg) : LiftoffRegister(reg.code()) {
      86             :     DCHECK_NE(0, kLiftoffAssemblerGpCacheRegs & reg.bit());
      87             :     DCHECK_EQ(reg, gp());
      88             :   }
      89             :   explicit LiftoffRegister(DoubleRegister reg)
      90      121636 :       : LiftoffRegister(kAfterMaxLiftoffGpRegCode + reg.code()) {
      91             :     DCHECK_NE(0, kLiftoffAssemblerFpCacheRegs & reg.bit());
      92             :     DCHECK_EQ(reg, fp());
      93             :   }
      94             : 
      95             :   static LiftoffRegister from_liftoff_code(uint32_t code) {
      96             :     DCHECK_LE(0, code);
      97             :     DCHECK_GT(kAfterMaxLiftoffRegCode, code);
      98             :     DCHECK_EQ(code, static_cast<storage_t>(code));
      99             :     return LiftoffRegister(code);
     100             :   }
     101             : 
     102      232968 :   static LiftoffRegister from_code(RegClass rc, int code) {
     103      232968 :     switch (rc) {
     104             :       case kGpReg:
     105      111332 :         return LiftoffRegister(Register::from_code(code));
     106             :       case kFpReg:
     107      121636 :         return LiftoffRegister(DoubleRegister::from_code(code));
     108             :       default:
     109           0 :         UNREACHABLE();
     110             :     }
     111             :   }
     112             : 
     113             :   static LiftoffRegister ForPair(Register low, Register high) {
     114             :     DCHECK(kNeedI64RegPair);
     115             :     DCHECK_NE(low, high);
     116           0 :     storage_t combined_code = low.code() | high.code() << kBitsPerGpRegCode |
     117           0 :                               1 << (2 * kBitsPerGpRegCode);
     118             :     return LiftoffRegister(combined_code);
     119             :   }
     120             : 
     121             :   constexpr bool is_pair() const {
     122             :     return kNeedI64RegPair && (code_ & (1 << (2 * kBitsPerGpRegCode))) != 0;
     123             :   }
     124         334 :   constexpr bool is_gp() const { return code_ < kAfterMaxLiftoffGpRegCode; }
     125             :   constexpr bool is_fp() const {
     126             :     return code_ >= kAfterMaxLiftoffGpRegCode &&
     127             :            code_ < kAfterMaxLiftoffFpRegCode;
     128             :   }
     129             : 
     130             :   LiftoffRegister low() const { return LiftoffRegister(low_gp()); }
     131             : 
     132             :   LiftoffRegister high() const { return LiftoffRegister(high_gp()); }
     133             : 
     134             :   Register low_gp() const {
     135             :     DCHECK(is_pair());
     136             :     static constexpr storage_t kCodeMask = (1 << kBitsPerGpRegCode) - 1;
     137             :     return Register::from_code(code_ & kCodeMask);
     138             :   }
     139             : 
     140             :   Register high_gp() const {
     141             :     DCHECK(is_pair());
     142             :     static constexpr storage_t kCodeMask = (1 << kBitsPerGpRegCode) - 1;
     143             :     return Register::from_code((code_ >> kBitsPerGpRegCode) & kCodeMask);
     144             :   }
     145             : 
     146             :   Register gp() const {
     147             :     DCHECK(is_gp());
     148     2715063 :     return Register::from_code(code_);
     149             :   }
     150             : 
     151             :   DoubleRegister fp() const {
     152             :     DCHECK(is_fp());
     153      280408 :     return DoubleRegister::from_code(code_ - kAfterMaxLiftoffGpRegCode);
     154             :   }
     155             : 
     156             :   int liftoff_code() const {
     157             :     DCHECK(is_gp() || is_fp());
     158     5621506 :     return code_;
     159             :   }
     160             : 
     161             :   RegClass reg_class() const {
     162         334 :     return is_pair() ? kGpRegPair : is_gp() ? kGpReg : kFpReg;
     163             :   }
     164             : 
     165             :   bool operator==(const LiftoffRegister other) const {
     166             :     DCHECK_EQ(is_pair(), other.is_pair());
     167          39 :     return code_ == other.code_;
     168             :   }
     169             :   bool operator!=(const LiftoffRegister other) const {
     170             :     DCHECK_EQ(is_pair(), other.is_pair());
     171      455606 :     return code_ != other.code_;
     172             :   }
     173             :   bool overlaps(const LiftoffRegister other) const {
     174             :     if (is_pair()) return low().overlaps(other) || high().overlaps(other);
     175             :     if (other.is_pair()) return *this == other.low() || *this == other.high();
     176             :     return *this == other;
     177             :   }
     178             : 
     179             :  private:
     180             :   storage_t code_;
     181             : 
     182      536383 :   explicit constexpr LiftoffRegister(storage_t code) : code_(code) {}
     183             : };
     184             : ASSERT_TRIVIALLY_COPYABLE(LiftoffRegister);
     185             : 
     186           0 : inline std::ostream& operator<<(std::ostream& os, LiftoffRegister reg) {
     187             :   if (reg.is_pair()) {
     188             :     return os << "<" << reg.low_gp() << "+" << reg.high_gp() << ">";
     189           0 :   } else if (reg.is_gp()) {
     190           0 :     return os << reg.gp();
     191             :   } else {
     192           0 :     return os << reg.fp();
     193             :   }
     194             : }
     195             : 
     196             : class LiftoffRegList {
     197             :  public:
     198             :   class Iterator;
     199             : 
     200             :   static constexpr bool use_u16 = kAfterMaxLiftoffRegCode <= 16;
     201             :   static constexpr bool use_u32 = !use_u16 && kAfterMaxLiftoffRegCode <= 32;
     202             :   using storage_t = std::conditional<
     203             :       use_u16, uint16_t,
     204             :       std::conditional<use_u32, uint32_t, uint64_t>::type>::type;
     205             : 
     206             :   static constexpr storage_t kGpMask = storage_t{kLiftoffAssemblerGpCacheRegs};
     207             :   static constexpr storage_t kFpMask = storage_t{kLiftoffAssemblerFpCacheRegs}
     208             :                                        << kAfterMaxLiftoffGpRegCode;
     209             : 
     210     2486838 :   constexpr LiftoffRegList() = default;
     211             : 
     212             :   Register set(Register reg) { return set(LiftoffRegister(reg)).gp(); }
     213             :   DoubleRegister set(DoubleRegister reg) {
     214             :     return set(LiftoffRegister(reg)).fp();
     215             :   }
     216             : 
     217             :   LiftoffRegister set(LiftoffRegister reg) {
     218             :     if (reg.is_pair()) {
     219             :       regs_ |= storage_t{1} << reg.low().liftoff_code();
     220             :       regs_ |= storage_t{1} << reg.high().liftoff_code();
     221             :     } else {
     222     3032312 :       regs_ |= storage_t{1} << reg.liftoff_code();
     223             :     }
     224             :     return reg;
     225             :   }
     226             : 
     227             :   LiftoffRegister clear(LiftoffRegister reg) {
     228             :     if (reg.is_pair()) {
     229             :       regs_ &= ~(storage_t{1} << reg.low().liftoff_code());
     230             :       regs_ &= ~(storage_t{1} << reg.high().liftoff_code());
     231             :     } else {
     232     1430781 :       regs_ &= ~(storage_t{1} << reg.liftoff_code());
     233             :     }
     234             :     return reg;
     235             :   }
     236             : 
     237             :   bool has(LiftoffRegister reg) const {
     238             :     if (reg.is_pair()) {
     239             :       DCHECK_EQ(has(reg.low()), has(reg.high()));
     240             :       reg = reg.low();
     241             :     }
     242     4142638 :     return (regs_ & (storage_t{1} << reg.liftoff_code())) != 0;
     243             :   }
     244             :   bool has(Register reg) const { return has(LiftoffRegister(reg)); }
     245             :   bool has(DoubleRegister reg) const { return has(LiftoffRegister(reg)); }
     246             : 
     247      825830 :   constexpr bool is_empty() const { return regs_ == 0; }
     248             : 
     249             :   constexpr unsigned GetNumRegsSet() const {
     250             :     return base::bits::CountPopulation(regs_);
     251             :   }
     252             : 
     253             :   constexpr LiftoffRegList operator&(const LiftoffRegList other) const {
     254       61597 :     return LiftoffRegList(regs_ & other.regs_);
     255             :   }
     256             : 
     257             :   constexpr LiftoffRegList operator|(const LiftoffRegList other) const {
     258             :     return LiftoffRegList(regs_ | other.regs_);
     259             :   }
     260             : 
     261             :   constexpr bool operator==(const LiftoffRegList other) const {
     262             :     return regs_ == other.regs_;
     263             :   }
     264             :   constexpr bool operator!=(const LiftoffRegList other) const {
     265             :     return regs_ != other.regs_;
     266             :   }
     267             : 
     268             :   LiftoffRegister GetFirstRegSet() const {
     269             :     DCHECK(!is_empty());
     270             :     int first_code = base::bits::CountTrailingZeros(regs_);
     271             :     return LiftoffRegister::from_liftoff_code(first_code);
     272             :   }
     273             : 
     274             :   LiftoffRegister GetLastRegSet() const {
     275             :     DCHECK(!is_empty());
     276             :     int last_code =
     277       17474 :         8 * sizeof(regs_) - 1 - base::bits::CountLeadingZeros(regs_);
     278             :     return LiftoffRegister::from_liftoff_code(last_code);
     279             :   }
     280             : 
     281             :   LiftoffRegList MaskOut(const LiftoffRegList mask) const {
     282             :     // Masking out is guaranteed to return a correct reg list, hence no checks
     283             :     // needed.
     284     1619205 :     return FromBits(regs_ & ~mask.regs_);
     285             :   }
     286             : 
     287             :   RegList GetGpList() { return regs_ & kGpMask; }
     288             :   RegList GetFpList() { return (regs_ & kFpMask) >> kAfterMaxLiftoffGpRegCode; }
     289             : 
     290             :   inline Iterator begin() const;
     291             :   inline Iterator end() const;
     292             : 
     293             :   static LiftoffRegList FromBits(storage_t bits) {
     294             :     DCHECK_EQ(bits, bits & (kGpMask | kFpMask));
     295             :     return LiftoffRegList(bits);
     296             :   }
     297             : 
     298             :   template <storage_t bits>
     299             :   static constexpr LiftoffRegList FromBits() {
     300             :     static_assert(bits == (bits & (kGpMask | kFpMask)), "illegal reg list");
     301             :     return LiftoffRegList(bits);
     302             :   }
     303             : 
     304             :   template <typename... Regs>
     305             :   static LiftoffRegList ForRegs(Regs... regs) {
     306             :     LiftoffRegList list;
     307      806954 :     for (LiftoffRegister reg : {LiftoffRegister(regs)...}) list.set(reg);
     308             :     return list;
     309             :   }
     310             : 
     311             :  private:
     312             :   storage_t regs_ = 0;
     313             : 
     314             :   // Unchecked constructor. Only use for valid bits.
     315             :   explicit constexpr LiftoffRegList(storage_t bits) : regs_(bits) {}
     316             : };
     317             : ASSERT_TRIVIALLY_COPYABLE(LiftoffRegList);
     318             : 
     319             : static constexpr LiftoffRegList kGpCacheRegList =
     320             :     LiftoffRegList::FromBits<LiftoffRegList::kGpMask>();
     321             : static constexpr LiftoffRegList kFpCacheRegList =
     322             :     LiftoffRegList::FromBits<LiftoffRegList::kFpMask>();
     323             : 
     324             : class LiftoffRegList::Iterator {
     325             :  public:
     326             :   LiftoffRegister operator*() { return remaining_.GetFirstRegSet(); }
     327             :   Iterator& operator++() {
     328             :     remaining_.clear(remaining_.GetFirstRegSet());
     329             :     return *this;
     330             :   }
     331             :   bool operator==(Iterator other) { return remaining_ == other.remaining_; }
     332             :   bool operator!=(Iterator other) { return remaining_ != other.remaining_; }
     333             : 
     334             :  private:
     335             :   explicit Iterator(LiftoffRegList remaining) : remaining_(remaining) {}
     336             :   friend class LiftoffRegList;
     337             : 
     338             :   LiftoffRegList remaining_;
     339             : };
     340             : 
     341             : LiftoffRegList::Iterator LiftoffRegList::begin() const {
     342             :   return Iterator{*this};
     343             : }
     344             : LiftoffRegList::Iterator LiftoffRegList::end() const {
     345             :   return Iterator{LiftoffRegList{}};
     346             : }
     347             : 
     348             : static constexpr LiftoffRegList GetCacheRegList(RegClass rc) {
     349      171901 :   return rc == kFpReg ? kFpCacheRegList : kGpCacheRegList;
     350             : }
     351             : 
     352             : inline std::ostream& operator<<(std::ostream& os, LiftoffRegList reglist) {
     353             :   os << "{";
     354             :   for (bool first = true; !reglist.is_empty(); first = false) {
     355             :     LiftoffRegister reg = reglist.GetFirstRegSet();
     356             :     reglist.clear(reg);
     357             :     os << (first ? "" : ", ") << reg;
     358             :   }
     359             :   return os << "}";
     360             : }
     361             : 
     362             : }  // namespace wasm
     363             : }  // namespace internal
     364             : }  // namespace v8
     365             : 
     366             : #endif  // V8_WASM_BASELINE_LIFTOFF_REGISTER_H_

Generated by: LCOV version 1.10