js/src/jit/shared/Lowering-x86-shared.cpp

changeset 0
6474c204b198
     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 +}

mercurial