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