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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "jit/shared/Lowering-x86-shared.h"
michael@0 8
michael@0 9 #include "mozilla/MathAlgorithms.h"
michael@0 10
michael@0 11 #include "jit/MIR.h"
michael@0 12
michael@0 13 #include "jit/shared/Lowering-shared-inl.h"
michael@0 14
michael@0 15 using namespace js;
michael@0 16 using namespace js::jit;
michael@0 17
michael@0 18 using mozilla::Abs;
michael@0 19 using mozilla::FloorLog2;
michael@0 20
michael@0 21 LTableSwitch *
michael@0 22 LIRGeneratorX86Shared::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
michael@0 23 MTableSwitch *tableswitch)
michael@0 24 {
michael@0 25 return new(alloc()) LTableSwitch(in, inputCopy, temp(), tableswitch);
michael@0 26 }
michael@0 27
michael@0 28 LTableSwitchV *
michael@0 29 LIRGeneratorX86Shared::newLTableSwitchV(MTableSwitch *tableswitch)
michael@0 30 {
michael@0 31 return new(alloc()) LTableSwitchV(temp(), tempDouble(), temp(), tableswitch);
michael@0 32 }
michael@0 33
michael@0 34 bool
michael@0 35 LIRGeneratorX86Shared::visitGuardShape(MGuardShape *ins)
michael@0 36 {
michael@0 37 JS_ASSERT(ins->obj()->type() == MIRType_Object);
michael@0 38
michael@0 39 LGuardShape *guard = new(alloc()) LGuardShape(useRegister(ins->obj()));
michael@0 40 if (!assignSnapshot(guard, ins->bailoutKind()))
michael@0 41 return false;
michael@0 42 if (!add(guard, ins))
michael@0 43 return false;
michael@0 44 return redefine(ins, ins->obj());
michael@0 45 }
michael@0 46
michael@0 47 bool
michael@0 48 LIRGeneratorX86Shared::visitGuardObjectType(MGuardObjectType *ins)
michael@0 49 {
michael@0 50 JS_ASSERT(ins->obj()->type() == MIRType_Object);
michael@0 51
michael@0 52 LGuardObjectType *guard = new(alloc()) LGuardObjectType(useRegister(ins->obj()));
michael@0 53 if (!assignSnapshot(guard))
michael@0 54 return false;
michael@0 55 if (!add(guard, ins))
michael@0 56 return false;
michael@0 57 return redefine(ins, ins->obj());
michael@0 58 }
michael@0 59
michael@0 60 bool
michael@0 61 LIRGeneratorX86Shared::visitPowHalf(MPowHalf *ins)
michael@0 62 {
michael@0 63 MDefinition *input = ins->input();
michael@0 64 JS_ASSERT(input->type() == MIRType_Double);
michael@0 65 LPowHalfD *lir = new(alloc()) LPowHalfD(useRegisterAtStart(input));
michael@0 66 return defineReuseInput(lir, ins, 0);
michael@0 67 }
michael@0 68
michael@0 69 bool
michael@0 70 LIRGeneratorX86Shared::lowerForShift(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
michael@0 71 MDefinition *lhs, MDefinition *rhs)
michael@0 72 {
michael@0 73 ins->setOperand(0, useRegisterAtStart(lhs));
michael@0 74
michael@0 75 // shift operator should be constant or in register ecx
michael@0 76 // x86 can't shift a non-ecx register
michael@0 77 if (rhs->isConstant())
michael@0 78 ins->setOperand(1, useOrConstant(rhs));
michael@0 79 else
michael@0 80 ins->setOperand(1, useFixed(rhs, ecx));
michael@0 81
michael@0 82 return defineReuseInput(ins, mir, 0);
michael@0 83 }
michael@0 84
michael@0 85 bool
michael@0 86 LIRGeneratorX86Shared::lowerForALU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir,
michael@0 87 MDefinition *input)
michael@0 88 {
michael@0 89 ins->setOperand(0, useRegisterAtStart(input));
michael@0 90 return defineReuseInput(ins, mir, 0);
michael@0 91 }
michael@0 92
michael@0 93 bool
michael@0 94 LIRGeneratorX86Shared::lowerForALU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
michael@0 95 MDefinition *lhs, MDefinition *rhs)
michael@0 96 {
michael@0 97 ins->setOperand(0, useRegisterAtStart(lhs));
michael@0 98 ins->setOperand(1, useOrConstant(rhs));
michael@0 99 return defineReuseInput(ins, mir, 0);
michael@0 100 }
michael@0 101
michael@0 102 bool
michael@0 103 LIRGeneratorX86Shared::lowerForFPU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir, MDefinition *lhs, MDefinition *rhs)
michael@0 104 {
michael@0 105 ins->setOperand(0, useRegisterAtStart(lhs));
michael@0 106 ins->setOperand(1, use(rhs));
michael@0 107 return defineReuseInput(ins, mir, 0);
michael@0 108 }
michael@0 109
michael@0 110 bool
michael@0 111 LIRGeneratorX86Shared::lowerForBitAndAndBranch(LBitAndAndBranch *baab, MInstruction *mir,
michael@0 112 MDefinition *lhs, MDefinition *rhs)
michael@0 113 {
michael@0 114 baab->setOperand(0, useRegisterAtStart(lhs));
michael@0 115 baab->setOperand(1, useRegisterOrConstantAtStart(rhs));
michael@0 116 return add(baab, mir);
michael@0 117 }
michael@0 118
michael@0 119 bool
michael@0 120 LIRGeneratorX86Shared::lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs)
michael@0 121 {
michael@0 122 // Note: lhs is used twice, so that we can restore the original value for the
michael@0 123 // negative zero check.
michael@0 124 LMulI *lir = new(alloc()) LMulI(useRegisterAtStart(lhs), useOrConstant(rhs), use(lhs));
michael@0 125 if (mul->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
michael@0 126 return false;
michael@0 127 return defineReuseInput(lir, mul, 0);
michael@0 128 }
michael@0 129
michael@0 130 bool
michael@0 131 LIRGeneratorX86Shared::lowerDivI(MDiv *div)
michael@0 132 {
michael@0 133 if (div->isUnsigned())
michael@0 134 return lowerUDiv(div);
michael@0 135
michael@0 136 // Division instructions are slow. Division by constant denominators can be
michael@0 137 // rewritten to use other instructions.
michael@0 138 if (div->rhs()->isConstant()) {
michael@0 139 int32_t rhs = div->rhs()->toConstant()->value().toInt32();
michael@0 140
michael@0 141 // Division by powers of two can be done by shifting, and division by
michael@0 142 // other numbers can be done by a reciprocal multiplication technique.
michael@0 143 int32_t shift = FloorLog2(Abs(rhs));
michael@0 144 if (rhs != 0 && uint32_t(1) << shift == Abs(rhs)) {
michael@0 145 LAllocation lhs = useRegisterAtStart(div->lhs());
michael@0 146 LDivPowTwoI *lir;
michael@0 147 if (!div->canBeNegativeDividend()) {
michael@0 148 // Numerator is unsigned, so does not need adjusting.
michael@0 149 lir = new(alloc()) LDivPowTwoI(lhs, lhs, shift, rhs < 0);
michael@0 150 } else {
michael@0 151 // Numerator is signed, and needs adjusting, and an extra
michael@0 152 // lhs copy register is needed.
michael@0 153 lir = new(alloc()) LDivPowTwoI(lhs, useRegister(div->lhs()), shift, rhs < 0);
michael@0 154 }
michael@0 155 if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
michael@0 156 return false;
michael@0 157 return defineReuseInput(lir, div, 0);
michael@0 158 }
michael@0 159 }
michael@0 160
michael@0 161 LDivI *lir = new(alloc()) LDivI(useRegister(div->lhs()), useRegister(div->rhs()),
michael@0 162 tempFixed(edx));
michael@0 163 if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
michael@0 164 return false;
michael@0 165 return defineFixed(lir, div, LAllocation(AnyRegister(eax)));
michael@0 166 }
michael@0 167
michael@0 168 bool
michael@0 169 LIRGeneratorX86Shared::lowerModI(MMod *mod)
michael@0 170 {
michael@0 171 if (mod->isUnsigned())
michael@0 172 return lowerUMod(mod);
michael@0 173
michael@0 174 if (mod->rhs()->isConstant()) {
michael@0 175 int32_t rhs = mod->rhs()->toConstant()->value().toInt32();
michael@0 176 int32_t shift = FloorLog2(Abs(rhs));
michael@0 177 if (rhs != 0 && uint32_t(1) << shift == Abs(rhs)) {
michael@0 178 LModPowTwoI *lir = new(alloc()) LModPowTwoI(useRegisterAtStart(mod->lhs()), shift);
michael@0 179 if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
michael@0 180 return false;
michael@0 181 return defineReuseInput(lir, mod, 0);
michael@0 182 }
michael@0 183 }
michael@0 184
michael@0 185 LModI *lir = new(alloc()) LModI(useRegister(mod->lhs()),
michael@0 186 useRegister(mod->rhs()),
michael@0 187 tempFixed(eax));
michael@0 188 if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
michael@0 189 return false;
michael@0 190 return defineFixed(lir, mod, LAllocation(AnyRegister(edx)));
michael@0 191 }
michael@0 192
michael@0 193 bool
michael@0 194 LIRGeneratorX86Shared::visitAsmJSNeg(MAsmJSNeg *ins)
michael@0 195 {
michael@0 196 if (ins->type() == MIRType_Int32)
michael@0 197 return defineReuseInput(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins, 0);
michael@0 198
michael@0 199 if (ins->type() == MIRType_Float32)
michael@0 200 return defineReuseInput(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins, 0);
michael@0 201
michael@0 202 JS_ASSERT(ins->type() == MIRType_Double);
michael@0 203 return defineReuseInput(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins, 0);
michael@0 204 }
michael@0 205
michael@0 206 bool
michael@0 207 LIRGeneratorX86Shared::lowerUDiv(MDiv *div)
michael@0 208 {
michael@0 209 LUDivOrMod *lir = new(alloc()) LUDivOrMod(useRegister(div->lhs()),
michael@0 210 useRegister(div->rhs()),
michael@0 211 tempFixed(edx));
michael@0 212 if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
michael@0 213 return false;
michael@0 214 return defineFixed(lir, div, LAllocation(AnyRegister(eax)));
michael@0 215 }
michael@0 216
michael@0 217 bool
michael@0 218 LIRGeneratorX86Shared::lowerUMod(MMod *mod)
michael@0 219 {
michael@0 220 LUDivOrMod *lir = new(alloc()) LUDivOrMod(useRegister(mod->lhs()),
michael@0 221 useRegister(mod->rhs()),
michael@0 222 tempFixed(eax));
michael@0 223 if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
michael@0 224 return false;
michael@0 225 return defineFixed(lir, mod, LAllocation(AnyRegister(edx)));
michael@0 226 }
michael@0 227
michael@0 228 bool
michael@0 229 LIRGeneratorX86Shared::lowerUrshD(MUrsh *mir)
michael@0 230 {
michael@0 231 MDefinition *lhs = mir->lhs();
michael@0 232 MDefinition *rhs = mir->rhs();
michael@0 233
michael@0 234 JS_ASSERT(lhs->type() == MIRType_Int32);
michael@0 235 JS_ASSERT(rhs->type() == MIRType_Int32);
michael@0 236 JS_ASSERT(mir->type() == MIRType_Double);
michael@0 237
michael@0 238 #ifdef JS_CODEGEN_X64
michael@0 239 JS_ASSERT(ecx == rcx);
michael@0 240 #endif
michael@0 241
michael@0 242 LUse lhsUse = useRegisterAtStart(lhs);
michael@0 243 LAllocation rhsAlloc = rhs->isConstant() ? useOrConstant(rhs) : useFixed(rhs, ecx);
michael@0 244
michael@0 245 LUrshD *lir = new(alloc()) LUrshD(lhsUse, rhsAlloc, tempCopy(lhs, 0));
michael@0 246 return define(lir, mir);
michael@0 247 }
michael@0 248
michael@0 249 bool
michael@0 250 LIRGeneratorX86Shared::lowerConstantDouble(double d, MInstruction *mir)
michael@0 251 {
michael@0 252 return define(new(alloc()) LDouble(d), mir);
michael@0 253 }
michael@0 254
michael@0 255 bool
michael@0 256 LIRGeneratorX86Shared::lowerConstantFloat32(float f, MInstruction *mir)
michael@0 257 {
michael@0 258 return define(new(alloc()) LFloat32(f), mir);
michael@0 259 }
michael@0 260
michael@0 261 bool
michael@0 262 LIRGeneratorX86Shared::visitConstant(MConstant *ins)
michael@0 263 {
michael@0 264 if (ins->type() == MIRType_Double)
michael@0 265 return lowerConstantDouble(ins->value().toDouble(), ins);
michael@0 266
michael@0 267 if (ins->type() == MIRType_Float32)
michael@0 268 return lowerConstantFloat32(ins->value().toDouble(), ins);
michael@0 269
michael@0 270 // Emit non-double constants at their uses.
michael@0 271 if (ins->canEmitAtUses())
michael@0 272 return emitAtUses(ins);
michael@0 273
michael@0 274 return LIRGeneratorShared::visitConstant(ins);
michael@0 275 }
michael@0 276
michael@0 277 bool
michael@0 278 LIRGeneratorX86Shared::lowerTruncateDToInt32(MTruncateToInt32 *ins)
michael@0 279 {
michael@0 280 MDefinition *opd = ins->input();
michael@0 281 JS_ASSERT(opd->type() == MIRType_Double);
michael@0 282
michael@0 283 LDefinition maybeTemp = Assembler::HasSSE3() ? LDefinition::BogusTemp() : tempDouble();
michael@0 284 return define(new(alloc()) LTruncateDToInt32(useRegister(opd), maybeTemp), ins);
michael@0 285 }
michael@0 286
michael@0 287 bool
michael@0 288 LIRGeneratorX86Shared::lowerTruncateFToInt32(MTruncateToInt32 *ins)
michael@0 289 {
michael@0 290 MDefinition *opd = ins->input();
michael@0 291 JS_ASSERT(opd->type() == MIRType_Float32);
michael@0 292
michael@0 293 LDefinition maybeTemp = Assembler::HasSSE3() ? LDefinition::BogusTemp() : tempFloat32();
michael@0 294 return define(new(alloc()) LTruncateFToInt32(useRegister(opd), maybeTemp), ins);
michael@0 295 }
michael@0 296
michael@0 297 bool
michael@0 298 LIRGeneratorX86Shared::visitForkJoinGetSlice(MForkJoinGetSlice *ins)
michael@0 299 {
michael@0 300 // We fix eax and edx for cmpxchg and div.
michael@0 301 LForkJoinGetSlice *lir = new(alloc())
michael@0 302 LForkJoinGetSlice(useFixed(ins->forkJoinContext(), ForkJoinGetSliceReg_cx),
michael@0 303 tempFixed(eax),
michael@0 304 tempFixed(edx),
michael@0 305 tempFixed(ForkJoinGetSliceReg_temp0),
michael@0 306 tempFixed(ForkJoinGetSliceReg_temp1));
michael@0 307 return defineFixed(lir, ins, LAllocation(AnyRegister(ForkJoinGetSliceReg_output)));
michael@0 308 }

mercurial