LCOV - code coverage report
Current view: top level - js/src/jit/x86-shared - MacroAssembler-x86-shared.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 124 447 27.7 %
Date: 2017-07-14 16:53:18 Functions: 21 72 29.2 %
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             : #include "jit/x86-shared/MacroAssembler-x86-shared.h"
       8             : 
       9             : #include "jit/JitFrames.h"
      10             : #include "jit/MacroAssembler.h"
      11             : 
      12             : #include "jit/MacroAssembler-inl.h"
      13             : 
      14             : using namespace js;
      15             : using namespace js::jit;
      16             : 
      17             : // Note: this function clobbers the input register.
      18             : void
      19           0 : MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output)
      20             : {
      21           0 :     ScratchDoubleScope scratch(*this);
      22           0 :     MOZ_ASSERT(input != scratch);
      23           0 :     Label positive, done;
      24             : 
      25             :     // <= 0 or NaN --> 0
      26           0 :     zeroDouble(scratch);
      27           0 :     branchDouble(DoubleGreaterThan, input, scratch, &positive);
      28             :     {
      29           0 :         move32(Imm32(0), output);
      30           0 :         jump(&done);
      31             :     }
      32             : 
      33           0 :     bind(&positive);
      34             : 
      35             :     // Add 0.5 and truncate.
      36           0 :     loadConstantDouble(0.5, scratch);
      37           0 :     addDouble(scratch, input);
      38             : 
      39           0 :     Label outOfRange;
      40             : 
      41             :     // Truncate to int32 and ensure the result <= 255. This relies on the
      42             :     // processor setting output to a value > 255 for doubles outside the int32
      43             :     // range (for instance 0x80000000).
      44           0 :     vcvttsd2si(input, output);
      45           0 :     branch32(Assembler::Above, output, Imm32(255), &outOfRange);
      46             :     {
      47             :         // Check if we had a tie.
      48           0 :         convertInt32ToDouble(output, scratch);
      49           0 :         branchDouble(DoubleNotEqual, input, scratch, &done);
      50             : 
      51             :         // It was a tie. Mask out the ones bit to get an even value.
      52             :         // See also js_TypedArray_uint8_clamp_double.
      53           0 :         and32(Imm32(~1), output);
      54           0 :         jump(&done);
      55             :     }
      56             : 
      57             :     // > 255 --> 255
      58           0 :     bind(&outOfRange);
      59             :     {
      60           0 :         move32(Imm32(255), output);
      61             :     }
      62             : 
      63           0 :     bind(&done);
      64           0 : }
      65             : 
      66             : void
      67           0 : MacroAssembler::alignFrameForICArguments(AfterICSaveLive& aic)
      68             : {
      69             :     // Exists for MIPS compatibility.
      70           0 : }
      71             : 
      72             : void
      73           0 : MacroAssembler::restoreFrameAlignmentForICArguments(AfterICSaveLive& aic)
      74             : {
      75             :     // Exists for MIPS compatibility.
      76           0 : }
      77             : 
      78             : bool
      79           0 : MacroAssemblerX86Shared::buildOOLFakeExitFrame(void* fakeReturnAddr)
      80             : {
      81           0 :     uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS,
      82           0 :                                               ExitFrameLayout::Size());
      83           0 :     asMasm().Push(Imm32(descriptor));
      84           0 :     asMasm().Push(ImmPtr(fakeReturnAddr));
      85           0 :     return true;
      86             : }
      87             : 
      88             : void
      89           0 : MacroAssemblerX86Shared::branchNegativeZero(FloatRegister reg,
      90             :                                             Register scratch,
      91             :                                             Label* label,
      92             :                                             bool maybeNonZero)
      93             : {
      94             :     // Determines whether the low double contained in the XMM register reg
      95             :     // is equal to -0.0.
      96             : 
      97             : #if defined(JS_CODEGEN_X86)
      98             :     Label nonZero;
      99             : 
     100             :     // if not already compared to zero
     101             :     if (maybeNonZero) {
     102             :         ScratchDoubleScope scratchDouble(asMasm());
     103             : 
     104             :         // Compare to zero. Lets through {0, -0}.
     105             :         zeroDouble(scratchDouble);
     106             : 
     107             :         // If reg is non-zero, jump to nonZero.
     108             :         asMasm().branchDouble(DoubleNotEqual, reg, scratchDouble, &nonZero);
     109             :     }
     110             :     // Input register is either zero or negative zero. Retrieve sign of input.
     111             :     vmovmskpd(reg, scratch);
     112             : 
     113             :     // If reg is 1 or 3, input is negative zero.
     114             :     // If reg is 0 or 2, input is a normal zero.
     115             :     asMasm().branchTest32(NonZero, scratch, Imm32(1), label);
     116             : 
     117             :     bind(&nonZero);
     118             : #elif defined(JS_CODEGEN_X64)
     119           0 :     vmovq(reg, scratch);
     120           0 :     cmpq(Imm32(1), scratch);
     121           0 :     j(Overflow, label);
     122             : #endif
     123           0 : }
     124             : 
     125             : void
     126           0 : MacroAssemblerX86Shared::branchNegativeZeroFloat32(FloatRegister reg,
     127             :                                                    Register scratch,
     128             :                                                    Label* label)
     129             : {
     130           0 :     vmovd(reg, scratch);
     131           0 :     cmp32(scratch, Imm32(1));
     132           0 :     j(Overflow, label);
     133           0 : }
     134             : 
     135             : MacroAssembler&
     136          27 : MacroAssemblerX86Shared::asMasm()
     137             : {
     138          27 :     return *static_cast<MacroAssembler*>(this);
     139             : }
     140             : 
     141             : const MacroAssembler&
     142           0 : MacroAssemblerX86Shared::asMasm() const
     143             : {
     144           0 :     return *static_cast<const MacroAssembler*>(this);
     145             : }
     146             : 
     147             : template<typename T>
     148             : void
     149           0 : MacroAssemblerX86Shared::compareExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem,
     150             :                                                         Register oldval, Register newval,
     151             :                                                         Register temp, AnyRegister output)
     152             : {
     153           0 :     switch (arrayType) {
     154             :       case Scalar::Int8:
     155           0 :         compareExchange8SignExtend(mem, oldval, newval, output.gpr());
     156           0 :         break;
     157             :       case Scalar::Uint8:
     158           0 :         compareExchange8ZeroExtend(mem, oldval, newval, output.gpr());
     159           0 :         break;
     160             :       case Scalar::Int16:
     161           0 :         compareExchange16SignExtend(mem, oldval, newval, output.gpr());
     162           0 :         break;
     163             :       case Scalar::Uint16:
     164           0 :         compareExchange16ZeroExtend(mem, oldval, newval, output.gpr());
     165           0 :         break;
     166             :       case Scalar::Int32:
     167           0 :         compareExchange32(mem, oldval, newval, output.gpr());
     168           0 :         break;
     169             :       case Scalar::Uint32:
     170             :         // At the moment, the code in MCallOptimize.cpp requires the output
     171             :         // type to be double for uint32 arrays.  See bug 1077305.
     172           0 :         MOZ_ASSERT(output.isFloat());
     173           0 :         compareExchange32(mem, oldval, newval, temp);
     174           0 :         asMasm().convertUInt32ToDouble(temp, output.fpu());
     175           0 :         break;
     176             :       default:
     177           0 :         MOZ_CRASH("Invalid typed array type");
     178             :     }
     179           0 : }
     180             : 
     181             : template void
     182             : MacroAssemblerX86Shared::compareExchangeToTypedIntArray(Scalar::Type arrayType, const Address& mem,
     183             :                                                         Register oldval, Register newval, Register temp,
     184             :                                                         AnyRegister output);
     185             : template void
     186             : MacroAssemblerX86Shared::compareExchangeToTypedIntArray(Scalar::Type arrayType, const BaseIndex& mem,
     187             :                                                         Register oldval, Register newval, Register temp,
     188             :                                                         AnyRegister output);
     189             : 
     190             : template<typename T>
     191             : void
     192           0 : MacroAssemblerX86Shared::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem,
     193             :                                                        Register value, Register temp, AnyRegister output)
     194             : {
     195           0 :     switch (arrayType) {
     196             :       case Scalar::Int8:
     197           0 :         atomicExchange8SignExtend(mem, value, output.gpr());
     198           0 :         break;
     199             :       case Scalar::Uint8:
     200           0 :         atomicExchange8ZeroExtend(mem, value, output.gpr());
     201           0 :         break;
     202             :       case Scalar::Int16:
     203           0 :         atomicExchange16SignExtend(mem, value, output.gpr());
     204           0 :         break;
     205             :       case Scalar::Uint16:
     206           0 :         atomicExchange16ZeroExtend(mem, value, output.gpr());
     207           0 :         break;
     208             :       case Scalar::Int32:
     209           0 :         atomicExchange32(mem, value, output.gpr());
     210           0 :         break;
     211             :       case Scalar::Uint32:
     212             :         // At the moment, the code in MCallOptimize.cpp requires the output
     213             :         // type to be double for uint32 arrays.  See bug 1077305.
     214           0 :         MOZ_ASSERT(output.isFloat());
     215           0 :         atomicExchange32(mem, value, temp);
     216           0 :         asMasm().convertUInt32ToDouble(temp, output.fpu());
     217           0 :         break;
     218             :       default:
     219           0 :         MOZ_CRASH("Invalid typed array type");
     220             :     }
     221           0 : }
     222             : 
     223             : template void
     224             : MacroAssemblerX86Shared::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const Address& mem,
     225             :                                                        Register value, Register temp, AnyRegister output);
     226             : template void
     227             : MacroAssemblerX86Shared::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const BaseIndex& mem,
     228             :                                                        Register value, Register temp, AnyRegister output);
     229             : 
     230             : template<class T, class Map>
     231             : T*
     232           0 : MacroAssemblerX86Shared::getConstant(const typename T::Pod& value, Map& map,
     233             :                                      Vector<T, 0, SystemAllocPolicy>& vec)
     234             : {
     235             :     typedef typename Map::AddPtr AddPtr;
     236           0 :     if (!map.initialized()) {
     237           0 :         enoughMemory_ &= map.init();
     238           0 :         if (!enoughMemory_)
     239           0 :             return nullptr;
     240             :     }
     241             :     size_t index;
     242           0 :     if (AddPtr p = map.lookupForAdd(value)) {
     243           0 :         index = p->value();
     244             :     } else {
     245           0 :         index = vec.length();
     246           0 :         enoughMemory_ &= vec.append(T(value));
     247           0 :         if (!enoughMemory_)
     248           0 :             return nullptr;
     249           0 :         enoughMemory_ &= map.add(p, value, index);
     250           0 :         if (!enoughMemory_)
     251           0 :             return nullptr;
     252             :     }
     253           0 :     return &vec[index];
     254             : }
     255             : 
     256             : MacroAssemblerX86Shared::Float*
     257           0 : MacroAssemblerX86Shared::getFloat(float f)
     258             : {
     259           0 :     return getConstant<Float, FloatMap>(f, floatMap_, floats_);
     260             : }
     261             : 
     262             : MacroAssemblerX86Shared::Double*
     263           0 : MacroAssemblerX86Shared::getDouble(double d)
     264             : {
     265           0 :     return getConstant<Double, DoubleMap>(d, doubleMap_, doubles_);
     266             : }
     267             : 
     268             : MacroAssemblerX86Shared::SimdData*
     269           0 : MacroAssemblerX86Shared::getSimdData(const SimdConstant& v)
     270             : {
     271           0 :     return getConstant<SimdData, SimdMap>(v, simdMap_, simds_);
     272             : }
     273             : 
     274             : template<class T, class Map>
     275             : static bool
     276           0 : MergeConstants(size_t delta, const Vector<T, 0, SystemAllocPolicy>& other,
     277             :                Map& map, Vector<T, 0, SystemAllocPolicy>& vec)
     278             : {
     279             :     typedef typename Map::AddPtr AddPtr;
     280           0 :     if (!map.initialized() && !map.init())
     281           0 :         return false;
     282             : 
     283           0 :     for (const T& c : other) {
     284             :         size_t index;
     285           0 :         if (AddPtr p = map.lookupForAdd(c.value)) {
     286           0 :             index = p->value();
     287             :         } else {
     288           0 :             index = vec.length();
     289           0 :             if (!vec.append(T(c.value)) || !map.add(p, c.value, index))
     290           0 :                 return false;
     291             :         }
     292           0 :         MacroAssemblerX86Shared::UsesVector& uses = vec[index].uses;
     293           0 :         for (CodeOffset use : c.uses) {
     294           0 :             use.offsetBy(delta);
     295           0 :             if (!uses.append(use))
     296           0 :                 return false;
     297             :         }
     298             :     }
     299             : 
     300           0 :     return true;
     301             : }
     302             : 
     303             : bool
     304           0 : MacroAssemblerX86Shared::asmMergeWith(const MacroAssemblerX86Shared& other)
     305             : {
     306           0 :     size_t sizeBefore = masm.size();
     307           0 :     if (!Assembler::asmMergeWith(other))
     308           0 :         return false;
     309           0 :     if (!MergeConstants<Double, DoubleMap>(sizeBefore, other.doubles_, doubleMap_, doubles_))
     310           0 :         return false;
     311           0 :     if (!MergeConstants<Float, FloatMap>(sizeBefore, other.floats_, floatMap_, floats_))
     312           0 :         return false;
     313           0 :     if (!MergeConstants<SimdData, SimdMap>(sizeBefore, other.simds_, simdMap_, simds_))
     314           0 :         return false;
     315           0 :     return true;
     316             : }
     317             : 
     318             : void
     319           0 : MacroAssemblerX86Shared::minMaxDouble(FloatRegister first, FloatRegister second, bool canBeNaN,
     320             :                                       bool isMax)
     321             : {
     322           0 :     Label done, nan, minMaxInst;
     323             : 
     324             :     // Do a vucomisd to catch equality and NaNs, which both require special
     325             :     // handling. If the operands are ordered and inequal, we branch straight to
     326             :     // the min/max instruction. If we wanted, we could also branch for less-than
     327             :     // or greater-than here instead of using min/max, however these conditions
     328             :     // will sometimes be hard on the branch predictor.
     329           0 :     vucomisd(second, first);
     330           0 :     j(Assembler::NotEqual, &minMaxInst);
     331           0 :     if (canBeNaN)
     332           0 :         j(Assembler::Parity, &nan);
     333             : 
     334             :     // Ordered and equal. The operands are bit-identical unless they are zero
     335             :     // and negative zero. These instructions merge the sign bits in that
     336             :     // case, and are no-ops otherwise.
     337           0 :     if (isMax)
     338           0 :         vandpd(second, first, first);
     339             :     else
     340           0 :         vorpd(second, first, first);
     341           0 :     jump(&done);
     342             : 
     343             :     // x86's min/max are not symmetric; if either operand is a NaN, they return
     344             :     // the read-only operand. We need to return a NaN if either operand is a
     345             :     // NaN, so we explicitly check for a NaN in the read-write operand.
     346           0 :     if (canBeNaN) {
     347           0 :         bind(&nan);
     348           0 :         vucomisd(first, first);
     349           0 :         j(Assembler::Parity, &done);
     350             :     }
     351             : 
     352             :     // When the values are inequal, or second is NaN, x86's min and max will
     353             :     // return the value we need.
     354           0 :     bind(&minMaxInst);
     355           0 :     if (isMax)
     356           0 :         vmaxsd(second, first, first);
     357             :     else
     358           0 :         vminsd(second, first, first);
     359             : 
     360           0 :     bind(&done);
     361           0 : }
     362             : 
     363             : void
     364           0 : MacroAssemblerX86Shared::minMaxFloat32(FloatRegister first, FloatRegister second, bool canBeNaN,
     365             :                                        bool isMax)
     366             : {
     367           0 :     Label done, nan, minMaxInst;
     368             : 
     369             :     // Do a vucomiss to catch equality and NaNs, which both require special
     370             :     // handling. If the operands are ordered and inequal, we branch straight to
     371             :     // the min/max instruction. If we wanted, we could also branch for less-than
     372             :     // or greater-than here instead of using min/max, however these conditions
     373             :     // will sometimes be hard on the branch predictor.
     374           0 :     vucomiss(second, first);
     375           0 :     j(Assembler::NotEqual, &minMaxInst);
     376           0 :     if (canBeNaN)
     377           0 :         j(Assembler::Parity, &nan);
     378             : 
     379             :     // Ordered and equal. The operands are bit-identical unless they are zero
     380             :     // and negative zero. These instructions merge the sign bits in that
     381             :     // case, and are no-ops otherwise.
     382           0 :     if (isMax)
     383           0 :         vandps(second, first, first);
     384             :     else
     385           0 :         vorps(second, first, first);
     386           0 :     jump(&done);
     387             : 
     388             :     // x86's min/max are not symmetric; if either operand is a NaN, they return
     389             :     // the read-only operand. We need to return a NaN if either operand is a
     390             :     // NaN, so we explicitly check for a NaN in the read-write operand.
     391           0 :     if (canBeNaN) {
     392           0 :         bind(&nan);
     393           0 :         vucomiss(first, first);
     394           0 :         j(Assembler::Parity, &done);
     395             :     }
     396             : 
     397             :     // When the values are inequal, or second is NaN, x86's min and max will
     398             :     // return the value we need.
     399           0 :     bind(&minMaxInst);
     400           0 :     if (isMax)
     401           0 :         vmaxss(second, first, first);
     402             :     else
     403           0 :         vminss(second, first, first);
     404             : 
     405           0 :     bind(&done);
     406           0 : }
     407             : 
     408             : //{{{ check_macroassembler_style
     409             : // ===============================================================
     410             : // MacroAssembler high-level usage.
     411             : 
     412             : void
     413           0 : MacroAssembler::flush()
     414             : {
     415           0 : }
     416             : 
     417             : void
     418         288 : MacroAssembler::comment(const char* msg)
     419             : {
     420         288 :     masm.comment(msg);
     421         288 : }
     422             : 
     423             : // ===============================================================
     424             : // Stack manipulation functions.
     425             : 
     426             : void
     427       11367 : MacroAssembler::PushRegsInMask(LiveRegisterSet set)
     428             : {
     429       11367 :     FloatRegisterSet fpuSet(set.fpus().reduceSetForPush());
     430       11367 :     unsigned numFpu = fpuSet.size();
     431       11367 :     int32_t diffF = fpuSet.getPushSizeInBytes();
     432       11367 :     int32_t diffG = set.gprs().size() * sizeof(intptr_t);
     433             : 
     434             :     // On x86, always use push to push the integer registers, as it's fast
     435             :     // on modern hardware and it's a small instruction.
     436      101571 :     for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); ++iter) {
     437       90199 :         diffG -= sizeof(intptr_t);
     438       90199 :         Push(*iter);
     439             :     }
     440       11367 :     MOZ_ASSERT(diffG == 0);
     441             : 
     442       11367 :     reserveStack(diffF);
     443      177039 :     for (FloatRegisterBackwardIterator iter(fpuSet); iter.more(); ++iter) {
     444      165677 :         FloatRegister reg = *iter;
     445      165677 :         diffF -= reg.size();
     446      165676 :         numFpu -= 1;
     447      165676 :         Address spillAddress(StackPointer, diffF);
     448      165676 :         if (reg.isDouble())
     449           6 :             storeDouble(reg, spillAddress);
     450      165663 :         else if (reg.isSingle())
     451           0 :             storeFloat32(reg, spillAddress);
     452      165663 :         else if (reg.isSimd128())
     453      165665 :             storeUnalignedSimd128Float(reg, spillAddress);
     454             :         else
     455           0 :             MOZ_CRASH("Unknown register type.");
     456             :     }
     457       11367 :     MOZ_ASSERT(numFpu == 0);
     458             :     // x64 padding to keep the stack aligned on uintptr_t. Keep in sync with
     459             :     // GetPushBytesInSize.
     460       11367 :     diffF -= diffF % sizeof(uintptr_t);
     461       11367 :     MOZ_ASSERT(diffF == 0);
     462       11367 : }
     463             : 
     464             : void
     465           0 : MacroAssembler::storeRegsInMask(LiveRegisterSet set, Address dest, Register)
     466             : {
     467           0 :     FloatRegisterSet fpuSet(set.fpus().reduceSetForPush());
     468           0 :     unsigned numFpu = fpuSet.size();
     469           0 :     int32_t diffF = fpuSet.getPushSizeInBytes();
     470           0 :     int32_t diffG = set.gprs().size() * sizeof(intptr_t);
     471             : 
     472           0 :     MOZ_ASSERT(dest.offset >= diffG + diffF);
     473             : 
     474           0 :     for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); ++iter) {
     475           0 :         diffG -= sizeof(intptr_t);
     476           0 :         dest.offset -= sizeof(intptr_t);
     477           0 :         storePtr(*iter, dest);
     478             :     }
     479           0 :     MOZ_ASSERT(diffG == 0);
     480             : 
     481           0 :     for (FloatRegisterBackwardIterator iter(fpuSet); iter.more(); ++iter) {
     482           0 :         FloatRegister reg = *iter;
     483           0 :         diffF -= reg.size();
     484           0 :         numFpu -= 1;
     485           0 :         dest.offset -= reg.size();
     486           0 :         if (reg.isDouble())
     487           0 :             storeDouble(reg, dest);
     488           0 :         else if (reg.isSingle())
     489           0 :             storeFloat32(reg, dest);
     490           0 :         else if (reg.isSimd128())
     491           0 :             storeUnalignedSimd128Float(reg, dest);
     492             :         else
     493           0 :             MOZ_CRASH("Unknown register type.");
     494             :     }
     495           0 :     MOZ_ASSERT(numFpu == 0);
     496             :     // x64 padding to keep the stack aligned on uintptr_t. Keep in sync with
     497             :     // GetPushBytesInSize.
     498           0 :     diffF -= diffF % sizeof(uintptr_t);
     499           0 :     MOZ_ASSERT(diffF == 0);
     500           0 : }
     501             : 
     502             : void
     503       11359 : MacroAssembler::PopRegsInMaskIgnore(LiveRegisterSet set, LiveRegisterSet ignore)
     504             : {
     505       11359 :     FloatRegisterSet fpuSet(set.fpus().reduceSetForPush());
     506       11359 :     unsigned numFpu = fpuSet.size();
     507       11359 :     int32_t diffG = set.gprs().size() * sizeof(intptr_t);
     508       11359 :     int32_t diffF = fpuSet.getPushSizeInBytes();
     509       11359 :     const int32_t reservedG = diffG;
     510       11359 :     const int32_t reservedF = diffF;
     511             : 
     512      176887 :     for (FloatRegisterBackwardIterator iter(fpuSet); iter.more(); ++iter) {
     513      165549 :         FloatRegister reg = *iter;
     514      165551 :         diffF -= reg.size();
     515      165542 :         numFpu -= 1;
     516      165542 :         if (ignore.has(reg))
     517           0 :             continue;
     518             : 
     519      165541 :         Address spillAddress(StackPointer, diffF);
     520      165542 :         if (reg.isDouble())
     521           6 :             loadDouble(spillAddress, reg);
     522      165535 :         else if (reg.isSingle())
     523           0 :             loadFloat32(spillAddress, reg);
     524      165534 :         else if (reg.isSimd128())
     525      165534 :             loadUnalignedSimd128Float(spillAddress, reg);
     526             :         else
     527           0 :             MOZ_CRASH("Unknown register type.");
     528             :     }
     529       11359 :     freeStack(reservedF);
     530       11358 :     MOZ_ASSERT(numFpu == 0);
     531             :     // x64 padding to keep the stack aligned on uintptr_t. Keep in sync with
     532             :     // GetPushBytesInSize.
     533       11358 :     diffF -= diffF % sizeof(uintptr_t);
     534       11358 :     MOZ_ASSERT(diffF == 0);
     535             : 
     536             :     // On x86, use pop to pop the integer registers, if we're not going to
     537             :     // ignore any slots, as it's fast on modern hardware and it's a small
     538             :     // instruction.
     539       11358 :     if (ignore.emptyGeneral()) {
     540      100501 :         for (GeneralRegisterForwardIterator iter(set.gprs()); iter.more(); ++iter) {
     541       89279 :             diffG -= sizeof(intptr_t);
     542       89279 :             Pop(*iter);
     543             :         }
     544             :     } else {
     545         933 :         for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); ++iter) {
     546         796 :             diffG -= sizeof(intptr_t);
     547         796 :             if (!ignore.has(*iter))
     548         735 :                 loadPtr(Address(StackPointer, diffG), *iter);
     549             :         }
     550         137 :         freeStack(reservedG);
     551             :     }
     552       11359 :     MOZ_ASSERT(diffG == 0);
     553       11359 : }
     554             : 
     555             : void
     556         385 : MacroAssembler::Push(const Operand op)
     557             : {
     558         385 :     push(op);
     559         385 :     adjustFrame(sizeof(intptr_t));
     560         385 : }
     561             : 
     562             : void
     563       99118 : MacroAssembler::Push(Register reg)
     564             : {
     565       99118 :     push(reg);
     566       99122 :     adjustFrame(sizeof(intptr_t));
     567       99122 : }
     568             : 
     569             : void
     570        2290 : MacroAssembler::Push(const Imm32 imm)
     571             : {
     572        2290 :     push(imm);
     573        2290 :     adjustFrame(sizeof(intptr_t));
     574        2290 : }
     575             : 
     576             : void
     577        1799 : MacroAssembler::Push(const ImmWord imm)
     578             : {
     579        1799 :     push(imm);
     580        1799 :     adjustFrame(sizeof(intptr_t));
     581        1799 : }
     582             : 
     583             : void
     584        1799 : MacroAssembler::Push(const ImmPtr imm)
     585             : {
     586        1799 :     Push(ImmWord(uintptr_t(imm.value)));
     587        1799 : }
     588             : 
     589             : void
     590         514 : MacroAssembler::Push(const ImmGCPtr ptr)
     591             : {
     592         514 :     push(ptr);
     593         514 :     adjustFrame(sizeof(intptr_t));
     594         514 : }
     595             : 
     596             : void
     597           0 : MacroAssembler::Push(FloatRegister t)
     598             : {
     599           0 :     push(t);
     600           0 :     adjustFrame(sizeof(double));
     601           0 : }
     602             : 
     603             : void
     604           0 : MacroAssembler::PushFlags()
     605             : {
     606           0 :     pushFlags();
     607           0 :     adjustFrame(sizeof(intptr_t));
     608           0 : }
     609             : 
     610             : void
     611         665 : MacroAssembler::Pop(const Operand op)
     612             : {
     613         665 :     pop(op);
     614         665 :     implicitPop(sizeof(intptr_t));
     615         665 : }
     616             : 
     617             : void
     618       93978 : MacroAssembler::Pop(Register reg)
     619             : {
     620       93978 :     pop(reg);
     621       93979 :     implicitPop(sizeof(intptr_t));
     622       93979 : }
     623             : 
     624             : void
     625           0 : MacroAssembler::Pop(FloatRegister reg)
     626             : {
     627           0 :     pop(reg);
     628           0 :     implicitPop(sizeof(double));
     629           0 : }
     630             : 
     631             : void
     632         274 : MacroAssembler::Pop(const ValueOperand& val)
     633             : {
     634         274 :     popValue(val);
     635         274 :     implicitPop(sizeof(Value));
     636         274 : }
     637             : 
     638             : void
     639           0 : MacroAssembler::PopFlags()
     640             : {
     641           0 :     popFlags();
     642           0 :     implicitPop(sizeof(intptr_t));
     643           0 : }
     644             : 
     645             : void
     646           0 : MacroAssembler::PopStackPtr()
     647             : {
     648           0 :     Pop(StackPointer);
     649           0 : }
     650             : 
     651             : // ===============================================================
     652             : // Simple call functions.
     653             : 
     654             : CodeOffset
     655          94 : MacroAssembler::call(Register reg)
     656             : {
     657          94 :     return Assembler::call(reg);
     658             : }
     659             : 
     660             : CodeOffset
     661         373 : MacroAssembler::call(Label* label)
     662             : {
     663         373 :     return Assembler::call(label);
     664             : }
     665             : 
     666             : void
     667       19474 : MacroAssembler::call(const Address& addr)
     668             : {
     669       19474 :     Assembler::call(Operand(addr.base, addr.offset));
     670       19474 : }
     671             : 
     672             : void
     673           0 : MacroAssembler::call(wasm::SymbolicAddress target)
     674             : {
     675           0 :     mov(target, eax);
     676           0 :     Assembler::call(eax);
     677           0 : }
     678             : 
     679             : void
     680           0 : MacroAssembler::call(ImmWord target)
     681             : {
     682           0 :     Assembler::call(target);
     683           0 : }
     684             : 
     685             : void
     686       12946 : MacroAssembler::call(ImmPtr target)
     687             : {
     688       12946 :     Assembler::call(target);
     689       12946 : }
     690             : 
     691             : void
     692        4069 : MacroAssembler::call(JitCode* target)
     693             : {
     694        4069 :     Assembler::call(target);
     695        4069 : }
     696             : 
     697             : CodeOffset
     698           0 : MacroAssembler::callWithPatch()
     699             : {
     700           0 :     return Assembler::callWithPatch();
     701             : }
     702             : void
     703           0 : MacroAssembler::patchCall(uint32_t callerOffset, uint32_t calleeOffset)
     704             : {
     705           0 :     Assembler::patchCall(callerOffset, calleeOffset);
     706           0 : }
     707             : 
     708             : void
     709          94 : MacroAssembler::callAndPushReturnAddress(Register reg)
     710             : {
     711          94 :     call(reg);
     712          94 : }
     713             : 
     714             : void
     715           4 : MacroAssembler::callAndPushReturnAddress(Label* label)
     716             : {
     717           4 :     call(label);
     718           4 : }
     719             : 
     720             : // ===============================================================
     721             : // Patchable near/far jumps.
     722             : 
     723             : CodeOffset
     724           0 : MacroAssembler::farJumpWithPatch()
     725             : {
     726           0 :     return Assembler::farJumpWithPatch();
     727             : }
     728             : 
     729             : void
     730           0 : MacroAssembler::patchFarJump(CodeOffset farJump, uint32_t targetOffset)
     731             : {
     732           0 :     Assembler::patchFarJump(farJump, targetOffset);
     733           0 : }
     734             : 
     735             : void
     736           0 : MacroAssembler::repatchFarJump(uint8_t* code, uint32_t farJumpOffset, uint32_t targetOffset)
     737             : {
     738           0 :     Assembler::repatchFarJump(code, farJumpOffset, targetOffset);
     739           0 : }
     740             : 
     741             : CodeOffset
     742           0 : MacroAssembler::nopPatchableToNearJump()
     743             : {
     744           0 :     return Assembler::twoByteNop();
     745             : }
     746             : 
     747             : void
     748           0 : MacroAssembler::patchNopToNearJump(uint8_t* jump, uint8_t* target)
     749             : {
     750           0 :     Assembler::patchTwoByteNopToJump(jump, target);
     751           0 : }
     752             : 
     753             : void
     754           0 : MacroAssembler::patchNearJumpToNop(uint8_t* jump)
     755             : {
     756           0 :     Assembler::patchJumpToTwoByteNop(jump);
     757           0 : }
     758             : 
     759             : CodeOffset
     760           0 : MacroAssembler::nopPatchableToCall(const wasm::CallSiteDesc& desc)
     761             : {
     762           0 :     CodeOffset offset(currentOffset());
     763           0 :     masm.nop_five();
     764           0 :     append(desc, CodeOffset(currentOffset()));
     765           0 :     MOZ_ASSERT_IF(!oom(), size() - offset.offset() == ToggledCallSize(nullptr));
     766           0 :     return offset;
     767             : }
     768             : 
     769             : void
     770           0 : MacroAssembler::patchNopToCall(uint8_t* callsite, uint8_t* target)
     771             : {
     772           0 :     Assembler::patchFiveByteNopToCall(callsite, target);
     773           0 : }
     774             : 
     775             : void
     776           0 : MacroAssembler::patchCallToNop(uint8_t* callsite)
     777             : {
     778           0 :     Assembler::patchCallToFiveByteNop(callsite);
     779           0 : }
     780             : 
     781             : // ===============================================================
     782             : // Jit Frames.
     783             : 
     784             : uint32_t
     785           9 : MacroAssembler::pushFakeReturnAddress(Register scratch)
     786             : {
     787           9 :     CodeLabel cl;
     788             : 
     789           9 :     mov(cl.patchAt(), scratch);
     790           9 :     Push(scratch);
     791           9 :     use(cl.target());
     792           9 :     uint32_t retAddr = currentOffset();
     793             : 
     794           9 :     addCodeLabel(cl);
     795           9 :     return retAddr;
     796             : }
     797             : 
     798             : // wasm specific methods, used in both the wasm baseline compiler and ion.
     799             : 
     800             : // RAII class that generates the jumps to traps when it's destructed, to
     801             : // prevent some code duplication in the outOfLineWasmTruncateXtoY methods.
     802             : struct MOZ_RAII AutoHandleWasmTruncateToIntErrors
     803             : {
     804             :     MacroAssembler& masm;
     805             :     Label inputIsNaN;
     806             :     Label fail;
     807             :     wasm::BytecodeOffset off;
     808             : 
     809           0 :     explicit AutoHandleWasmTruncateToIntErrors(MacroAssembler& masm, wasm::BytecodeOffset off)
     810           0 :       : masm(masm), off(off)
     811           0 :     { }
     812             : 
     813           0 :     ~AutoHandleWasmTruncateToIntErrors() {
     814             :         // Handle errors.
     815           0 :         masm.bind(&fail);
     816           0 :         masm.jump(wasm::TrapDesc(off, wasm::Trap::IntegerOverflow, masm.framePushed()));
     817             : 
     818           0 :         masm.bind(&inputIsNaN);
     819           0 :         masm.jump(wasm::TrapDesc(off, wasm::Trap::InvalidConversionToInteger, masm.framePushed()));
     820           0 :     }
     821             : };
     822             : 
     823             : void
     824           0 : MacroAssembler::wasmTruncateDoubleToInt32(FloatRegister input, Register output, Label* oolEntry)
     825             : {
     826           0 :     vcvttsd2si(input, output);
     827           0 :     cmp32(output, Imm32(1));
     828           0 :     j(Assembler::Overflow, oolEntry);
     829           0 : }
     830             : 
     831             : void
     832           0 : MacroAssembler::wasmTruncateFloat32ToInt32(FloatRegister input, Register output, Label* oolEntry)
     833             : {
     834           0 :     vcvttss2si(input, output);
     835           0 :     cmp32(output, Imm32(1));
     836           0 :     j(Assembler::Overflow, oolEntry);
     837           0 : }
     838             : 
     839             : void
     840           0 : MacroAssembler::outOfLineWasmTruncateDoubleToInt32(FloatRegister input, bool isUnsigned,
     841             :                                                    wasm::BytecodeOffset off, Label* rejoin)
     842             : {
     843           0 :     AutoHandleWasmTruncateToIntErrors traps(*this, off);
     844             : 
     845             :     // Eagerly take care of NaNs.
     846           0 :     branchDouble(Assembler::DoubleUnordered, input, input, &traps.inputIsNaN);
     847             : 
     848             :     // Handle special values (not needed for unsigned values).
     849           0 :     if (isUnsigned)
     850           0 :         return;
     851             : 
     852             :     // We've used vcvttsd2si. The only valid double values that can
     853             :     // truncate to INT32_MIN are in ]INT32_MIN - 1; INT32_MIN].
     854           0 :     loadConstantDouble(double(INT32_MIN) - 1.0, ScratchDoubleReg);
     855           0 :     branchDouble(Assembler::DoubleLessThanOrEqual, input, ScratchDoubleReg, &traps.fail);
     856             : 
     857           0 :     loadConstantDouble(double(INT32_MIN), ScratchDoubleReg);
     858           0 :     branchDouble(Assembler::DoubleGreaterThan, input, ScratchDoubleReg, &traps.fail);
     859           0 :     jump(rejoin);
     860             : }
     861             : 
     862             : void
     863           0 : MacroAssembler::outOfLineWasmTruncateFloat32ToInt32(FloatRegister input, bool isUnsigned,
     864             :                                                     wasm::BytecodeOffset off, Label* rejoin)
     865             : {
     866           0 :     AutoHandleWasmTruncateToIntErrors traps(*this, off);
     867             : 
     868             :     // Eagerly take care of NaNs.
     869           0 :     branchFloat(Assembler::DoubleUnordered, input, input, &traps.inputIsNaN);
     870             : 
     871             :     // Handle special values (not needed for unsigned values).
     872           0 :     if (isUnsigned)
     873           0 :         return;
     874             : 
     875             :     // We've used vcvttss2si. Check that the input wasn't
     876             :     // float(INT32_MIN), which is the only legimitate input that
     877             :     // would truncate to INT32_MIN.
     878           0 :     loadConstantFloat32(float(INT32_MIN), ScratchFloat32Reg);
     879           0 :     branchFloat(Assembler::DoubleNotEqual, input, ScratchFloat32Reg, &traps.fail);
     880           0 :     jump(rejoin);
     881             : }
     882             : 
     883             : void
     884           0 : MacroAssembler::outOfLineWasmTruncateDoubleToInt64(FloatRegister input, bool isUnsigned,
     885             :                                                    wasm::BytecodeOffset off, Label* rejoin)
     886             : {
     887           0 :     AutoHandleWasmTruncateToIntErrors traps(*this, off);
     888             : 
     889             :     // Eagerly take care of NaNs.
     890           0 :     branchDouble(Assembler::DoubleUnordered, input, input, &traps.inputIsNaN);
     891             : 
     892             :     // Handle special values.
     893           0 :     if (isUnsigned) {
     894           0 :         loadConstantDouble(-0.0, ScratchDoubleReg);
     895           0 :         branchDouble(Assembler::DoubleGreaterThan, input, ScratchDoubleReg, &traps.fail);
     896           0 :         loadConstantDouble(-1.0, ScratchDoubleReg);
     897           0 :         branchDouble(Assembler::DoubleLessThanOrEqual, input, ScratchDoubleReg, &traps.fail);
     898           0 :         jump(rejoin);
     899           0 :         return;
     900             :     }
     901             : 
     902             :     // We've used vcvtsd2sq. The only legit value whose i64
     903             :     // truncation is INT64_MIN is double(INT64_MIN): exponent is so
     904             :     // high that the highest resolution around is much more than 1.
     905           0 :     loadConstantDouble(double(int64_t(INT64_MIN)), ScratchDoubleReg);
     906           0 :     branchDouble(Assembler::DoubleNotEqual, input, ScratchDoubleReg, &traps.fail);
     907           0 :     jump(rejoin);
     908             : }
     909             : 
     910             : void
     911           0 : MacroAssembler::outOfLineWasmTruncateFloat32ToInt64(FloatRegister input, bool isUnsigned,
     912             :                                                     wasm::BytecodeOffset off, Label* rejoin)
     913             : {
     914           0 :     AutoHandleWasmTruncateToIntErrors traps(*this, off);
     915             : 
     916             :     // Eagerly take care of NaNs.
     917           0 :     branchFloat(Assembler::DoubleUnordered, input, input, &traps.inputIsNaN);
     918             : 
     919             :     // Handle special values.
     920           0 :     if (isUnsigned) {
     921           0 :         loadConstantFloat32(-0.0f, ScratchFloat32Reg);
     922           0 :         branchFloat(Assembler::DoubleGreaterThan, input, ScratchFloat32Reg, &traps.fail);
     923           0 :         loadConstantFloat32(-1.0f, ScratchFloat32Reg);
     924           0 :         branchFloat(Assembler::DoubleLessThanOrEqual, input, ScratchFloat32Reg, &traps.fail);
     925           0 :         jump(rejoin);
     926           0 :         return;
     927             :     }
     928             : 
     929             :     // We've used vcvtss2sq. See comment in outOfLineWasmTruncateDoubleToInt64.
     930           0 :     loadConstantFloat32(float(int64_t(INT64_MIN)), ScratchFloat32Reg);
     931           0 :     branchFloat(Assembler::DoubleNotEqual, input, ScratchFloat32Reg, &traps.fail);
     932           0 :     jump(rejoin);
     933             : }
     934             : 
     935             : //}}} check_macroassembler_style

Generated by: LCOV version 1.13