LCOV - code coverage report
Current view: top level - js/src/jit/x86-shared - Architecture-x86-shared.h (source / functions) Hit Total Coverage
Test: output.info Lines: 57 85 67.1 %
Date: 2017-07-14 16:53:18 Functions: 22 37 59.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef jit_x86_shared_Architecture_x86_h
       8             : #define jit_x86_shared_Architecture_x86_h
       9             : 
      10             : #if !defined(JS_CODEGEN_X86) && !defined(JS_CODEGEN_X64)
      11             : # error "Unsupported architecture!"
      12             : #endif
      13             : 
      14             : #include "mozilla/MathAlgorithms.h"
      15             : 
      16             : #include <string.h>
      17             : 
      18             : #include "jit/shared/Architecture-shared.h"
      19             : 
      20             : #include "jit/x86-shared/Constants-x86-shared.h"
      21             : 
      22             : namespace js {
      23             : namespace jit {
      24             : 
      25             : // Does this architecture support SIMD conversions between Uint32x4 and Float32x4?
      26             : static constexpr bool SupportsUint32x4FloatConversions = false;
      27             : 
      28             : // Does this architecture support comparisons of unsigned integer vectors?
      29             : static constexpr bool SupportsUint8x16Compares = false;
      30             : static constexpr bool SupportsUint16x8Compares = false;
      31             : static constexpr bool SupportsUint32x4Compares = false;
      32             : 
      33             : #if defined(JS_CODEGEN_X86)
      34             : // In bytes: slots needed for potential memory->memory move spills.
      35             : //   +8 for cycles
      36             : //   +4 for gpr spills
      37             : //   +8 for double spills
      38             : static const uint32_t ION_FRAME_SLACK_SIZE    = 20;
      39             : 
      40             : #elif defined(JS_CODEGEN_X64)
      41             : // In bytes: slots needed for potential memory->memory move spills.
      42             : //   +8 for cycles
      43             : //   +8 for gpr spills
      44             : //   +8 for double spills
      45             : static const uint32_t ION_FRAME_SLACK_SIZE     = 24;
      46             : #endif
      47             : 
      48             : #if defined(JS_CODEGEN_X86)
      49             : // These offsets are specific to nunboxing, and capture offsets into the
      50             : // components of a js::Value.
      51             : static const int32_t NUNBOX32_TYPE_OFFSET         = 4;
      52             : static const int32_t NUNBOX32_PAYLOAD_OFFSET      = 0;
      53             : 
      54             : // Size of each bailout table entry. On x86 this is a 5-byte relative call.
      55             : static const uint32_t BAILOUT_TABLE_ENTRY_SIZE    = 5;
      56             : #endif
      57             : 
      58             : #if defined(JS_CODEGEN_X64) && defined(_WIN64)
      59             : static const uint32_t ShadowStackSpace = 32;
      60             : #else
      61             : static const uint32_t ShadowStackSpace = 0;
      62             : #endif
      63             : 
      64             : static const uint32_t JumpImmediateRange = INT32_MAX;
      65             : 
      66             : class Registers {
      67             :   public:
      68             :     typedef uint8_t Code;
      69             :     typedef X86Encoding::RegisterID Encoding;
      70             : 
      71             :     // Content spilled during bailouts.
      72             :     union RegisterContent {
      73             :         uintptr_t r;
      74             :     };
      75             : 
      76             : #if defined(JS_CODEGEN_X86)
      77             :     typedef uint8_t SetType;
      78             : 
      79             :     static const char* GetName(Code code) {
      80             :         return X86Encoding::GPRegName(Encoding(code));
      81             :     }
      82             : 
      83             :     static const uint32_t Total = 8;
      84             :     static const uint32_t TotalPhys = 8;
      85             :     static const uint32_t Allocatable = 7;
      86             : 
      87             : #elif defined(JS_CODEGEN_X64)
      88             :     typedef uint16_t SetType;
      89             : 
      90        5463 :     static const char* GetName(Code code) {
      91             :         static const char * const Names[] = { "rax", "rcx", "rdx", "rbx",
      92             :                                               "rsp", "rbp", "rsi", "rdi",
      93             :                                               "r8",  "r9",  "r10", "r11",
      94             :                                               "r12", "r13", "r14", "r15" };
      95        5463 :         return Names[code];
      96             :     }
      97             : 
      98             :     static const uint32_t Total = 16;
      99             :     static const uint32_t TotalPhys = 16;
     100             :     static const uint32_t Allocatable = 14;
     101             : #endif
     102             : 
     103       22827 :     static uint32_t SetSize(SetType x) {
     104             :         static_assert(sizeof(SetType) <= 4, "SetType must be, at most, 32 bits");
     105       22827 :         return mozilla::CountPopulation32(x);
     106             :     }
     107      200302 :     static uint32_t FirstBit(SetType x) {
     108      200302 :         return mozilla::CountTrailingZeroes32(x);
     109             :     }
     110      182879 :     static uint32_t LastBit(SetType x) {
     111      182879 :         return 31 - mozilla::CountLeadingZeroes32(x);
     112             :     }
     113             : 
     114             :     static Code FromName(const char* name) {
     115             :         for (size_t i = 0; i < Total; i++) {
     116             :             if (strcmp(GetName(Code(i)), name) == 0)
     117             :                 return Code(i);
     118             :         }
     119             :         return Invalid;
     120             :     }
     121             : 
     122             :     static const Encoding StackPointer = X86Encoding::rsp;
     123             :     static const Encoding Invalid = X86Encoding::invalid_reg;
     124             : 
     125             :     static const SetType AllMask = (1 << Total) - 1;
     126             : 
     127             : #if defined(JS_CODEGEN_X86)
     128             :     static const SetType ArgRegMask = 0;
     129             : 
     130             :     static const SetType VolatileMask =
     131             :         (1 << X86Encoding::rax) |
     132             :         (1 << X86Encoding::rcx) |
     133             :         (1 << X86Encoding::rdx);
     134             : 
     135             :     static const SetType WrapperMask =
     136             :         VolatileMask |
     137             :         (1 << X86Encoding::rbx);
     138             : 
     139             :     static const SetType SingleByteRegs =
     140             :         (1 << X86Encoding::rax) |
     141             :         (1 << X86Encoding::rcx) |
     142             :         (1 << X86Encoding::rdx) |
     143             :         (1 << X86Encoding::rbx);
     144             : 
     145             :     static const SetType NonAllocatableMask =
     146             :         (1 << X86Encoding::rsp);
     147             : 
     148             :     // Registers returned from a JS -> JS call.
     149             :     static const SetType JSCallMask =
     150             :         (1 << X86Encoding::rcx) |
     151             :         (1 << X86Encoding::rdx);
     152             : 
     153             :     // Registers returned from a JS -> C call.
     154             :     static const SetType CallMask =
     155             :         (1 << X86Encoding::rax);
     156             : 
     157             : #elif defined(JS_CODEGEN_X64)
     158             :     static const SetType ArgRegMask =
     159             : # if !defined(_WIN64)
     160             :         (1 << X86Encoding::rdi) |
     161             :         (1 << X86Encoding::rsi) |
     162             : # endif
     163             :         (1 << X86Encoding::rdx) |
     164             :         (1 << X86Encoding::rcx) |
     165             :         (1 << X86Encoding::r8) |
     166             :         (1 << X86Encoding::r9);
     167             : 
     168             :     static const SetType VolatileMask =
     169             :         (1 << X86Encoding::rax) |
     170             :         ArgRegMask |
     171             :         (1 << X86Encoding::r10) |
     172             :         (1 << X86Encoding::r11);
     173             : 
     174             :     static const SetType WrapperMask = VolatileMask;
     175             : 
     176             :     static const SetType SingleByteRegs = AllMask & ~(1 << X86Encoding::rsp);
     177             : 
     178             :     static const SetType NonAllocatableMask =
     179             :         (1 << X86Encoding::rsp) |
     180             :         (1 << X86Encoding::r11);      // This is ScratchReg.
     181             : 
     182             :     // Registers returned from a JS -> JS call.
     183             :     static const SetType JSCallMask =
     184             :         (1 << X86Encoding::rcx);
     185             : 
     186             :     // Registers returned from a JS -> C call.
     187             :     static const SetType CallMask =
     188             :         (1 << X86Encoding::rax);
     189             : 
     190             : #endif
     191             : 
     192             :     static const SetType NonVolatileMask =
     193             :         AllMask & ~VolatileMask & ~(1 << X86Encoding::rsp);
     194             : 
     195             :     static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
     196             : 
     197             :     // Registers that can be allocated without being saved, generally.
     198             :     static const SetType TempMask = VolatileMask & ~NonAllocatableMask;
     199             : };
     200             : 
     201             : typedef Registers::SetType PackedRegisterMask;
     202             : 
     203             : class FloatRegisters {
     204             :   public:
     205             :     typedef X86Encoding::XMMRegisterID Encoding;
     206             : 
     207             :     enum ContentType {
     208             :         Single,     // 32-bit float.
     209             :         Double,     // 64-bit double.
     210             :         Simd128,    // 128-bit SIMD type (int32x4, bool16x8, etc).
     211             :         NumTypes
     212             :     };
     213             : 
     214             :     // Content spilled during bailouts.
     215             :     union RegisterContent {
     216             :         float s;
     217             :         double d;
     218             :         int32_t i4[4];
     219             :         float s4[4];
     220             :     };
     221             : 
     222             :     static const char* GetName(Encoding code) {
     223             :         return X86Encoding::XMMRegName(code);
     224             :     }
     225             : 
     226             :     static Encoding FromName(const char* name) {
     227             :         for (size_t i = 0; i < Total; i++) {
     228             :             if (strcmp(GetName(Encoding(i)), name) == 0)
     229             :                 return Encoding(i);
     230             :         }
     231             :         return Invalid;
     232             :     }
     233             : 
     234             :     static const Encoding Invalid = X86Encoding::invalid_xmm;
     235             : 
     236             : #if defined(JS_CODEGEN_X86)
     237             :     static const uint32_t Total = 8 * NumTypes;
     238             :     static const uint32_t TotalPhys = 8;
     239             :     static const uint32_t Allocatable = 7;
     240             :     typedef uint32_t SetType;
     241             : 
     242             : #elif defined(JS_CODEGEN_X64)
     243             :     static const uint32_t Total = 16 * NumTypes;
     244             :     static const uint32_t TotalPhys = 16;
     245             :     static const uint32_t Allocatable = 15;
     246             :     typedef uint64_t SetType;
     247             : 
     248             : #endif
     249             : 
     250             :     static_assert(sizeof(SetType) * 8 >= Total,
     251             :                   "SetType should be large enough to enumerate all registers.");
     252             : 
     253             :     // Magic values which are used to duplicate a mask of physical register for
     254             :     // a specific type of register. A multiplication is used to copy and shift
     255             :     // the bits of the physical register mask.
     256             :     static const SetType SpreadSingle = SetType(1) << (uint32_t(Single) * TotalPhys);
     257             :     static const SetType SpreadDouble = SetType(1) << (uint32_t(Double) * TotalPhys);
     258             :     static const SetType SpreadSimd128 = SetType(1) << (uint32_t(Simd128) * TotalPhys);
     259             :     static const SetType SpreadScalar = SpreadSingle | SpreadDouble;
     260             :     static const SetType SpreadVector = SpreadSimd128;
     261             :     static const SetType Spread = SpreadScalar | SpreadVector;
     262             : 
     263             :     static const SetType AllPhysMask = ((1 << TotalPhys) - 1);
     264             :     static const SetType AllMask = AllPhysMask * Spread;
     265             :     static const SetType AllDoubleMask = AllPhysMask * SpreadDouble;
     266             :     static const SetType AllSingleMask = AllPhysMask * SpreadSingle;
     267             :     static const SetType AllVector128Mask = AllPhysMask * SpreadSimd128;
     268             : 
     269             : #if defined(JS_CODEGEN_X86)
     270             :     static const SetType NonAllocatableMask =
     271             :         Spread * (1 << X86Encoding::xmm7);     // This is ScratchDoubleReg.
     272             : 
     273             : #elif defined(JS_CODEGEN_X64)
     274             :     static const SetType NonAllocatableMask =
     275             :         Spread * (1 << X86Encoding::xmm15);    // This is ScratchDoubleReg.
     276             : #endif
     277             : 
     278             : #if defined(JS_CODEGEN_X64) && defined(_WIN64)
     279             :     static const SetType VolatileMask =
     280             :         ( (1 << X86Encoding::xmm0) |
     281             :           (1 << X86Encoding::xmm1) |
     282             :           (1 << X86Encoding::xmm2) |
     283             :           (1 << X86Encoding::xmm3) |
     284             :           (1 << X86Encoding::xmm4) |
     285             :           (1 << X86Encoding::xmm5)
     286             :         ) * SpreadScalar
     287             :         | AllPhysMask * SpreadVector;
     288             : 
     289             : #else
     290             :     static const SetType VolatileMask =
     291             :         AllMask;
     292             : #endif
     293             : 
     294             :     static const SetType NonVolatileMask = AllMask & ~VolatileMask;
     295             :     static const SetType WrapperMask = VolatileMask;
     296             :     static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
     297             : };
     298             : 
     299             : template <typename T>
     300             : class TypedRegisterSet;
     301             : 
     302             : struct FloatRegister {
     303             :     typedef FloatRegisters Codes;
     304             :     typedef size_t Code;
     305             :     typedef Codes::Encoding Encoding;
     306             :     typedef Codes::SetType SetType;
     307       22725 :     static uint32_t SetSize(SetType x) {
     308             :         // Count the number of non-aliased registers, for the moment.
     309             :         //
     310             :         // Copy the set bits of each typed register to the low part of the of
     311             :         // the Set, and count the number of registers. This is made to avoid
     312             :         // registers which are allocated twice with different types (such as in
     313             :         // AllMask).
     314       22725 :         x |= x >> (2 * Codes::TotalPhys);
     315       22725 :         x |= x >> Codes::TotalPhys;
     316       22725 :         x &= Codes::AllPhysMask;
     317             :         static_assert(Codes::AllPhysMask <= 0xffff, "We can safely use CountPopulation32");
     318       22725 :         return mozilla::CountPopulation32(x);
     319             :     }
     320             : 
     321             : #if defined(JS_CODEGEN_X86)
     322             :     static uint32_t FirstBit(SetType x) {
     323             :         static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
     324             :         return mozilla::CountTrailingZeroes32(x);
     325             :     }
     326             :     static uint32_t LastBit(SetType x) {
     327             :         return 31 - mozilla::CountLeadingZeroes32(x);
     328             :     }
     329             : 
     330             : #elif defined(JS_CODEGEN_X64)
     331        7155 :     static uint32_t FirstBit(SetType x) {
     332             :         static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
     333        7155 :         return mozilla::CountTrailingZeroes64(x);
     334             :     }
     335      662344 :     static uint32_t LastBit(SetType x) {
     336      662344 :         return 63 - mozilla::CountLeadingZeroes64(x);
     337             :     }
     338             : #endif
     339             : 
     340             :   private:
     341             :     // Note: These fields are using one extra bit to make the invalid enumerated
     342             :     // values fit, and thus prevent a warning.
     343             :     Codes::Encoding reg_ : 5;
     344             :     Codes::ContentType type_ : 3;
     345             :     bool isInvalid_ : 1;
     346             : 
     347             :     // Constants used for exporting/importing the float register code.
     348             : #if defined(JS_CODEGEN_X86)
     349             :     static const size_t RegSize = 3;
     350             : #elif defined(JS_CODEGEN_X64)
     351             :     static const size_t RegSize = 4;
     352             : #endif
     353             :     static const size_t RegMask = (1 << RegSize) - 1;
     354             : 
     355             :   public:
     356           0 :     constexpr FloatRegister()
     357           0 :         : reg_(Codes::Encoding(0)), type_(Codes::Single), isInvalid_(true)
     358           0 :     { }
     359      672306 :     constexpr FloatRegister(uint32_t r, Codes::ContentType k)
     360      672306 :         : reg_(Codes::Encoding(r)), type_(k), isInvalid_(false)
     361      672306 :     { }
     362         123 :     constexpr FloatRegister(Codes::Encoding r, Codes::ContentType k)
     363         123 :         : reg_(r), type_(k), isInvalid_(false)
     364         123 :     { }
     365             : 
     366      672306 :     static FloatRegister FromCode(uint32_t i) {
     367      672306 :         MOZ_ASSERT(i < Codes::Total);
     368      672306 :         return FloatRegister(i & RegMask, Codes::ContentType(i >> RegSize));
     369             :     }
     370             : 
     371      662314 :     bool isSingle() const { MOZ_ASSERT(!isInvalid()); return type_ == Codes::Single; }
     372      662961 :     bool isDouble() const { MOZ_ASSERT(!isInvalid()); return type_ == Codes::Double; }
     373      662302 :     bool isSimd128() const { MOZ_ASSERT(!isInvalid()); return type_ == Codes::Simd128; }
     374     3488759 :     bool isInvalid() const { return isInvalid_; }
     375             : 
     376           0 :     FloatRegister asSingle() const { MOZ_ASSERT(!isInvalid()); return FloatRegister(reg_, Codes::Single); }
     377           0 :     FloatRegister asDouble() const { MOZ_ASSERT(!isInvalid()); return FloatRegister(reg_, Codes::Double); }
     378           0 :     FloatRegister asSimd128() const { MOZ_ASSERT(!isInvalid()); return FloatRegister(reg_, Codes::Simd128); }
     379             : 
     380      331227 :     uint32_t size() const {
     381      331227 :         MOZ_ASSERT(!isInvalid());
     382      331227 :         if (isSingle())
     383           0 :             return sizeof(float);
     384      331225 :         if (isDouble())
     385          12 :             return sizeof(double);
     386      331214 :         MOZ_ASSERT(isSimd128());
     387      331205 :         return 4 * sizeof(int32_t);
     388             :     }
     389             : 
     390      839420 :     Code code() const {
     391      839420 :         MOZ_ASSERT(!isInvalid());
     392      839419 :         MOZ_ASSERT(uint32_t(reg_) < Codes::TotalPhys);
     393             :         // :TODO: ARM is doing the same thing, but we should avoid this, except
     394             :         // that the RegisterSets depends on this.
     395      839419 :         return Code(reg_ | (type_ << RegSize));
     396             :     }
     397      331662 :     Encoding encoding() const {
     398      331662 :         MOZ_ASSERT(!isInvalid());
     399      331662 :         MOZ_ASSERT(uint32_t(reg_) < Codes::TotalPhys);
     400      331662 :         return reg_;
     401             :     }
     402             :     // defined in Assembler-x86-shared.cpp
     403             :     const char* name() const;
     404           0 :     bool volatile_() const {
     405           0 :         return !!((SetType(1) << code()) & FloatRegisters::VolatileMask);
     406             :     }
     407           0 :     bool operator !=(FloatRegister other) const {
     408           0 :         return other.reg_ != reg_ || other.type_ != type_;
     409             :     }
     410           0 :     bool operator ==(FloatRegister other) const {
     411           0 :         return other.reg_ == reg_ && other.type_ == type_;
     412             :     }
     413           0 :     bool aliases(FloatRegister other) const {
     414           0 :         return other.reg_ == reg_;
     415             :     }
     416             :     // Check if two floating point registers have the same type.
     417             :     bool equiv(FloatRegister other) const {
     418             :         return other.type_ == type_;
     419             :     }
     420             : 
     421         164 :     uint32_t numAliased() const {
     422         164 :         return Codes::NumTypes;
     423             :     }
     424           0 :     uint32_t numAlignedAliased() const {
     425           0 :         return numAliased();
     426             :     }
     427             : 
     428             :     // N.B. FloatRegister is an explicit outparam here because msvc-2010
     429             :     // miscompiled it on win64 when the value was simply returned
     430         123 :     void aliased(uint32_t aliasIdx, FloatRegister* ret) const {
     431         123 :         MOZ_ASSERT(aliasIdx < Codes::NumTypes);
     432         123 :         *ret = FloatRegister(reg_, Codes::ContentType((aliasIdx + type_) % Codes::NumTypes));
     433         123 :     }
     434           0 :     void alignedAliased(uint32_t aliasIdx, FloatRegister* ret) const {
     435           0 :         aliased(aliasIdx, ret);
     436           0 :     }
     437             : 
     438         112 :     SetType alignedOrDominatedAliasedSet() const {
     439         112 :         return Codes::Spread << reg_;
     440             :     }
     441             : 
     442             :     static constexpr RegTypeName DefaultType = RegTypeName::Float64;
     443             : 
     444             :     template <RegTypeName = DefaultType>
     445             :     static SetType LiveAsIndexableSet(SetType s) {
     446             :         return SetType(0);
     447             :     }
     448             : 
     449             :     template <RegTypeName Name = DefaultType>
     450           0 :     static SetType AllocatableAsIndexableSet(SetType s) {
     451             :         static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable");
     452           0 :         return LiveAsIndexableSet<Name>(s);
     453             :     }
     454             : 
     455             :     static TypedRegisterSet<FloatRegister> ReduceSetForPush(const TypedRegisterSet<FloatRegister>& s);
     456             :     static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
     457             :     uint32_t getRegisterDumpOffsetInBytes();
     458             : };
     459             : 
     460             : template <> inline FloatRegister::SetType
     461           0 : FloatRegister::LiveAsIndexableSet<RegTypeName::Float32>(SetType set)
     462             : {
     463           0 :     return set & FloatRegisters::AllSingleMask;
     464             : }
     465             : 
     466             : template <> inline FloatRegister::SetType
     467           0 : FloatRegister::LiveAsIndexableSet<RegTypeName::Float64>(SetType set)
     468             : {
     469           0 :     return set & FloatRegisters::AllDoubleMask;
     470             : }
     471             : 
     472             : template <> inline FloatRegister::SetType
     473             : FloatRegister::LiveAsIndexableSet<RegTypeName::Vector128>(SetType set)
     474             : {
     475             :     return set & FloatRegisters::AllVector128Mask;
     476             : }
     477             : 
     478             : template <> inline FloatRegister::SetType
     479      669498 : FloatRegister::LiveAsIndexableSet<RegTypeName::Any>(SetType set)
     480             : {
     481      669498 :     return set;
     482             : }
     483             : 
     484             : // Arm/D32 has double registers that can NOT be treated as float32
     485             : // and this requires some dances in lowering.
     486             : inline bool
     487          12 : hasUnaliasedDouble()
     488             : {
     489          12 :     return false;
     490             : }
     491             : 
     492             : // On ARM, Dn aliases both S2n and S2n+1, so if you need to convert a float32
     493             : // to a double as a temporary, you need a temporary double register.
     494             : inline bool
     495           0 : hasMultiAlias()
     496             : {
     497           0 :     return false;
     498             : }
     499             : 
     500             : } // namespace jit
     501             : } // namespace js
     502             : 
     503             : #endif /* jit_x86_shared_Architecture_x86_h */

Generated by: LCOV version 1.13