1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/shared/MacroAssembler-x86-shared.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,198 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "jit/shared/MacroAssembler-x86-shared.h" 1.11 + 1.12 +#include "jit/IonFrames.h" 1.13 +#include "jit/IonMacroAssembler.h" 1.14 + 1.15 +using namespace js; 1.16 +using namespace js::jit; 1.17 + 1.18 +void 1.19 +MacroAssembler::PushRegsInMask(RegisterSet set) 1.20 +{ 1.21 + int32_t diffF = set.fpus().size() * sizeof(double); 1.22 + int32_t diffG = set.gprs().size() * sizeof(intptr_t); 1.23 + 1.24 + // On x86, always use push to push the integer registers, as it's fast 1.25 + // on modern hardware and it's a small instruction. 1.26 + for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) { 1.27 + diffG -= sizeof(intptr_t); 1.28 + Push(*iter); 1.29 + } 1.30 + JS_ASSERT(diffG == 0); 1.31 + 1.32 + reserveStack(diffF); 1.33 + for (FloatRegisterBackwardIterator iter(set.fpus()); iter.more(); iter++) { 1.34 + diffF -= sizeof(double); 1.35 + storeDouble(*iter, Address(StackPointer, diffF)); 1.36 + } 1.37 + JS_ASSERT(diffF == 0); 1.38 +} 1.39 + 1.40 +void 1.41 +MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore) 1.42 +{ 1.43 + int32_t diffG = set.gprs().size() * sizeof(intptr_t); 1.44 + int32_t diffF = set.fpus().size() * sizeof(double); 1.45 + const int32_t reservedG = diffG; 1.46 + const int32_t reservedF = diffF; 1.47 + 1.48 + for (FloatRegisterBackwardIterator iter(set.fpus()); iter.more(); iter++) { 1.49 + diffF -= sizeof(double); 1.50 + if (!ignore.has(*iter)) 1.51 + loadDouble(Address(StackPointer, diffF), *iter); 1.52 + } 1.53 + freeStack(reservedF); 1.54 + JS_ASSERT(diffF == 0); 1.55 + 1.56 + // On x86, use pop to pop the integer registers, if we're not going to 1.57 + // ignore any slots, as it's fast on modern hardware and it's a small 1.58 + // instruction. 1.59 + if (ignore.empty(false)) { 1.60 + for (GeneralRegisterForwardIterator iter(set.gprs()); iter.more(); iter++) { 1.61 + diffG -= sizeof(intptr_t); 1.62 + Pop(*iter); 1.63 + } 1.64 + } else { 1.65 + for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) { 1.66 + diffG -= sizeof(intptr_t); 1.67 + if (!ignore.has(*iter)) 1.68 + loadPtr(Address(StackPointer, diffG), *iter); 1.69 + } 1.70 + freeStack(reservedG); 1.71 + } 1.72 + JS_ASSERT(diffG == 0); 1.73 +} 1.74 + 1.75 +// Note: this function clobbers the input register. 1.76 +void 1.77 +MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output) 1.78 +{ 1.79 + JS_ASSERT(input != ScratchFloatReg); 1.80 + Label positive, done; 1.81 + 1.82 + // <= 0 or NaN --> 0 1.83 + zeroDouble(ScratchFloatReg); 1.84 + branchDouble(DoubleGreaterThan, input, ScratchFloatReg, &positive); 1.85 + { 1.86 + move32(Imm32(0), output); 1.87 + jump(&done); 1.88 + } 1.89 + 1.90 + bind(&positive); 1.91 + 1.92 + // Add 0.5 and truncate. 1.93 + loadConstantDouble(0.5, ScratchFloatReg); 1.94 + addDouble(ScratchFloatReg, input); 1.95 + 1.96 + Label outOfRange; 1.97 + 1.98 + // Truncate to int32 and ensure the result <= 255. This relies on the 1.99 + // processor setting output to a value > 255 for doubles outside the int32 1.100 + // range (for instance 0x80000000). 1.101 + cvttsd2si(input, output); 1.102 + branch32(Assembler::Above, output, Imm32(255), &outOfRange); 1.103 + { 1.104 + // Check if we had a tie. 1.105 + convertInt32ToDouble(output, ScratchFloatReg); 1.106 + branchDouble(DoubleNotEqual, input, ScratchFloatReg, &done); 1.107 + 1.108 + // It was a tie. Mask out the ones bit to get an even value. 1.109 + // See also js_TypedArray_uint8_clamp_double. 1.110 + and32(Imm32(~1), output); 1.111 + jump(&done); 1.112 + } 1.113 + 1.114 + // > 255 --> 255 1.115 + bind(&outOfRange); 1.116 + { 1.117 + move32(Imm32(255), output); 1.118 + } 1.119 + 1.120 + bind(&done); 1.121 +} 1.122 + 1.123 +// Builds an exit frame on the stack, with a return address to an internal 1.124 +// non-function. Returns offset to be passed to markSafepointAt(). 1.125 +bool 1.126 +MacroAssemblerX86Shared::buildFakeExitFrame(const Register &scratch, uint32_t *offset) 1.127 +{ 1.128 + mozilla::DebugOnly<uint32_t> initialDepth = framePushed(); 1.129 + 1.130 + CodeLabel cl; 1.131 + mov(cl.dest(), scratch); 1.132 + 1.133 + uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS); 1.134 + Push(Imm32(descriptor)); 1.135 + Push(scratch); 1.136 + 1.137 + bind(cl.src()); 1.138 + *offset = currentOffset(); 1.139 + 1.140 + JS_ASSERT(framePushed() == initialDepth + IonExitFrameLayout::Size()); 1.141 + return addCodeLabel(cl); 1.142 +} 1.143 + 1.144 +void 1.145 +MacroAssemblerX86Shared::callWithExitFrame(JitCode *target) 1.146 +{ 1.147 + uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS); 1.148 + Push(Imm32(descriptor)); 1.149 + call(target); 1.150 +} 1.151 + 1.152 +bool 1.153 +MacroAssemblerX86Shared::buildOOLFakeExitFrame(void *fakeReturnAddr) 1.154 +{ 1.155 + uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS); 1.156 + Push(Imm32(descriptor)); 1.157 + Push(ImmPtr(fakeReturnAddr)); 1.158 + return true; 1.159 +} 1.160 + 1.161 +void 1.162 +MacroAssemblerX86Shared::branchNegativeZero(const FloatRegister ®, 1.163 + const Register &scratch, 1.164 + Label *label) 1.165 +{ 1.166 + // Determines whether the low double contained in the XMM register reg 1.167 + // is equal to -0.0. 1.168 + 1.169 +#if defined(JS_CODEGEN_X86) 1.170 + Label nonZero; 1.171 + 1.172 + // Compare to zero. Lets through {0, -0}. 1.173 + xorpd(ScratchFloatReg, ScratchFloatReg); 1.174 + 1.175 + // If reg is non-zero, jump to nonZero. 1.176 + branchDouble(DoubleNotEqual, reg, ScratchFloatReg, &nonZero); 1.177 + 1.178 + // Input register is either zero or negative zero. Retrieve sign of input. 1.179 + movmskpd(reg, scratch); 1.180 + 1.181 + // If reg is 1 or 3, input is negative zero. 1.182 + // If reg is 0 or 2, input is a normal zero. 1.183 + branchTest32(NonZero, scratch, Imm32(1), label); 1.184 + 1.185 + bind(&nonZero); 1.186 +#elif defined(JS_CODEGEN_X64) 1.187 + movq(reg, scratch); 1.188 + cmpq(scratch, Imm32(1)); 1.189 + j(Overflow, label); 1.190 +#endif 1.191 +} 1.192 + 1.193 +void 1.194 +MacroAssemblerX86Shared::branchNegativeZeroFloat32(const FloatRegister ®, 1.195 + const Register &scratch, 1.196 + Label *label) 1.197 +{ 1.198 + movd(reg, scratch); 1.199 + cmpl(scratch, Imm32(1)); 1.200 + j(Overflow, label); 1.201 +}