1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/shared/Lowering-x86-shared.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,308 @@ 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/Lowering-x86-shared.h" 1.11 + 1.12 +#include "mozilla/MathAlgorithms.h" 1.13 + 1.14 +#include "jit/MIR.h" 1.15 + 1.16 +#include "jit/shared/Lowering-shared-inl.h" 1.17 + 1.18 +using namespace js; 1.19 +using namespace js::jit; 1.20 + 1.21 +using mozilla::Abs; 1.22 +using mozilla::FloorLog2; 1.23 + 1.24 +LTableSwitch * 1.25 +LIRGeneratorX86Shared::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy, 1.26 + MTableSwitch *tableswitch) 1.27 +{ 1.28 + return new(alloc()) LTableSwitch(in, inputCopy, temp(), tableswitch); 1.29 +} 1.30 + 1.31 +LTableSwitchV * 1.32 +LIRGeneratorX86Shared::newLTableSwitchV(MTableSwitch *tableswitch) 1.33 +{ 1.34 + return new(alloc()) LTableSwitchV(temp(), tempDouble(), temp(), tableswitch); 1.35 +} 1.36 + 1.37 +bool 1.38 +LIRGeneratorX86Shared::visitGuardShape(MGuardShape *ins) 1.39 +{ 1.40 + JS_ASSERT(ins->obj()->type() == MIRType_Object); 1.41 + 1.42 + LGuardShape *guard = new(alloc()) LGuardShape(useRegister(ins->obj())); 1.43 + if (!assignSnapshot(guard, ins->bailoutKind())) 1.44 + return false; 1.45 + if (!add(guard, ins)) 1.46 + return false; 1.47 + return redefine(ins, ins->obj()); 1.48 +} 1.49 + 1.50 +bool 1.51 +LIRGeneratorX86Shared::visitGuardObjectType(MGuardObjectType *ins) 1.52 +{ 1.53 + JS_ASSERT(ins->obj()->type() == MIRType_Object); 1.54 + 1.55 + LGuardObjectType *guard = new(alloc()) LGuardObjectType(useRegister(ins->obj())); 1.56 + if (!assignSnapshot(guard)) 1.57 + return false; 1.58 + if (!add(guard, ins)) 1.59 + return false; 1.60 + return redefine(ins, ins->obj()); 1.61 +} 1.62 + 1.63 +bool 1.64 +LIRGeneratorX86Shared::visitPowHalf(MPowHalf *ins) 1.65 +{ 1.66 + MDefinition *input = ins->input(); 1.67 + JS_ASSERT(input->type() == MIRType_Double); 1.68 + LPowHalfD *lir = new(alloc()) LPowHalfD(useRegisterAtStart(input)); 1.69 + return defineReuseInput(lir, ins, 0); 1.70 +} 1.71 + 1.72 +bool 1.73 +LIRGeneratorX86Shared::lowerForShift(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir, 1.74 + MDefinition *lhs, MDefinition *rhs) 1.75 +{ 1.76 + ins->setOperand(0, useRegisterAtStart(lhs)); 1.77 + 1.78 + // shift operator should be constant or in register ecx 1.79 + // x86 can't shift a non-ecx register 1.80 + if (rhs->isConstant()) 1.81 + ins->setOperand(1, useOrConstant(rhs)); 1.82 + else 1.83 + ins->setOperand(1, useFixed(rhs, ecx)); 1.84 + 1.85 + return defineReuseInput(ins, mir, 0); 1.86 +} 1.87 + 1.88 +bool 1.89 +LIRGeneratorX86Shared::lowerForALU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir, 1.90 + MDefinition *input) 1.91 +{ 1.92 + ins->setOperand(0, useRegisterAtStart(input)); 1.93 + return defineReuseInput(ins, mir, 0); 1.94 +} 1.95 + 1.96 +bool 1.97 +LIRGeneratorX86Shared::lowerForALU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir, 1.98 + MDefinition *lhs, MDefinition *rhs) 1.99 +{ 1.100 + ins->setOperand(0, useRegisterAtStart(lhs)); 1.101 + ins->setOperand(1, useOrConstant(rhs)); 1.102 + return defineReuseInput(ins, mir, 0); 1.103 +} 1.104 + 1.105 +bool 1.106 +LIRGeneratorX86Shared::lowerForFPU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir, MDefinition *lhs, MDefinition *rhs) 1.107 +{ 1.108 + ins->setOperand(0, useRegisterAtStart(lhs)); 1.109 + ins->setOperand(1, use(rhs)); 1.110 + return defineReuseInput(ins, mir, 0); 1.111 +} 1.112 + 1.113 +bool 1.114 +LIRGeneratorX86Shared::lowerForBitAndAndBranch(LBitAndAndBranch *baab, MInstruction *mir, 1.115 + MDefinition *lhs, MDefinition *rhs) 1.116 +{ 1.117 + baab->setOperand(0, useRegisterAtStart(lhs)); 1.118 + baab->setOperand(1, useRegisterOrConstantAtStart(rhs)); 1.119 + return add(baab, mir); 1.120 +} 1.121 + 1.122 +bool 1.123 +LIRGeneratorX86Shared::lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs) 1.124 +{ 1.125 + // Note: lhs is used twice, so that we can restore the original value for the 1.126 + // negative zero check. 1.127 + LMulI *lir = new(alloc()) LMulI(useRegisterAtStart(lhs), useOrConstant(rhs), use(lhs)); 1.128 + if (mul->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) 1.129 + return false; 1.130 + return defineReuseInput(lir, mul, 0); 1.131 +} 1.132 + 1.133 +bool 1.134 +LIRGeneratorX86Shared::lowerDivI(MDiv *div) 1.135 +{ 1.136 + if (div->isUnsigned()) 1.137 + return lowerUDiv(div); 1.138 + 1.139 + // Division instructions are slow. Division by constant denominators can be 1.140 + // rewritten to use other instructions. 1.141 + if (div->rhs()->isConstant()) { 1.142 + int32_t rhs = div->rhs()->toConstant()->value().toInt32(); 1.143 + 1.144 + // Division by powers of two can be done by shifting, and division by 1.145 + // other numbers can be done by a reciprocal multiplication technique. 1.146 + int32_t shift = FloorLog2(Abs(rhs)); 1.147 + if (rhs != 0 && uint32_t(1) << shift == Abs(rhs)) { 1.148 + LAllocation lhs = useRegisterAtStart(div->lhs()); 1.149 + LDivPowTwoI *lir; 1.150 + if (!div->canBeNegativeDividend()) { 1.151 + // Numerator is unsigned, so does not need adjusting. 1.152 + lir = new(alloc()) LDivPowTwoI(lhs, lhs, shift, rhs < 0); 1.153 + } else { 1.154 + // Numerator is signed, and needs adjusting, and an extra 1.155 + // lhs copy register is needed. 1.156 + lir = new(alloc()) LDivPowTwoI(lhs, useRegister(div->lhs()), shift, rhs < 0); 1.157 + } 1.158 + if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) 1.159 + return false; 1.160 + return defineReuseInput(lir, div, 0); 1.161 + } 1.162 + } 1.163 + 1.164 + LDivI *lir = new(alloc()) LDivI(useRegister(div->lhs()), useRegister(div->rhs()), 1.165 + tempFixed(edx)); 1.166 + if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) 1.167 + return false; 1.168 + return defineFixed(lir, div, LAllocation(AnyRegister(eax))); 1.169 +} 1.170 + 1.171 +bool 1.172 +LIRGeneratorX86Shared::lowerModI(MMod *mod) 1.173 +{ 1.174 + if (mod->isUnsigned()) 1.175 + return lowerUMod(mod); 1.176 + 1.177 + if (mod->rhs()->isConstant()) { 1.178 + int32_t rhs = mod->rhs()->toConstant()->value().toInt32(); 1.179 + int32_t shift = FloorLog2(Abs(rhs)); 1.180 + if (rhs != 0 && uint32_t(1) << shift == Abs(rhs)) { 1.181 + LModPowTwoI *lir = new(alloc()) LModPowTwoI(useRegisterAtStart(mod->lhs()), shift); 1.182 + if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) 1.183 + return false; 1.184 + return defineReuseInput(lir, mod, 0); 1.185 + } 1.186 + } 1.187 + 1.188 + LModI *lir = new(alloc()) LModI(useRegister(mod->lhs()), 1.189 + useRegister(mod->rhs()), 1.190 + tempFixed(eax)); 1.191 + if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) 1.192 + return false; 1.193 + return defineFixed(lir, mod, LAllocation(AnyRegister(edx))); 1.194 +} 1.195 + 1.196 +bool 1.197 +LIRGeneratorX86Shared::visitAsmJSNeg(MAsmJSNeg *ins) 1.198 +{ 1.199 + if (ins->type() == MIRType_Int32) 1.200 + return defineReuseInput(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins, 0); 1.201 + 1.202 + if (ins->type() == MIRType_Float32) 1.203 + return defineReuseInput(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins, 0); 1.204 + 1.205 + JS_ASSERT(ins->type() == MIRType_Double); 1.206 + return defineReuseInput(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins, 0); 1.207 +} 1.208 + 1.209 +bool 1.210 +LIRGeneratorX86Shared::lowerUDiv(MDiv *div) 1.211 +{ 1.212 + LUDivOrMod *lir = new(alloc()) LUDivOrMod(useRegister(div->lhs()), 1.213 + useRegister(div->rhs()), 1.214 + tempFixed(edx)); 1.215 + if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) 1.216 + return false; 1.217 + return defineFixed(lir, div, LAllocation(AnyRegister(eax))); 1.218 +} 1.219 + 1.220 +bool 1.221 +LIRGeneratorX86Shared::lowerUMod(MMod *mod) 1.222 +{ 1.223 + LUDivOrMod *lir = new(alloc()) LUDivOrMod(useRegister(mod->lhs()), 1.224 + useRegister(mod->rhs()), 1.225 + tempFixed(eax)); 1.226 + if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) 1.227 + return false; 1.228 + return defineFixed(lir, mod, LAllocation(AnyRegister(edx))); 1.229 +} 1.230 + 1.231 +bool 1.232 +LIRGeneratorX86Shared::lowerUrshD(MUrsh *mir) 1.233 +{ 1.234 + MDefinition *lhs = mir->lhs(); 1.235 + MDefinition *rhs = mir->rhs(); 1.236 + 1.237 + JS_ASSERT(lhs->type() == MIRType_Int32); 1.238 + JS_ASSERT(rhs->type() == MIRType_Int32); 1.239 + JS_ASSERT(mir->type() == MIRType_Double); 1.240 + 1.241 +#ifdef JS_CODEGEN_X64 1.242 + JS_ASSERT(ecx == rcx); 1.243 +#endif 1.244 + 1.245 + LUse lhsUse = useRegisterAtStart(lhs); 1.246 + LAllocation rhsAlloc = rhs->isConstant() ? useOrConstant(rhs) : useFixed(rhs, ecx); 1.247 + 1.248 + LUrshD *lir = new(alloc()) LUrshD(lhsUse, rhsAlloc, tempCopy(lhs, 0)); 1.249 + return define(lir, mir); 1.250 +} 1.251 + 1.252 +bool 1.253 +LIRGeneratorX86Shared::lowerConstantDouble(double d, MInstruction *mir) 1.254 +{ 1.255 + return define(new(alloc()) LDouble(d), mir); 1.256 +} 1.257 + 1.258 +bool 1.259 +LIRGeneratorX86Shared::lowerConstantFloat32(float f, MInstruction *mir) 1.260 +{ 1.261 + return define(new(alloc()) LFloat32(f), mir); 1.262 +} 1.263 + 1.264 +bool 1.265 +LIRGeneratorX86Shared::visitConstant(MConstant *ins) 1.266 +{ 1.267 + if (ins->type() == MIRType_Double) 1.268 + return lowerConstantDouble(ins->value().toDouble(), ins); 1.269 + 1.270 + if (ins->type() == MIRType_Float32) 1.271 + return lowerConstantFloat32(ins->value().toDouble(), ins); 1.272 + 1.273 + // Emit non-double constants at their uses. 1.274 + if (ins->canEmitAtUses()) 1.275 + return emitAtUses(ins); 1.276 + 1.277 + return LIRGeneratorShared::visitConstant(ins); 1.278 +} 1.279 + 1.280 +bool 1.281 +LIRGeneratorX86Shared::lowerTruncateDToInt32(MTruncateToInt32 *ins) 1.282 +{ 1.283 + MDefinition *opd = ins->input(); 1.284 + JS_ASSERT(opd->type() == MIRType_Double); 1.285 + 1.286 + LDefinition maybeTemp = Assembler::HasSSE3() ? LDefinition::BogusTemp() : tempDouble(); 1.287 + return define(new(alloc()) LTruncateDToInt32(useRegister(opd), maybeTemp), ins); 1.288 +} 1.289 + 1.290 +bool 1.291 +LIRGeneratorX86Shared::lowerTruncateFToInt32(MTruncateToInt32 *ins) 1.292 +{ 1.293 + MDefinition *opd = ins->input(); 1.294 + JS_ASSERT(opd->type() == MIRType_Float32); 1.295 + 1.296 + LDefinition maybeTemp = Assembler::HasSSE3() ? LDefinition::BogusTemp() : tempFloat32(); 1.297 + return define(new(alloc()) LTruncateFToInt32(useRegister(opd), maybeTemp), ins); 1.298 +} 1.299 + 1.300 +bool 1.301 +LIRGeneratorX86Shared::visitForkJoinGetSlice(MForkJoinGetSlice *ins) 1.302 +{ 1.303 + // We fix eax and edx for cmpxchg and div. 1.304 + LForkJoinGetSlice *lir = new(alloc()) 1.305 + LForkJoinGetSlice(useFixed(ins->forkJoinContext(), ForkJoinGetSliceReg_cx), 1.306 + tempFixed(eax), 1.307 + tempFixed(edx), 1.308 + tempFixed(ForkJoinGetSliceReg_temp0), 1.309 + tempFixed(ForkJoinGetSliceReg_temp1)); 1.310 + return defineFixed(lir, ins, LAllocation(AnyRegister(ForkJoinGetSliceReg_output))); 1.311 +}