js/src/jit/x86/CodeGenerator-x86.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/x86/CodeGenerator-x86.h"
michael@0 8
michael@0 9 #include "mozilla/DebugOnly.h"
michael@0 10
michael@0 11 #include "jsnum.h"
michael@0 12
michael@0 13 #include "jit/IonCaches.h"
michael@0 14 #include "jit/MIR.h"
michael@0 15 #include "jit/MIRGraph.h"
michael@0 16 #include "vm/Shape.h"
michael@0 17
michael@0 18 #include "jsscriptinlines.h"
michael@0 19
michael@0 20 #include "jit/ExecutionMode-inl.h"
michael@0 21 #include "jit/shared/CodeGenerator-shared-inl.h"
michael@0 22
michael@0 23 using namespace js;
michael@0 24 using namespace js::jit;
michael@0 25
michael@0 26 using mozilla::DebugOnly;
michael@0 27 using mozilla::FloatingPoint;
michael@0 28 using JS::GenericNaN;
michael@0 29
michael@0 30 CodeGeneratorX86::CodeGeneratorX86(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm)
michael@0 31 : CodeGeneratorX86Shared(gen, graph, masm)
michael@0 32 {
michael@0 33 }
michael@0 34
michael@0 35 static const uint32_t FrameSizes[] = { 128, 256, 512, 1024 };
michael@0 36
michael@0 37 FrameSizeClass
michael@0 38 FrameSizeClass::FromDepth(uint32_t frameDepth)
michael@0 39 {
michael@0 40 for (uint32_t i = 0; i < JS_ARRAY_LENGTH(FrameSizes); i++) {
michael@0 41 if (frameDepth < FrameSizes[i])
michael@0 42 return FrameSizeClass(i);
michael@0 43 }
michael@0 44
michael@0 45 return FrameSizeClass::None();
michael@0 46 }
michael@0 47
michael@0 48 FrameSizeClass
michael@0 49 FrameSizeClass::ClassLimit()
michael@0 50 {
michael@0 51 return FrameSizeClass(JS_ARRAY_LENGTH(FrameSizes));
michael@0 52 }
michael@0 53
michael@0 54 uint32_t
michael@0 55 FrameSizeClass::frameSize() const
michael@0 56 {
michael@0 57 JS_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID);
michael@0 58 JS_ASSERT(class_ < JS_ARRAY_LENGTH(FrameSizes));
michael@0 59
michael@0 60 return FrameSizes[class_];
michael@0 61 }
michael@0 62
michael@0 63 ValueOperand
michael@0 64 CodeGeneratorX86::ToValue(LInstruction *ins, size_t pos)
michael@0 65 {
michael@0 66 Register typeReg = ToRegister(ins->getOperand(pos + TYPE_INDEX));
michael@0 67 Register payloadReg = ToRegister(ins->getOperand(pos + PAYLOAD_INDEX));
michael@0 68 return ValueOperand(typeReg, payloadReg);
michael@0 69 }
michael@0 70
michael@0 71 ValueOperand
michael@0 72 CodeGeneratorX86::ToOutValue(LInstruction *ins)
michael@0 73 {
michael@0 74 Register typeReg = ToRegister(ins->getDef(TYPE_INDEX));
michael@0 75 Register payloadReg = ToRegister(ins->getDef(PAYLOAD_INDEX));
michael@0 76 return ValueOperand(typeReg, payloadReg);
michael@0 77 }
michael@0 78
michael@0 79 ValueOperand
michael@0 80 CodeGeneratorX86::ToTempValue(LInstruction *ins, size_t pos)
michael@0 81 {
michael@0 82 Register typeReg = ToRegister(ins->getTemp(pos + TYPE_INDEX));
michael@0 83 Register payloadReg = ToRegister(ins->getTemp(pos + PAYLOAD_INDEX));
michael@0 84 return ValueOperand(typeReg, payloadReg);
michael@0 85 }
michael@0 86
michael@0 87 bool
michael@0 88 CodeGeneratorX86::visitValue(LValue *value)
michael@0 89 {
michael@0 90 const ValueOperand out = ToOutValue(value);
michael@0 91 masm.moveValue(value->value(), out);
michael@0 92 return true;
michael@0 93 }
michael@0 94
michael@0 95 bool
michael@0 96 CodeGeneratorX86::visitBox(LBox *box)
michael@0 97 {
michael@0 98 const LDefinition *type = box->getDef(TYPE_INDEX);
michael@0 99
michael@0 100 DebugOnly<const LAllocation *> a = box->getOperand(0);
michael@0 101 JS_ASSERT(!a->isConstant());
michael@0 102
michael@0 103 // On x86, the input operand and the output payload have the same
michael@0 104 // virtual register. All that needs to be written is the type tag for
michael@0 105 // the type definition.
michael@0 106 masm.mov(ImmWord(MIRTypeToTag(box->type())), ToRegister(type));
michael@0 107 return true;
michael@0 108 }
michael@0 109
michael@0 110 bool
michael@0 111 CodeGeneratorX86::visitBoxFloatingPoint(LBoxFloatingPoint *box)
michael@0 112 {
michael@0 113 const LAllocation *in = box->getOperand(0);
michael@0 114 const ValueOperand out = ToOutValue(box);
michael@0 115
michael@0 116 FloatRegister reg = ToFloatRegister(in);
michael@0 117 if (box->type() == MIRType_Float32) {
michael@0 118 masm.convertFloat32ToDouble(reg, ScratchFloatReg);
michael@0 119 reg = ScratchFloatReg;
michael@0 120 }
michael@0 121 masm.boxDouble(reg, out);
michael@0 122 return true;
michael@0 123 }
michael@0 124
michael@0 125 bool
michael@0 126 CodeGeneratorX86::visitUnbox(LUnbox *unbox)
michael@0 127 {
michael@0 128 // Note that for unbox, the type and payload indexes are switched on the
michael@0 129 // inputs.
michael@0 130 MUnbox *mir = unbox->mir();
michael@0 131
michael@0 132 if (mir->fallible()) {
michael@0 133 masm.cmpl(ToOperand(unbox->type()), Imm32(MIRTypeToTag(mir->type())));
michael@0 134 if (!bailoutIf(Assembler::NotEqual, unbox->snapshot()))
michael@0 135 return false;
michael@0 136 }
michael@0 137 return true;
michael@0 138 }
michael@0 139
michael@0 140 bool
michael@0 141 CodeGeneratorX86::visitLoadSlotV(LLoadSlotV *load)
michael@0 142 {
michael@0 143 const ValueOperand out = ToOutValue(load);
michael@0 144 Register base = ToRegister(load->input());
michael@0 145 int32_t offset = load->mir()->slot() * sizeof(js::Value);
michael@0 146
michael@0 147 masm.loadValue(Address(base, offset), out);
michael@0 148 return true;
michael@0 149 }
michael@0 150
michael@0 151 bool
michael@0 152 CodeGeneratorX86::visitLoadSlotT(LLoadSlotT *load)
michael@0 153 {
michael@0 154 Register base = ToRegister(load->input());
michael@0 155 int32_t offset = load->mir()->slot() * sizeof(js::Value);
michael@0 156
michael@0 157 if (load->mir()->type() == MIRType_Double)
michael@0 158 masm.loadInt32OrDouble(Operand(base, offset), ToFloatRegister(load->output()));
michael@0 159 else
michael@0 160 masm.load32(Address(base, offset + NUNBOX32_PAYLOAD_OFFSET), ToRegister(load->output()));
michael@0 161 return true;
michael@0 162 }
michael@0 163
michael@0 164 bool
michael@0 165 CodeGeneratorX86::visitStoreSlotT(LStoreSlotT *store)
michael@0 166 {
michael@0 167 Register base = ToRegister(store->slots());
michael@0 168 int32_t offset = store->mir()->slot() * sizeof(js::Value);
michael@0 169
michael@0 170 const LAllocation *value = store->value();
michael@0 171 MIRType valueType = store->mir()->value()->type();
michael@0 172
michael@0 173 if (store->mir()->needsBarrier())
michael@0 174 emitPreBarrier(Address(base, offset), store->mir()->slotType());
michael@0 175
michael@0 176 if (valueType == MIRType_Double) {
michael@0 177 masm.storeDouble(ToFloatRegister(value), Operand(base, offset));
michael@0 178 return true;
michael@0 179 }
michael@0 180
michael@0 181 // Store the type tag if needed.
michael@0 182 if (valueType != store->mir()->slotType())
michael@0 183 masm.storeTypeTag(ImmType(ValueTypeFromMIRType(valueType)), Operand(base, offset));
michael@0 184
michael@0 185 // Store the payload.
michael@0 186 if (value->isConstant())
michael@0 187 masm.storePayload(*value->toConstant(), Operand(base, offset));
michael@0 188 else
michael@0 189 masm.storePayload(ToRegister(value), Operand(base, offset));
michael@0 190
michael@0 191 return true;
michael@0 192 }
michael@0 193
michael@0 194 bool
michael@0 195 CodeGeneratorX86::visitLoadElementT(LLoadElementT *load)
michael@0 196 {
michael@0 197 Operand source = createArrayElementOperand(ToRegister(load->elements()), load->index());
michael@0 198
michael@0 199 if (load->mir()->needsHoleCheck()) {
michael@0 200 Assembler::Condition cond = masm.testMagic(Assembler::Equal, source);
michael@0 201 if (!bailoutIf(cond, load->snapshot()))
michael@0 202 return false;
michael@0 203 }
michael@0 204
michael@0 205 if (load->mir()->type() == MIRType_Double) {
michael@0 206 FloatRegister fpreg = ToFloatRegister(load->output());
michael@0 207 if (load->mir()->loadDoubles()) {
michael@0 208 if (source.kind() == Operand::MEM_REG_DISP)
michael@0 209 masm.loadDouble(source.toAddress(), fpreg);
michael@0 210 else
michael@0 211 masm.loadDouble(source.toBaseIndex(), fpreg);
michael@0 212 } else {
michael@0 213 masm.loadInt32OrDouble(source, fpreg);
michael@0 214 }
michael@0 215 } else {
michael@0 216 masm.movl(masm.ToPayload(source), ToRegister(load->output()));
michael@0 217 }
michael@0 218
michael@0 219 return true;
michael@0 220 }
michael@0 221
michael@0 222 void
michael@0 223 CodeGeneratorX86::storeElementTyped(const LAllocation *value, MIRType valueType, MIRType elementType,
michael@0 224 const Register &elements, const LAllocation *index)
michael@0 225 {
michael@0 226 Operand dest = createArrayElementOperand(elements, index);
michael@0 227
michael@0 228 if (valueType == MIRType_Double) {
michael@0 229 masm.storeDouble(ToFloatRegister(value), dest);
michael@0 230 return;
michael@0 231 }
michael@0 232
michael@0 233 // Store the type tag if needed.
michael@0 234 if (valueType != elementType)
michael@0 235 masm.storeTypeTag(ImmType(ValueTypeFromMIRType(valueType)), dest);
michael@0 236
michael@0 237 // Store the payload.
michael@0 238 if (value->isConstant())
michael@0 239 masm.storePayload(*value->toConstant(), dest);
michael@0 240 else
michael@0 241 masm.storePayload(ToRegister(value), dest);
michael@0 242 }
michael@0 243
michael@0 244 bool
michael@0 245 CodeGeneratorX86::visitImplicitThis(LImplicitThis *lir)
michael@0 246 {
michael@0 247 Register callee = ToRegister(lir->callee());
michael@0 248 const ValueOperand out = ToOutValue(lir);
michael@0 249
michael@0 250 // The implicit |this| is always |undefined| if the function's environment
michael@0 251 // is the current global.
michael@0 252 GlobalObject *global = &gen->info().script()->global();
michael@0 253 masm.cmpPtr(Operand(callee, JSFunction::offsetOfEnvironment()), ImmGCPtr(global));
michael@0 254
michael@0 255 // TODO: OOL stub path.
michael@0 256 if (!bailoutIf(Assembler::NotEqual, lir->snapshot()))
michael@0 257 return false;
michael@0 258
michael@0 259 masm.moveValue(UndefinedValue(), out);
michael@0 260 return true;
michael@0 261 }
michael@0 262
michael@0 263 bool
michael@0 264 CodeGeneratorX86::visitInterruptCheck(LInterruptCheck *lir)
michael@0 265 {
michael@0 266 OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing());
michael@0 267 if (!ool)
michael@0 268 return false;
michael@0 269
michael@0 270 masm.cmpl(Operand(AbsoluteAddress(GetIonContext()->runtime->addressOfInterrupt())), Imm32(0));
michael@0 271 masm.j(Assembler::NonZero, ool->entry());
michael@0 272 masm.bind(ool->rejoin());
michael@0 273 return true;
michael@0 274 }
michael@0 275
michael@0 276 bool
michael@0 277 CodeGeneratorX86::visitCompareB(LCompareB *lir)
michael@0 278 {
michael@0 279 MCompare *mir = lir->mir();
michael@0 280
michael@0 281 const ValueOperand lhs = ToValue(lir, LCompareB::Lhs);
michael@0 282 const LAllocation *rhs = lir->rhs();
michael@0 283 const Register output = ToRegister(lir->output());
michael@0 284
michael@0 285 JS_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE);
michael@0 286
michael@0 287 Label notBoolean, done;
michael@0 288 masm.branchTestBoolean(Assembler::NotEqual, lhs, &notBoolean);
michael@0 289 {
michael@0 290 if (rhs->isConstant())
michael@0 291 masm.cmp32(lhs.payloadReg(), Imm32(rhs->toConstant()->toBoolean()));
michael@0 292 else
michael@0 293 masm.cmp32(lhs.payloadReg(), ToRegister(rhs));
michael@0 294 masm.emitSet(JSOpToCondition(mir->compareType(), mir->jsop()), output);
michael@0 295 masm.jump(&done);
michael@0 296 }
michael@0 297 masm.bind(&notBoolean);
michael@0 298 {
michael@0 299 masm.move32(Imm32(mir->jsop() == JSOP_STRICTNE), output);
michael@0 300 }
michael@0 301
michael@0 302 masm.bind(&done);
michael@0 303 return true;
michael@0 304 }
michael@0 305
michael@0 306 bool
michael@0 307 CodeGeneratorX86::visitCompareBAndBranch(LCompareBAndBranch *lir)
michael@0 308 {
michael@0 309 MCompare *mir = lir->cmpMir();
michael@0 310 const ValueOperand lhs = ToValue(lir, LCompareBAndBranch::Lhs);
michael@0 311 const LAllocation *rhs = lir->rhs();
michael@0 312
michael@0 313 JS_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE);
michael@0 314
michael@0 315 Assembler::Condition cond = masm.testBoolean(Assembler::NotEqual, lhs);
michael@0 316 jumpToBlock((mir->jsop() == JSOP_STRICTEQ) ? lir->ifFalse() : lir->ifTrue(), cond);
michael@0 317
michael@0 318 if (rhs->isConstant())
michael@0 319 masm.cmp32(lhs.payloadReg(), Imm32(rhs->toConstant()->toBoolean()));
michael@0 320 else
michael@0 321 masm.cmp32(lhs.payloadReg(), ToRegister(rhs));
michael@0 322 emitBranch(JSOpToCondition(mir->compareType(), mir->jsop()), lir->ifTrue(), lir->ifFalse());
michael@0 323 return true;
michael@0 324 }
michael@0 325
michael@0 326 bool
michael@0 327 CodeGeneratorX86::visitCompareV(LCompareV *lir)
michael@0 328 {
michael@0 329 MCompare *mir = lir->mir();
michael@0 330 Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop());
michael@0 331 const ValueOperand lhs = ToValue(lir, LCompareV::LhsInput);
michael@0 332 const ValueOperand rhs = ToValue(lir, LCompareV::RhsInput);
michael@0 333 const Register output = ToRegister(lir->output());
michael@0 334
michael@0 335 JS_ASSERT(IsEqualityOp(mir->jsop()));
michael@0 336
michael@0 337 Label notEqual, done;
michael@0 338 masm.cmp32(lhs.typeReg(), rhs.typeReg());
michael@0 339 masm.j(Assembler::NotEqual, &notEqual);
michael@0 340 {
michael@0 341 masm.cmp32(lhs.payloadReg(), rhs.payloadReg());
michael@0 342 masm.emitSet(cond, output);
michael@0 343 masm.jump(&done);
michael@0 344 }
michael@0 345 masm.bind(&notEqual);
michael@0 346 {
michael@0 347 masm.move32(Imm32(cond == Assembler::NotEqual), output);
michael@0 348 }
michael@0 349
michael@0 350 masm.bind(&done);
michael@0 351 return true;
michael@0 352 }
michael@0 353
michael@0 354 bool
michael@0 355 CodeGeneratorX86::visitCompareVAndBranch(LCompareVAndBranch *lir)
michael@0 356 {
michael@0 357 MCompare *mir = lir->cmpMir();
michael@0 358 Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop());
michael@0 359 const ValueOperand lhs = ToValue(lir, LCompareVAndBranch::LhsInput);
michael@0 360 const ValueOperand rhs = ToValue(lir, LCompareVAndBranch::RhsInput);
michael@0 361
michael@0 362 JS_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ ||
michael@0 363 mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE);
michael@0 364
michael@0 365 MBasicBlock *notEqual = (cond == Assembler::Equal) ? lir->ifFalse() : lir->ifTrue();
michael@0 366
michael@0 367 masm.cmp32(lhs.typeReg(), rhs.typeReg());
michael@0 368 jumpToBlock(notEqual, Assembler::NotEqual);
michael@0 369 masm.cmp32(lhs.payloadReg(), rhs.payloadReg());
michael@0 370 emitBranch(cond, lir->ifTrue(), lir->ifFalse());
michael@0 371
michael@0 372 return true;
michael@0 373 }
michael@0 374
michael@0 375 bool
michael@0 376 CodeGeneratorX86::visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble *lir)
michael@0 377 {
michael@0 378 Register input = ToRegister(lir->input());
michael@0 379 Register temp = ToRegister(lir->temp());
michael@0 380
michael@0 381 if (input != temp)
michael@0 382 masm.mov(input, temp);
michael@0 383
michael@0 384 // Beware: convertUInt32ToDouble clobbers input.
michael@0 385 masm.convertUInt32ToDouble(temp, ToFloatRegister(lir->output()));
michael@0 386 return true;
michael@0 387 }
michael@0 388
michael@0 389 bool
michael@0 390 CodeGeneratorX86::visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32 *lir)
michael@0 391 {
michael@0 392 Register input = ToRegister(lir->input());
michael@0 393 Register temp = ToRegister(lir->temp());
michael@0 394 FloatRegister output = ToFloatRegister(lir->output());
michael@0 395
michael@0 396 if (input != temp)
michael@0 397 masm.mov(input, temp);
michael@0 398
michael@0 399 // Beware: convertUInt32ToFloat32 clobbers input.
michael@0 400 masm.convertUInt32ToFloat32(temp, output);
michael@0 401 return true;
michael@0 402 }
michael@0 403
michael@0 404 // Load a NaN or zero into a register for an out of bounds AsmJS or static
michael@0 405 // typed array load.
michael@0 406 class jit::OutOfLineLoadTypedArrayOutOfBounds : public OutOfLineCodeBase<CodeGeneratorX86>
michael@0 407 {
michael@0 408 AnyRegister dest_;
michael@0 409 bool isFloat32Load_;
michael@0 410 public:
michael@0 411 OutOfLineLoadTypedArrayOutOfBounds(AnyRegister dest, bool isFloat32Load)
michael@0 412 : dest_(dest), isFloat32Load_(isFloat32Load)
michael@0 413 {}
michael@0 414
michael@0 415 const AnyRegister &dest() const { return dest_; }
michael@0 416 bool isFloat32Load() const { return isFloat32Load_; }
michael@0 417 bool accept(CodeGeneratorX86 *codegen) { return codegen->visitOutOfLineLoadTypedArrayOutOfBounds(this); }
michael@0 418 };
michael@0 419
michael@0 420 template<typename T>
michael@0 421 void
michael@0 422 CodeGeneratorX86::loadViewTypeElement(ArrayBufferView::ViewType vt, const T &srcAddr,
michael@0 423 const LDefinition *out)
michael@0 424 {
michael@0 425 switch (vt) {
michael@0 426 case ArrayBufferView::TYPE_INT8: masm.movsblWithPatch(srcAddr, ToRegister(out)); break;
michael@0 427 case ArrayBufferView::TYPE_UINT8_CLAMPED:
michael@0 428 case ArrayBufferView::TYPE_UINT8: masm.movzblWithPatch(srcAddr, ToRegister(out)); break;
michael@0 429 case ArrayBufferView::TYPE_INT16: masm.movswlWithPatch(srcAddr, ToRegister(out)); break;
michael@0 430 case ArrayBufferView::TYPE_UINT16: masm.movzwlWithPatch(srcAddr, ToRegister(out)); break;
michael@0 431 case ArrayBufferView::TYPE_INT32:
michael@0 432 case ArrayBufferView::TYPE_UINT32: masm.movlWithPatch(srcAddr, ToRegister(out)); break;
michael@0 433 case ArrayBufferView::TYPE_FLOAT32: masm.movssWithPatch(srcAddr, ToFloatRegister(out)); break;
michael@0 434 case ArrayBufferView::TYPE_FLOAT64: masm.movsdWithPatch(srcAddr, ToFloatRegister(out)); break;
michael@0 435 default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
michael@0 436 }
michael@0 437 }
michael@0 438
michael@0 439 template<typename T>
michael@0 440 bool
michael@0 441 CodeGeneratorX86::loadAndNoteViewTypeElement(ArrayBufferView::ViewType vt, const T &srcAddr,
michael@0 442 const LDefinition *out)
michael@0 443 {
michael@0 444 uint32_t before = masm.size();
michael@0 445 loadViewTypeElement(vt, srcAddr, out);
michael@0 446 uint32_t after = masm.size();
michael@0 447 return masm.append(AsmJSHeapAccess(before, after, vt, ToAnyRegister(out)));
michael@0 448 }
michael@0 449
michael@0 450 bool
michael@0 451 CodeGeneratorX86::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins)
michael@0 452 {
michael@0 453 const MLoadTypedArrayElementStatic *mir = ins->mir();
michael@0 454 ArrayBufferView::ViewType vt = mir->viewType();
michael@0 455 JS_ASSERT_IF(vt == ArrayBufferView::TYPE_FLOAT32, mir->type() == MIRType_Float32);
michael@0 456
michael@0 457 Register ptr = ToRegister(ins->ptr());
michael@0 458 const LDefinition *out = ins->output();
michael@0 459
michael@0 460 OutOfLineLoadTypedArrayOutOfBounds *ool = nullptr;
michael@0 461 bool isFloat32Load = (vt == ArrayBufferView::TYPE_FLOAT32);
michael@0 462 if (!mir->fallible()) {
michael@0 463 ool = new(alloc()) OutOfLineLoadTypedArrayOutOfBounds(ToAnyRegister(out), isFloat32Load);
michael@0 464 if (!addOutOfLineCode(ool))
michael@0 465 return false;
michael@0 466 }
michael@0 467
michael@0 468 masm.cmpl(ptr, Imm32(mir->length()));
michael@0 469 if (ool)
michael@0 470 masm.j(Assembler::AboveOrEqual, ool->entry());
michael@0 471 else if (!bailoutIf(Assembler::AboveOrEqual, ins->snapshot()))
michael@0 472 return false;
michael@0 473
michael@0 474 Address srcAddr(ptr, (int32_t) mir->base());
michael@0 475 loadViewTypeElement(vt, srcAddr, out);
michael@0 476 if (vt == ArrayBufferView::TYPE_FLOAT64)
michael@0 477 masm.canonicalizeDouble(ToFloatRegister(out));
michael@0 478 if (vt == ArrayBufferView::TYPE_FLOAT32)
michael@0 479 masm.canonicalizeFloat(ToFloatRegister(out));
michael@0 480 if (ool)
michael@0 481 masm.bind(ool->rejoin());
michael@0 482 return true;
michael@0 483 }
michael@0 484
michael@0 485 bool
michael@0 486 CodeGeneratorX86::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins)
michael@0 487 {
michael@0 488 const MAsmJSLoadHeap *mir = ins->mir();
michael@0 489 ArrayBufferView::ViewType vt = mir->viewType();
michael@0 490 const LAllocation *ptr = ins->ptr();
michael@0 491 const LDefinition *out = ins->output();
michael@0 492
michael@0 493 if (ptr->isConstant()) {
michael@0 494 // The constant displacement still needs to be added to the as-yet-unknown
michael@0 495 // base address of the heap. For now, embed the displacement as an
michael@0 496 // immediate in the instruction. This displacement will fixed up when the
michael@0 497 // base address is known during dynamic linking (AsmJSModule::initHeap).
michael@0 498 PatchedAbsoluteAddress srcAddr((void *) ptr->toConstant()->toInt32());
michael@0 499 return loadAndNoteViewTypeElement(vt, srcAddr, out);
michael@0 500 }
michael@0 501
michael@0 502 Register ptrReg = ToRegister(ptr);
michael@0 503 Address srcAddr(ptrReg, 0);
michael@0 504
michael@0 505 if (mir->skipBoundsCheck())
michael@0 506 return loadAndNoteViewTypeElement(vt, srcAddr, out);
michael@0 507
michael@0 508 bool isFloat32Load = vt == ArrayBufferView::TYPE_FLOAT32;
michael@0 509 OutOfLineLoadTypedArrayOutOfBounds *ool = new(alloc()) OutOfLineLoadTypedArrayOutOfBounds(ToAnyRegister(out), isFloat32Load);
michael@0 510 if (!addOutOfLineCode(ool))
michael@0 511 return false;
michael@0 512
michael@0 513 CodeOffsetLabel cmp = masm.cmplWithPatch(ptrReg, Imm32(0));
michael@0 514 masm.j(Assembler::AboveOrEqual, ool->entry());
michael@0 515
michael@0 516 uint32_t before = masm.size();
michael@0 517 loadViewTypeElement(vt, srcAddr, out);
michael@0 518 uint32_t after = masm.size();
michael@0 519 masm.bind(ool->rejoin());
michael@0 520 return masm.append(AsmJSHeapAccess(before, after, vt, ToAnyRegister(out), cmp.offset()));
michael@0 521 }
michael@0 522
michael@0 523 bool
michael@0 524 CodeGeneratorX86::visitOutOfLineLoadTypedArrayOutOfBounds(OutOfLineLoadTypedArrayOutOfBounds *ool)
michael@0 525 {
michael@0 526 if (ool->dest().isFloat()) {
michael@0 527 if (ool->isFloat32Load())
michael@0 528 masm.loadConstantFloat32(float(GenericNaN()), ool->dest().fpu());
michael@0 529 else
michael@0 530 masm.loadConstantDouble(GenericNaN(), ool->dest().fpu());
michael@0 531 } else {
michael@0 532 Register destReg = ool->dest().gpr();
michael@0 533 masm.mov(ImmWord(0), destReg);
michael@0 534 }
michael@0 535 masm.jmp(ool->rejoin());
michael@0 536 return true;
michael@0 537 }
michael@0 538
michael@0 539 template<typename T>
michael@0 540 void
michael@0 541 CodeGeneratorX86::storeViewTypeElement(ArrayBufferView::ViewType vt, const LAllocation *value,
michael@0 542 const T &dstAddr)
michael@0 543 {
michael@0 544 switch (vt) {
michael@0 545 case ArrayBufferView::TYPE_INT8:
michael@0 546 case ArrayBufferView::TYPE_UINT8_CLAMPED:
michael@0 547 case ArrayBufferView::TYPE_UINT8: masm.movbWithPatch(ToRegister(value), dstAddr); break;
michael@0 548 case ArrayBufferView::TYPE_INT16:
michael@0 549 case ArrayBufferView::TYPE_UINT16: masm.movwWithPatch(ToRegister(value), dstAddr); break;
michael@0 550 case ArrayBufferView::TYPE_INT32:
michael@0 551 case ArrayBufferView::TYPE_UINT32: masm.movlWithPatch(ToRegister(value), dstAddr); break;
michael@0 552 case ArrayBufferView::TYPE_FLOAT32: masm.movssWithPatch(ToFloatRegister(value), dstAddr); break;
michael@0 553 case ArrayBufferView::TYPE_FLOAT64: masm.movsdWithPatch(ToFloatRegister(value), dstAddr); break;
michael@0 554 default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
michael@0 555 }
michael@0 556 }
michael@0 557
michael@0 558 template<typename T>
michael@0 559 bool
michael@0 560 CodeGeneratorX86::storeAndNoteViewTypeElement(ArrayBufferView::ViewType vt, const LAllocation *value,
michael@0 561 const T &dstAddr)
michael@0 562 {
michael@0 563 uint32_t before = masm.size();
michael@0 564 storeViewTypeElement(vt, value, dstAddr);
michael@0 565 uint32_t after = masm.size();
michael@0 566 return masm.append(AsmJSHeapAccess(before, after));
michael@0 567 }
michael@0 568
michael@0 569 bool
michael@0 570 CodeGeneratorX86::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins)
michael@0 571 {
michael@0 572 MStoreTypedArrayElementStatic *mir = ins->mir();
michael@0 573 ArrayBufferView::ViewType vt = mir->viewType();
michael@0 574
michael@0 575 Register ptr = ToRegister(ins->ptr());
michael@0 576 const LAllocation *value = ins->value();
michael@0 577
michael@0 578 masm.cmpl(ptr, Imm32(mir->length()));
michael@0 579 Label rejoin;
michael@0 580 masm.j(Assembler::AboveOrEqual, &rejoin);
michael@0 581
michael@0 582 Address dstAddr(ptr, (int32_t) mir->base());
michael@0 583 storeViewTypeElement(vt, value, dstAddr);
michael@0 584 masm.bind(&rejoin);
michael@0 585 return true;
michael@0 586 }
michael@0 587
michael@0 588 bool
michael@0 589 CodeGeneratorX86::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
michael@0 590 {
michael@0 591 MAsmJSStoreHeap *mir = ins->mir();
michael@0 592 ArrayBufferView::ViewType vt = mir->viewType();
michael@0 593 const LAllocation *value = ins->value();
michael@0 594 const LAllocation *ptr = ins->ptr();
michael@0 595
michael@0 596 if (ptr->isConstant()) {
michael@0 597 // The constant displacement still needs to be added to the as-yet-unknown
michael@0 598 // base address of the heap. For now, embed the displacement as an
michael@0 599 // immediate in the instruction. This displacement will fixed up when the
michael@0 600 // base address is known during dynamic linking (AsmJSModule::initHeap).
michael@0 601 PatchedAbsoluteAddress dstAddr((void *) ptr->toConstant()->toInt32());
michael@0 602 return storeAndNoteViewTypeElement(vt, value, dstAddr);
michael@0 603 }
michael@0 604
michael@0 605 Register ptrReg = ToRegister(ptr);
michael@0 606 Address dstAddr(ptrReg, 0);
michael@0 607
michael@0 608 if (mir->skipBoundsCheck())
michael@0 609 return storeAndNoteViewTypeElement(vt, value, dstAddr);
michael@0 610
michael@0 611 CodeOffsetLabel cmp = masm.cmplWithPatch(ptrReg, Imm32(0));
michael@0 612 Label rejoin;
michael@0 613 masm.j(Assembler::AboveOrEqual, &rejoin);
michael@0 614
michael@0 615 uint32_t before = masm.size();
michael@0 616 storeViewTypeElement(vt, value, dstAddr);
michael@0 617 uint32_t after = masm.size();
michael@0 618 masm.bind(&rejoin);
michael@0 619 return masm.append(AsmJSHeapAccess(before, after, cmp.offset()));
michael@0 620 }
michael@0 621
michael@0 622 bool
michael@0 623 CodeGeneratorX86::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins)
michael@0 624 {
michael@0 625 MAsmJSLoadGlobalVar *mir = ins->mir();
michael@0 626 MIRType type = mir->type();
michael@0 627 JS_ASSERT(IsNumberType(type));
michael@0 628
michael@0 629 CodeOffsetLabel label;
michael@0 630 if (type == MIRType_Int32)
michael@0 631 label = masm.movlWithPatch(PatchedAbsoluteAddress(), ToRegister(ins->output()));
michael@0 632 else if (type == MIRType_Float32)
michael@0 633 label = masm.movssWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output()));
michael@0 634 else
michael@0 635 label = masm.movsdWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output()));
michael@0 636
michael@0 637 return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset()));
michael@0 638 }
michael@0 639
michael@0 640 bool
michael@0 641 CodeGeneratorX86::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins)
michael@0 642 {
michael@0 643 MAsmJSStoreGlobalVar *mir = ins->mir();
michael@0 644
michael@0 645 MIRType type = mir->value()->type();
michael@0 646 JS_ASSERT(IsNumberType(type));
michael@0 647
michael@0 648 CodeOffsetLabel label;
michael@0 649 if (type == MIRType_Int32)
michael@0 650 label = masm.movlWithPatch(ToRegister(ins->value()), PatchedAbsoluteAddress());
michael@0 651 else if (type == MIRType_Float32)
michael@0 652 label = masm.movssWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
michael@0 653 else
michael@0 654 label = masm.movsdWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
michael@0 655
michael@0 656 return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset()));
michael@0 657 }
michael@0 658
michael@0 659 bool
michael@0 660 CodeGeneratorX86::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr *ins)
michael@0 661 {
michael@0 662 MAsmJSLoadFuncPtr *mir = ins->mir();
michael@0 663
michael@0 664 Register index = ToRegister(ins->index());
michael@0 665 Register out = ToRegister(ins->output());
michael@0 666 CodeOffsetLabel label = masm.movlWithPatch(PatchedAbsoluteAddress(), index, TimesFour, out);
michael@0 667
michael@0 668 return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset()));
michael@0 669 }
michael@0 670
michael@0 671 bool
michael@0 672 CodeGeneratorX86::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc *ins)
michael@0 673 {
michael@0 674 MAsmJSLoadFFIFunc *mir = ins->mir();
michael@0 675
michael@0 676 Register out = ToRegister(ins->output());
michael@0 677 CodeOffsetLabel label = masm.movlWithPatch(PatchedAbsoluteAddress(), out);
michael@0 678
michael@0 679 return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset()));
michael@0 680 }
michael@0 681
michael@0 682 void
michael@0 683 CodeGeneratorX86::postAsmJSCall(LAsmJSCall *lir)
michael@0 684 {
michael@0 685 MAsmJSCall *mir = lir->mir();
michael@0 686 if (!IsFloatingPointType(mir->type()) || mir->callee().which() != MAsmJSCall::Callee::Builtin)
michael@0 687 return;
michael@0 688
michael@0 689 if (mir->type() == MIRType_Float32) {
michael@0 690 masm.reserveStack(sizeof(float));
michael@0 691 Operand op(esp, 0);
michael@0 692 masm.fstp32(op);
michael@0 693 masm.loadFloat32(op, ReturnFloatReg);
michael@0 694 masm.freeStack(sizeof(float));
michael@0 695 } else {
michael@0 696 masm.reserveStack(sizeof(double));
michael@0 697 Operand op(esp, 0);
michael@0 698 masm.fstp(op);
michael@0 699 masm.loadDouble(op, ReturnFloatReg);
michael@0 700 masm.freeStack(sizeof(double));
michael@0 701 }
michael@0 702 }
michael@0 703
michael@0 704 void
michael@0 705 DispatchIonCache::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
michael@0 706 {
michael@0 707 // On x86, where there is no general purpose scratch register available,
michael@0 708 // child cache classes must manually specify a dispatch scratch register.
michael@0 709 MOZ_ASSUME_UNREACHABLE("x86 needs manual assignment of dispatchScratch");
michael@0 710 }
michael@0 711
michael@0 712 void
michael@0 713 GetPropertyParIC::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
michael@0 714 {
michael@0 715 // We don't have a scratch register, but only use the temp if we needed
michael@0 716 // one, it's BogusTemp otherwise.
michael@0 717 JS_ASSERT(ins->isGetPropertyCacheV() || ins->isGetPropertyCacheT());
michael@0 718 if (ins->isGetPropertyCacheV() || ins->toGetPropertyCacheT()->temp()->isBogusTemp())
michael@0 719 addState->dispatchScratch = output_.scratchReg().gpr();
michael@0 720 else
michael@0 721 addState->dispatchScratch = ToRegister(ins->toGetPropertyCacheT()->temp());
michael@0 722 }
michael@0 723
michael@0 724 void
michael@0 725 GetElementParIC::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
michael@0 726 {
michael@0 727 // We don't have a scratch register, but only use the temp if we needed
michael@0 728 // one, it's BogusTemp otherwise.
michael@0 729 JS_ASSERT(ins->isGetElementCacheV() || ins->isGetElementCacheT());
michael@0 730 if (ins->isGetElementCacheV() || ins->toGetElementCacheT()->temp()->isBogusTemp())
michael@0 731 addState->dispatchScratch = output_.scratchReg().gpr();
michael@0 732 else
michael@0 733 addState->dispatchScratch = ToRegister(ins->toGetElementCacheT()->temp());
michael@0 734 }
michael@0 735
michael@0 736 void
michael@0 737 SetPropertyParIC::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
michael@0 738 {
michael@0 739 // We don't have an output register to reuse, so we always need a temp.
michael@0 740 JS_ASSERT(ins->isSetPropertyCacheV() || ins->isSetPropertyCacheT());
michael@0 741 if (ins->isSetPropertyCacheV())
michael@0 742 addState->dispatchScratch = ToRegister(ins->toSetPropertyCacheV()->tempForDispatchCache());
michael@0 743 else
michael@0 744 addState->dispatchScratch = ToRegister(ins->toSetPropertyCacheT()->tempForDispatchCache());
michael@0 745 }
michael@0 746
michael@0 747 void
michael@0 748 SetElementParIC::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
michael@0 749 {
michael@0 750 // We don't have an output register to reuse, but luckily SetElementCache
michael@0 751 // already needs a temp.
michael@0 752 JS_ASSERT(ins->isSetElementCacheV() || ins->isSetElementCacheT());
michael@0 753 if (ins->isSetElementCacheV())
michael@0 754 addState->dispatchScratch = ToRegister(ins->toSetElementCacheV()->temp());
michael@0 755 else
michael@0 756 addState->dispatchScratch = ToRegister(ins->toSetElementCacheT()->temp());
michael@0 757 }
michael@0 758
michael@0 759 namespace js {
michael@0 760 namespace jit {
michael@0 761
michael@0 762 class OutOfLineTruncate : public OutOfLineCodeBase<CodeGeneratorX86>
michael@0 763 {
michael@0 764 LTruncateDToInt32 *ins_;
michael@0 765
michael@0 766 public:
michael@0 767 OutOfLineTruncate(LTruncateDToInt32 *ins)
michael@0 768 : ins_(ins)
michael@0 769 { }
michael@0 770
michael@0 771 bool accept(CodeGeneratorX86 *codegen) {
michael@0 772 return codegen->visitOutOfLineTruncate(this);
michael@0 773 }
michael@0 774 LTruncateDToInt32 *ins() const {
michael@0 775 return ins_;
michael@0 776 }
michael@0 777 };
michael@0 778
michael@0 779 class OutOfLineTruncateFloat32 : public OutOfLineCodeBase<CodeGeneratorX86>
michael@0 780 {
michael@0 781 LTruncateFToInt32 *ins_;
michael@0 782
michael@0 783 public:
michael@0 784 OutOfLineTruncateFloat32(LTruncateFToInt32 *ins)
michael@0 785 : ins_(ins)
michael@0 786 { }
michael@0 787
michael@0 788 bool accept(CodeGeneratorX86 *codegen) {
michael@0 789 return codegen->visitOutOfLineTruncateFloat32(this);
michael@0 790 }
michael@0 791 LTruncateFToInt32 *ins() const {
michael@0 792 return ins_;
michael@0 793 }
michael@0 794 };
michael@0 795
michael@0 796 } // namespace jit
michael@0 797 } // namespace js
michael@0 798
michael@0 799 bool
michael@0 800 CodeGeneratorX86::visitTruncateDToInt32(LTruncateDToInt32 *ins)
michael@0 801 {
michael@0 802 FloatRegister input = ToFloatRegister(ins->input());
michael@0 803 Register output = ToRegister(ins->output());
michael@0 804
michael@0 805 OutOfLineTruncate *ool = new(alloc()) OutOfLineTruncate(ins);
michael@0 806 if (!addOutOfLineCode(ool))
michael@0 807 return false;
michael@0 808
michael@0 809 masm.branchTruncateDouble(input, output, ool->entry());
michael@0 810 masm.bind(ool->rejoin());
michael@0 811 return true;
michael@0 812 }
michael@0 813
michael@0 814 bool
michael@0 815 CodeGeneratorX86::visitTruncateFToInt32(LTruncateFToInt32 *ins)
michael@0 816 {
michael@0 817 FloatRegister input = ToFloatRegister(ins->input());
michael@0 818 Register output = ToRegister(ins->output());
michael@0 819
michael@0 820 OutOfLineTruncateFloat32 *ool = new(alloc()) OutOfLineTruncateFloat32(ins);
michael@0 821 if (!addOutOfLineCode(ool))
michael@0 822 return false;
michael@0 823
michael@0 824 masm.branchTruncateFloat32(input, output, ool->entry());
michael@0 825 masm.bind(ool->rejoin());
michael@0 826 return true;
michael@0 827 }
michael@0 828
michael@0 829 bool
michael@0 830 CodeGeneratorX86::visitOutOfLineTruncate(OutOfLineTruncate *ool)
michael@0 831 {
michael@0 832 LTruncateDToInt32 *ins = ool->ins();
michael@0 833 FloatRegister input = ToFloatRegister(ins->input());
michael@0 834 Register output = ToRegister(ins->output());
michael@0 835
michael@0 836 Label fail;
michael@0 837
michael@0 838 if (Assembler::HasSSE3()) {
michael@0 839 // Push double.
michael@0 840 masm.subl(Imm32(sizeof(double)), esp);
michael@0 841 masm.storeDouble(input, Operand(esp, 0));
michael@0 842
michael@0 843 static const uint32_t EXPONENT_MASK = 0x7ff00000;
michael@0 844 static const uint32_t EXPONENT_SHIFT = FloatingPoint<double>::ExponentShift - 32;
michael@0 845 static const uint32_t TOO_BIG_EXPONENT = (FloatingPoint<double>::ExponentBias + 63)
michael@0 846 << EXPONENT_SHIFT;
michael@0 847
michael@0 848 // Check exponent to avoid fp exceptions.
michael@0 849 Label failPopDouble;
michael@0 850 masm.load32(Address(esp, 4), output);
michael@0 851 masm.and32(Imm32(EXPONENT_MASK), output);
michael@0 852 masm.branch32(Assembler::GreaterThanOrEqual, output, Imm32(TOO_BIG_EXPONENT), &failPopDouble);
michael@0 853
michael@0 854 // Load double, perform 64-bit truncation.
michael@0 855 masm.fld(Operand(esp, 0));
michael@0 856 masm.fisttp(Operand(esp, 0));
michael@0 857
michael@0 858 // Load low word, pop double and jump back.
michael@0 859 masm.load32(Address(esp, 0), output);
michael@0 860 masm.addl(Imm32(sizeof(double)), esp);
michael@0 861 masm.jump(ool->rejoin());
michael@0 862
michael@0 863 masm.bind(&failPopDouble);
michael@0 864 masm.addl(Imm32(sizeof(double)), esp);
michael@0 865 masm.jump(&fail);
michael@0 866 } else {
michael@0 867 FloatRegister temp = ToFloatRegister(ins->tempFloat());
michael@0 868
michael@0 869 // Try to convert doubles representing integers within 2^32 of a signed
michael@0 870 // integer, by adding/subtracting 2^32 and then trying to convert to int32.
michael@0 871 // This has to be an exact conversion, as otherwise the truncation works
michael@0 872 // incorrectly on the modified value.
michael@0 873 masm.xorpd(ScratchFloatReg, ScratchFloatReg);
michael@0 874 masm.ucomisd(input, ScratchFloatReg);
michael@0 875 masm.j(Assembler::Parity, &fail);
michael@0 876
michael@0 877 {
michael@0 878 Label positive;
michael@0 879 masm.j(Assembler::Above, &positive);
michael@0 880
michael@0 881 masm.loadConstantDouble(4294967296.0, temp);
michael@0 882 Label skip;
michael@0 883 masm.jmp(&skip);
michael@0 884
michael@0 885 masm.bind(&positive);
michael@0 886 masm.loadConstantDouble(-4294967296.0, temp);
michael@0 887 masm.bind(&skip);
michael@0 888 }
michael@0 889
michael@0 890 masm.addsd(input, temp);
michael@0 891 masm.cvttsd2si(temp, output);
michael@0 892 masm.cvtsi2sd(output, ScratchFloatReg);
michael@0 893
michael@0 894 masm.ucomisd(temp, ScratchFloatReg);
michael@0 895 masm.j(Assembler::Parity, &fail);
michael@0 896 masm.j(Assembler::Equal, ool->rejoin());
michael@0 897 }
michael@0 898
michael@0 899 masm.bind(&fail);
michael@0 900 {
michael@0 901 saveVolatile(output);
michael@0 902
michael@0 903 masm.setupUnalignedABICall(1, output);
michael@0 904 masm.passABIArg(input, MoveOp::DOUBLE);
michael@0 905 if (gen->compilingAsmJS())
michael@0 906 masm.callWithABI(AsmJSImm_ToInt32);
michael@0 907 else
michael@0 908 masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::ToInt32));
michael@0 909 masm.storeCallResult(output);
michael@0 910
michael@0 911 restoreVolatile(output);
michael@0 912 }
michael@0 913
michael@0 914 masm.jump(ool->rejoin());
michael@0 915 return true;
michael@0 916 }
michael@0 917
michael@0 918 bool
michael@0 919 CodeGeneratorX86::visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32 *ool)
michael@0 920 {
michael@0 921 LTruncateFToInt32 *ins = ool->ins();
michael@0 922 FloatRegister input = ToFloatRegister(ins->input());
michael@0 923 Register output = ToRegister(ins->output());
michael@0 924
michael@0 925 Label fail;
michael@0 926
michael@0 927 if (Assembler::HasSSE3()) {
michael@0 928 // Push float32, but subtracts 64 bits so that the value popped by fisttp fits
michael@0 929 masm.subl(Imm32(sizeof(uint64_t)), esp);
michael@0 930 masm.storeFloat32(input, Operand(esp, 0));
michael@0 931
michael@0 932 static const uint32_t EXPONENT_MASK = FloatingPoint<float>::ExponentBits;
michael@0 933 static const uint32_t EXPONENT_SHIFT = FloatingPoint<float>::ExponentShift;
michael@0 934 // Integers are still 64 bits long, so we can still test for an exponent > 63.
michael@0 935 static const uint32_t TOO_BIG_EXPONENT = (FloatingPoint<float>::ExponentBias + 63)
michael@0 936 << EXPONENT_SHIFT;
michael@0 937
michael@0 938 // Check exponent to avoid fp exceptions.
michael@0 939 Label failPopFloat;
michael@0 940 masm.movl(Operand(esp, 0), output);
michael@0 941 masm.and32(Imm32(EXPONENT_MASK), output);
michael@0 942 masm.branch32(Assembler::GreaterThanOrEqual, output, Imm32(TOO_BIG_EXPONENT), &failPopFloat);
michael@0 943
michael@0 944 // Load float, perform 32-bit truncation.
michael@0 945 masm.fld32(Operand(esp, 0));
michael@0 946 masm.fisttp(Operand(esp, 0));
michael@0 947
michael@0 948 // Load low word, pop 64bits and jump back.
michael@0 949 masm.movl(Operand(esp, 0), output);
michael@0 950 masm.addl(Imm32(sizeof(uint64_t)), esp);
michael@0 951 masm.jump(ool->rejoin());
michael@0 952
michael@0 953 masm.bind(&failPopFloat);
michael@0 954 masm.addl(Imm32(sizeof(uint64_t)), esp);
michael@0 955 masm.jump(&fail);
michael@0 956 } else {
michael@0 957 FloatRegister temp = ToFloatRegister(ins->tempFloat());
michael@0 958
michael@0 959 // Try to convert float32 representing integers within 2^32 of a signed
michael@0 960 // integer, by adding/subtracting 2^32 and then trying to convert to int32.
michael@0 961 // This has to be an exact conversion, as otherwise the truncation works
michael@0 962 // incorrectly on the modified value.
michael@0 963 masm.xorps(ScratchFloatReg, ScratchFloatReg);
michael@0 964 masm.ucomiss(input, ScratchFloatReg);
michael@0 965 masm.j(Assembler::Parity, &fail);
michael@0 966
michael@0 967 {
michael@0 968 Label positive;
michael@0 969 masm.j(Assembler::Above, &positive);
michael@0 970
michael@0 971 masm.loadConstantFloat32(4294967296.f, temp);
michael@0 972 Label skip;
michael@0 973 masm.jmp(&skip);
michael@0 974
michael@0 975 masm.bind(&positive);
michael@0 976 masm.loadConstantFloat32(-4294967296.f, temp);
michael@0 977 masm.bind(&skip);
michael@0 978 }
michael@0 979
michael@0 980 masm.addss(input, temp);
michael@0 981 masm.cvttss2si(temp, output);
michael@0 982 masm.cvtsi2ss(output, ScratchFloatReg);
michael@0 983
michael@0 984 masm.ucomiss(temp, ScratchFloatReg);
michael@0 985 masm.j(Assembler::Parity, &fail);
michael@0 986 masm.j(Assembler::Equal, ool->rejoin());
michael@0 987 }
michael@0 988
michael@0 989 masm.bind(&fail);
michael@0 990 {
michael@0 991 saveVolatile(output);
michael@0 992
michael@0 993 masm.push(input);
michael@0 994 masm.setupUnalignedABICall(1, output);
michael@0 995 masm.cvtss2sd(input, input);
michael@0 996 masm.passABIArg(input, MoveOp::DOUBLE);
michael@0 997
michael@0 998 if (gen->compilingAsmJS())
michael@0 999 masm.callWithABI(AsmJSImm_ToInt32);
michael@0 1000 else
michael@0 1001 masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::ToInt32));
michael@0 1002
michael@0 1003 masm.storeCallResult(output);
michael@0 1004 masm.pop(input);
michael@0 1005
michael@0 1006 restoreVolatile(output);
michael@0 1007 }
michael@0 1008
michael@0 1009 masm.jump(ool->rejoin());
michael@0 1010 return true;
michael@0 1011 }

mercurial