js/src/jit/mips/CodeGenerator-mips.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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/mips/CodeGenerator-mips.h"
michael@0 8
michael@0 9 #include "mozilla/MathAlgorithms.h"
michael@0 10
michael@0 11 #include "jscntxt.h"
michael@0 12 #include "jscompartment.h"
michael@0 13 #include "jsnum.h"
michael@0 14
michael@0 15 #include "jit/CodeGenerator.h"
michael@0 16 #include "jit/IonFrames.h"
michael@0 17 #include "jit/JitCompartment.h"
michael@0 18 #include "jit/MIR.h"
michael@0 19 #include "jit/MIRGraph.h"
michael@0 20 #include "vm/Shape.h"
michael@0 21
michael@0 22 #include "jsscriptinlines.h"
michael@0 23
michael@0 24 #include "jit/shared/CodeGenerator-shared-inl.h"
michael@0 25
michael@0 26 using namespace js;
michael@0 27 using namespace js::jit;
michael@0 28
michael@0 29 using mozilla::FloorLog2;
michael@0 30 using mozilla::NegativeInfinity;
michael@0 31 using JS::GenericNaN;
michael@0 32
michael@0 33 // shared
michael@0 34 CodeGeneratorMIPS::CodeGeneratorMIPS(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm)
michael@0 35 : CodeGeneratorShared(gen, graph, masm)
michael@0 36 {
michael@0 37 }
michael@0 38
michael@0 39 bool
michael@0 40 CodeGeneratorMIPS::generatePrologue()
michael@0 41 {
michael@0 42 if (gen->compilingAsmJS()) {
michael@0 43 masm.Push(ra);
michael@0 44 // Note that this automatically sets MacroAssembler::framePushed().
michael@0 45 masm.reserveStack(frameDepth_);
michael@0 46 } else {
michael@0 47 // Note that this automatically sets MacroAssembler::framePushed().
michael@0 48 masm.reserveStack(frameSize());
michael@0 49 masm.checkStackAlignment();
michael@0 50 }
michael@0 51
michael@0 52 return true;
michael@0 53 }
michael@0 54
michael@0 55 bool
michael@0 56 CodeGeneratorMIPS::generateEpilogue()
michael@0 57 {
michael@0 58 masm.bind(&returnLabel_);
michael@0 59 #if JS_TRACE_LOGGING
michael@0 60 masm.tracelogStop();
michael@0 61 #endif
michael@0 62 if (gen->compilingAsmJS()) {
michael@0 63 // Pop the stack we allocated at the start of the function.
michael@0 64 masm.freeStack(frameDepth_);
michael@0 65 masm.Pop(ra);
michael@0 66 masm.abiret();
michael@0 67 MOZ_ASSERT(masm.framePushed() == 0);
michael@0 68 } else {
michael@0 69 // Pop the stack we allocated at the start of the function.
michael@0 70 masm.freeStack(frameSize());
michael@0 71 MOZ_ASSERT(masm.framePushed() == 0);
michael@0 72 masm.ret();
michael@0 73 }
michael@0 74 return true;
michael@0 75 }
michael@0 76
michael@0 77 void
michael@0 78 CodeGeneratorMIPS::branchToBlock(Assembler::FloatFormat fmt, FloatRegister lhs, FloatRegister rhs,
michael@0 79 MBasicBlock *mir, Assembler::DoubleCondition cond)
michael@0 80 {
michael@0 81 Label *label = mir->lir()->label();
michael@0 82 if (Label *oolEntry = labelForBackedgeWithImplicitCheck(mir)) {
michael@0 83 // Note: the backedge is initially a jump to the next instruction.
michael@0 84 // It will be patched to the target block's label during link().
michael@0 85 RepatchLabel rejoin;
michael@0 86
michael@0 87 CodeOffsetJump backedge;
michael@0 88 Label skip;
michael@0 89 if (fmt == Assembler::DoubleFloat)
michael@0 90 masm.ma_bc1d(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump);
michael@0 91 else
michael@0 92 masm.ma_bc1s(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump);
michael@0 93
michael@0 94 backedge = masm.jumpWithPatch(&rejoin);
michael@0 95 masm.bind(&rejoin);
michael@0 96 masm.bind(&skip);
michael@0 97
michael@0 98 if (!patchableBackedges_.append(PatchableBackedgeInfo(backedge, label, oolEntry)))
michael@0 99 MOZ_CRASH();
michael@0 100 } else {
michael@0 101 if (fmt == Assembler::DoubleFloat)
michael@0 102 masm.branchDouble(cond, lhs, rhs, mir->lir()->label());
michael@0 103 else
michael@0 104 masm.branchFloat(cond, lhs, rhs, mir->lir()->label());
michael@0 105 }
michael@0 106 }
michael@0 107
michael@0 108 bool
michael@0 109 OutOfLineBailout::accept(CodeGeneratorMIPS *codegen)
michael@0 110 {
michael@0 111 return codegen->visitOutOfLineBailout(this);
michael@0 112 }
michael@0 113
michael@0 114 bool
michael@0 115 CodeGeneratorMIPS::visitTestIAndBranch(LTestIAndBranch *test)
michael@0 116 {
michael@0 117 const LAllocation *opd = test->getOperand(0);
michael@0 118 MBasicBlock *ifTrue = test->ifTrue();
michael@0 119 MBasicBlock *ifFalse = test->ifFalse();
michael@0 120
michael@0 121 emitBranch(ToRegister(opd), Imm32(0), Assembler::NonZero, ifTrue, ifFalse);
michael@0 122 return true;
michael@0 123 }
michael@0 124
michael@0 125 bool
michael@0 126 CodeGeneratorMIPS::visitCompare(LCompare *comp)
michael@0 127 {
michael@0 128 Assembler::Condition cond = JSOpToCondition(comp->mir()->compareType(), comp->jsop());
michael@0 129 const LAllocation *left = comp->getOperand(0);
michael@0 130 const LAllocation *right = comp->getOperand(1);
michael@0 131 const LDefinition *def = comp->getDef(0);
michael@0 132
michael@0 133 if (right->isConstant())
michael@0 134 masm.cmp32Set(cond, ToRegister(left), Imm32(ToInt32(right)), ToRegister(def));
michael@0 135 else if (right->isGeneralReg())
michael@0 136 masm.cmp32Set(cond, ToRegister(left), ToRegister(right), ToRegister(def));
michael@0 137 else
michael@0 138 masm.cmp32Set(cond, ToRegister(left), ToAddress(right), ToRegister(def));
michael@0 139
michael@0 140 return true;
michael@0 141 }
michael@0 142
michael@0 143 bool
michael@0 144 CodeGeneratorMIPS::visitCompareAndBranch(LCompareAndBranch *comp)
michael@0 145 {
michael@0 146 Assembler::Condition cond = JSOpToCondition(comp->cmpMir()->compareType(), comp->jsop());
michael@0 147 if (comp->right()->isConstant()) {
michael@0 148 emitBranch(ToRegister(comp->left()), Imm32(ToInt32(comp->right())), cond,
michael@0 149 comp->ifTrue(), comp->ifFalse());
michael@0 150 } else if (comp->right()->isGeneralReg()) {
michael@0 151 emitBranch(ToRegister(comp->left()), ToRegister(comp->right()), cond,
michael@0 152 comp->ifTrue(), comp->ifFalse());
michael@0 153 } else {
michael@0 154 emitBranch(ToRegister(comp->left()), ToAddress(comp->right()), cond,
michael@0 155 comp->ifTrue(), comp->ifFalse());
michael@0 156 }
michael@0 157
michael@0 158 return true;
michael@0 159 }
michael@0 160
michael@0 161 bool
michael@0 162 CodeGeneratorMIPS::generateOutOfLineCode()
michael@0 163 {
michael@0 164 if (!CodeGeneratorShared::generateOutOfLineCode())
michael@0 165 return false;
michael@0 166
michael@0 167 if (deoptLabel_.used()) {
michael@0 168 // All non-table-based bailouts will go here.
michael@0 169 masm.bind(&deoptLabel_);
michael@0 170
michael@0 171 // Push the frame size, so the handler can recover the IonScript.
michael@0 172 // Frame size is stored in 'ra' and pushed by GenerateBailoutThunk
michael@0 173 // We have to use 'ra' because generateBailoutTable will implicitly do
michael@0 174 // the same.
michael@0 175 masm.move32(Imm32(frameSize()), ra);
michael@0 176
michael@0 177 JitCode *handler = gen->jitRuntime()->getGenericBailoutHandler();
michael@0 178
michael@0 179 masm.branch(handler);
michael@0 180 }
michael@0 181
michael@0 182 return true;
michael@0 183 }
michael@0 184
michael@0 185 bool
michael@0 186 CodeGeneratorMIPS::bailoutFrom(Label *label, LSnapshot *snapshot)
michael@0 187 {
michael@0 188 if (masm.bailed())
michael@0 189 return false;
michael@0 190 MOZ_ASSERT(label->used());
michael@0 191 MOZ_ASSERT(!label->bound());
michael@0 192
michael@0 193 CompileInfo &info = snapshot->mir()->block()->info();
michael@0 194 switch (info.executionMode()) {
michael@0 195 case ParallelExecution: {
michael@0 196 // in parallel mode, make no attempt to recover, just signal an error.
michael@0 197 OutOfLineAbortPar *ool = oolAbortPar(ParallelBailoutUnsupported,
michael@0 198 snapshot->mir()->block(),
michael@0 199 snapshot->mir()->pc());
michael@0 200 masm.retarget(label, ool->entry());
michael@0 201 return true;
michael@0 202 }
michael@0 203 case SequentialExecution:
michael@0 204 break;
michael@0 205 default:
michael@0 206 MOZ_ASSUME_UNREACHABLE("No such execution mode");
michael@0 207 }
michael@0 208
michael@0 209 if (!encode(snapshot))
michael@0 210 return false;
michael@0 211
michael@0 212 // Though the assembler doesn't track all frame pushes, at least make sure
michael@0 213 // the known value makes sense. We can't use bailout tables if the stack
michael@0 214 // isn't properly aligned to the static frame size.
michael@0 215 MOZ_ASSERT_IF(frameClass_ != FrameSizeClass::None(),
michael@0 216 frameClass_.frameSize() == masm.framePushed());
michael@0 217
michael@0 218 // We don't use table bailouts because retargeting is easier this way.
michael@0 219 OutOfLineBailout *ool = new(alloc()) OutOfLineBailout(snapshot, masm.framePushed());
michael@0 220 if (!addOutOfLineCode(ool)) {
michael@0 221 return false;
michael@0 222 }
michael@0 223
michael@0 224 masm.retarget(label, ool->entry());
michael@0 225
michael@0 226 return true;
michael@0 227 }
michael@0 228
michael@0 229 bool
michael@0 230 CodeGeneratorMIPS::bailout(LSnapshot *snapshot)
michael@0 231 {
michael@0 232 Label label;
michael@0 233 masm.jump(&label);
michael@0 234 return bailoutFrom(&label, snapshot);
michael@0 235 }
michael@0 236
michael@0 237 bool
michael@0 238 CodeGeneratorMIPS::visitOutOfLineBailout(OutOfLineBailout *ool)
michael@0 239 {
michael@0 240 // Push snapshotOffset and make sure stack is aligned.
michael@0 241 masm.subPtr(Imm32(2 * sizeof(void *)), StackPointer);
michael@0 242 masm.storePtr(ImmWord(ool->snapshot()->snapshotOffset()), Address(StackPointer, 0));
michael@0 243
michael@0 244 masm.jump(&deoptLabel_);
michael@0 245 return true;
michael@0 246 }
michael@0 247
michael@0 248 bool
michael@0 249 CodeGeneratorMIPS::visitMinMaxD(LMinMaxD *ins)
michael@0 250 {
michael@0 251 FloatRegister first = ToFloatRegister(ins->first());
michael@0 252 FloatRegister second = ToFloatRegister(ins->second());
michael@0 253 FloatRegister output = ToFloatRegister(ins->output());
michael@0 254
michael@0 255 MOZ_ASSERT(first == output);
michael@0 256
michael@0 257 Assembler::DoubleCondition cond = ins->mir()->isMax()
michael@0 258 ? Assembler::DoubleLessThanOrEqual
michael@0 259 : Assembler::DoubleGreaterThanOrEqual;
michael@0 260 Label nan, equal, returnSecond, done;
michael@0 261
michael@0 262 // First or second is NaN, result is NaN.
michael@0 263 masm.ma_bc1d(first, second, &nan, Assembler::DoubleUnordered, ShortJump);
michael@0 264 // Make sure we handle -0 and 0 right.
michael@0 265 masm.ma_bc1d(first, second, &equal, Assembler::DoubleEqual, ShortJump);
michael@0 266 masm.ma_bc1d(first, second, &returnSecond, cond, ShortJump);
michael@0 267 masm.ma_b(&done, ShortJump);
michael@0 268
michael@0 269 // Check for zero.
michael@0 270 masm.bind(&equal);
michael@0 271 masm.loadConstantDouble(0.0, ScratchFloatReg);
michael@0 272 // First wasn't 0 or -0, so just return it.
michael@0 273 masm.ma_bc1d(first, ScratchFloatReg, &done, Assembler::DoubleNotEqualOrUnordered, ShortJump);
michael@0 274
michael@0 275 // So now both operands are either -0 or 0.
michael@0 276 if (ins->mir()->isMax()) {
michael@0 277 // -0 + -0 = -0 and -0 + 0 = 0.
michael@0 278 masm.addDouble(second, first);
michael@0 279 } else {
michael@0 280 masm.negateDouble(first);
michael@0 281 masm.subDouble(second, first);
michael@0 282 masm.negateDouble(first);
michael@0 283 }
michael@0 284 masm.ma_b(&done, ShortJump);
michael@0 285
michael@0 286 masm.bind(&nan);
michael@0 287 masm.loadConstantDouble(GenericNaN(), output);
michael@0 288 masm.ma_b(&done, ShortJump);
michael@0 289
michael@0 290 masm.bind(&returnSecond);
michael@0 291 masm.moveDouble(second, output);
michael@0 292
michael@0 293 masm.bind(&done);
michael@0 294 return true;
michael@0 295 }
michael@0 296
michael@0 297 bool
michael@0 298 CodeGeneratorMIPS::visitAbsD(LAbsD *ins)
michael@0 299 {
michael@0 300 FloatRegister input = ToFloatRegister(ins->input());
michael@0 301 MOZ_ASSERT(input == ToFloatRegister(ins->output()));
michael@0 302 masm.as_absd(input, input);
michael@0 303 return true;
michael@0 304 }
michael@0 305
michael@0 306 bool
michael@0 307 CodeGeneratorMIPS::visitAbsF(LAbsF *ins)
michael@0 308 {
michael@0 309 FloatRegister input = ToFloatRegister(ins->input());
michael@0 310 MOZ_ASSERT(input == ToFloatRegister(ins->output()));
michael@0 311 masm.as_abss(input, input);
michael@0 312 return true;
michael@0 313 }
michael@0 314
michael@0 315 bool
michael@0 316 CodeGeneratorMIPS::visitSqrtD(LSqrtD *ins)
michael@0 317 {
michael@0 318 FloatRegister input = ToFloatRegister(ins->input());
michael@0 319 FloatRegister output = ToFloatRegister(ins->output());
michael@0 320 masm.as_sqrtd(output, input);
michael@0 321 return true;
michael@0 322 }
michael@0 323
michael@0 324 bool
michael@0 325 CodeGeneratorMIPS::visitSqrtF(LSqrtF *ins)
michael@0 326 {
michael@0 327 FloatRegister input = ToFloatRegister(ins->input());
michael@0 328 FloatRegister output = ToFloatRegister(ins->output());
michael@0 329 masm.as_sqrts(output, input);
michael@0 330 return true;
michael@0 331 }
michael@0 332
michael@0 333 bool
michael@0 334 CodeGeneratorMIPS::visitAddI(LAddI *ins)
michael@0 335 {
michael@0 336 const LAllocation *lhs = ins->getOperand(0);
michael@0 337 const LAllocation *rhs = ins->getOperand(1);
michael@0 338 const LDefinition *dest = ins->getDef(0);
michael@0 339
michael@0 340 MOZ_ASSERT(rhs->isConstant() || rhs->isGeneralReg());
michael@0 341
michael@0 342 // If there is no snapshot, we don't need to check for overflow
michael@0 343 if (!ins->snapshot()) {
michael@0 344 if (rhs->isConstant())
michael@0 345 masm.ma_addu(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)));
michael@0 346 else
michael@0 347 masm.as_addu(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
michael@0 348 return true;
michael@0 349 }
michael@0 350
michael@0 351 Label overflow;
michael@0 352 if (rhs->isConstant())
michael@0 353 masm.ma_addTestOverflow(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)), &overflow);
michael@0 354 else
michael@0 355 masm.ma_addTestOverflow(ToRegister(dest), ToRegister(lhs), ToRegister(rhs), &overflow);
michael@0 356
michael@0 357 if (!bailoutFrom(&overflow, ins->snapshot()))
michael@0 358 return false;
michael@0 359
michael@0 360 return true;
michael@0 361 }
michael@0 362
michael@0 363 bool
michael@0 364 CodeGeneratorMIPS::visitSubI(LSubI *ins)
michael@0 365 {
michael@0 366 const LAllocation *lhs = ins->getOperand(0);
michael@0 367 const LAllocation *rhs = ins->getOperand(1);
michael@0 368 const LDefinition *dest = ins->getDef(0);
michael@0 369
michael@0 370 MOZ_ASSERT(rhs->isConstant() || rhs->isGeneralReg());
michael@0 371
michael@0 372 // If there is no snapshot, we don't need to check for overflow
michael@0 373 if (!ins->snapshot()) {
michael@0 374 if (rhs->isConstant())
michael@0 375 masm.ma_subu(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)));
michael@0 376 else
michael@0 377 masm.as_subu(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
michael@0 378 return true;
michael@0 379 }
michael@0 380
michael@0 381 Label overflow;
michael@0 382 if (rhs->isConstant())
michael@0 383 masm.ma_subTestOverflow(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)), &overflow);
michael@0 384 else
michael@0 385 masm.ma_subTestOverflow(ToRegister(dest), ToRegister(lhs), ToRegister(rhs), &overflow);
michael@0 386
michael@0 387 if (!bailoutFrom(&overflow, ins->snapshot()))
michael@0 388 return false;
michael@0 389
michael@0 390 return true;
michael@0 391 }
michael@0 392
michael@0 393 bool
michael@0 394 CodeGeneratorMIPS::visitMulI(LMulI *ins)
michael@0 395 {
michael@0 396 const LAllocation *lhs = ins->lhs();
michael@0 397 const LAllocation *rhs = ins->rhs();
michael@0 398 Register dest = ToRegister(ins->output());
michael@0 399 MMul *mul = ins->mir();
michael@0 400
michael@0 401 MOZ_ASSERT_IF(mul->mode() == MMul::Integer, !mul->canBeNegativeZero() && !mul->canOverflow());
michael@0 402
michael@0 403 if (rhs->isConstant()) {
michael@0 404 int32_t constant = ToInt32(rhs);
michael@0 405 Register src = ToRegister(lhs);
michael@0 406
michael@0 407 // Bailout on -0.0
michael@0 408 if (mul->canBeNegativeZero() && constant <= 0) {
michael@0 409 Assembler::Condition cond = (constant == 0) ? Assembler::LessThan : Assembler::Equal;
michael@0 410 if (!bailoutCmp32(cond, src, Imm32(0), ins->snapshot()))
michael@0 411 return false;
michael@0 412 }
michael@0 413
michael@0 414 switch (constant) {
michael@0 415 case -1:
michael@0 416 if (mul->canOverflow()) {
michael@0 417 if (!bailoutCmp32(Assembler::Equal, src, Imm32(INT32_MIN), ins->snapshot()))
michael@0 418 return false;
michael@0 419 }
michael@0 420 masm.ma_negu(dest, src);
michael@0 421 break;
michael@0 422 case 0:
michael@0 423 masm.move32(Imm32(0), dest);
michael@0 424 break;
michael@0 425 case 1:
michael@0 426 masm.move32(src, dest);
michael@0 427 break;
michael@0 428 case 2:
michael@0 429 if (mul->canOverflow()) {
michael@0 430 Label mulTwoOverflow;
michael@0 431 masm.ma_addTestOverflow(dest, src, src, &mulTwoOverflow);
michael@0 432
michael@0 433 if (!bailoutFrom(&mulTwoOverflow, ins->snapshot()))
michael@0 434 return false;
michael@0 435 } else {
michael@0 436 masm.as_addu(dest, src, src);
michael@0 437 }
michael@0 438 break;
michael@0 439 default:
michael@0 440 uint32_t shift = FloorLog2(constant);
michael@0 441
michael@0 442 if (!mul->canOverflow() && (constant > 0)) {
michael@0 443 // If it cannot overflow, we can do lots of optimizations.
michael@0 444 uint32_t rest = constant - (1 << shift);
michael@0 445
michael@0 446 // See if the constant has one bit set, meaning it can be
michael@0 447 // encoded as a bitshift.
michael@0 448 if ((1 << shift) == constant) {
michael@0 449 masm.ma_sll(dest, src, Imm32(shift));
michael@0 450 return true;
michael@0 451 }
michael@0 452
michael@0 453 // If the constant cannot be encoded as (1<<C1), see if it can
michael@0 454 // be encoded as (1<<C1) | (1<<C2), which can be computed
michael@0 455 // using an add and a shift.
michael@0 456 uint32_t shift_rest = FloorLog2(rest);
michael@0 457 if (src != dest && (1u << shift_rest) == rest) {
michael@0 458 masm.ma_sll(dest, src, Imm32(shift - shift_rest));
michael@0 459 masm.add32(src, dest);
michael@0 460 if (shift_rest != 0)
michael@0 461 masm.ma_sll(dest, dest, Imm32(shift_rest));
michael@0 462 return true;
michael@0 463 }
michael@0 464 }
michael@0 465
michael@0 466 if (mul->canOverflow() && (constant > 0) && (src != dest)) {
michael@0 467 // To stay on the safe side, only optimize things that are a
michael@0 468 // power of 2.
michael@0 469
michael@0 470 if ((1 << shift) == constant) {
michael@0 471 // dest = lhs * pow(2, shift)
michael@0 472 masm.ma_sll(dest, src, Imm32(shift));
michael@0 473 // At runtime, check (lhs == dest >> shift), if this does
michael@0 474 // not hold, some bits were lost due to overflow, and the
michael@0 475 // computation should be resumed as a double.
michael@0 476 masm.ma_sra(ScratchRegister, dest, Imm32(shift));
michael@0 477 if (!bailoutCmp32(Assembler::NotEqual, src, ScratchRegister, ins->snapshot()))
michael@0 478 return false;
michael@0 479 return true;
michael@0 480 }
michael@0 481 }
michael@0 482
michael@0 483 if (mul->canOverflow()) {
michael@0 484 Label mulConstOverflow;
michael@0 485 masm.ma_mul_branch_overflow(dest, ToRegister(lhs), Imm32(ToInt32(rhs)),
michael@0 486 &mulConstOverflow);
michael@0 487
michael@0 488 if (!bailoutFrom(&mulConstOverflow, ins->snapshot()))
michael@0 489 return false;
michael@0 490 } else {
michael@0 491 masm.ma_mult(src, Imm32(ToInt32(rhs)));
michael@0 492 masm.as_mflo(dest);
michael@0 493 }
michael@0 494 break;
michael@0 495 }
michael@0 496 } else {
michael@0 497 Label multRegOverflow;
michael@0 498
michael@0 499 if (mul->canOverflow()) {
michael@0 500 masm.ma_mul_branch_overflow(dest, ToRegister(lhs), ToRegister(rhs), &multRegOverflow);
michael@0 501 if (!bailoutFrom(&multRegOverflow, ins->snapshot()))
michael@0 502 return false;
michael@0 503 } else {
michael@0 504 masm.as_mult(ToRegister(lhs), ToRegister(rhs));
michael@0 505 masm.as_mflo(dest);
michael@0 506 }
michael@0 507
michael@0 508 if (mul->canBeNegativeZero()) {
michael@0 509 Label done;
michael@0 510 masm.ma_b(dest, dest, &done, Assembler::NonZero, ShortJump);
michael@0 511
michael@0 512 // Result is -0 if lhs or rhs is negative.
michael@0 513 // In that case result must be double value so bailout
michael@0 514 Register scratch = SecondScratchReg;
michael@0 515 masm.ma_or(scratch, ToRegister(lhs), ToRegister(rhs));
michael@0 516 if (!bailoutCmp32(Assembler::Signed, scratch, scratch, ins->snapshot()))
michael@0 517 return false;
michael@0 518
michael@0 519 masm.bind(&done);
michael@0 520 }
michael@0 521 }
michael@0 522
michael@0 523 return true;
michael@0 524 }
michael@0 525
michael@0 526 bool
michael@0 527 CodeGeneratorMIPS::visitDivI(LDivI *ins)
michael@0 528 {
michael@0 529 // Extract the registers from this instruction
michael@0 530 Register lhs = ToRegister(ins->lhs());
michael@0 531 Register rhs = ToRegister(ins->rhs());
michael@0 532 Register dest = ToRegister(ins->output());
michael@0 533 Register temp = ToRegister(ins->getTemp(0));
michael@0 534 MDiv *mir = ins->mir();
michael@0 535
michael@0 536 Label done;
michael@0 537
michael@0 538 // Handle divide by zero.
michael@0 539 if (mir->canBeDivideByZero()) {
michael@0 540 if (mir->canTruncateInfinities()) {
michael@0 541 // Truncated division by zero is zero (Infinity|0 == 0)
michael@0 542 Label notzero;
michael@0 543 masm.ma_b(rhs, rhs, &notzero, Assembler::NonZero, ShortJump);
michael@0 544 masm.move32(Imm32(0), dest);
michael@0 545 masm.ma_b(&done, ShortJump);
michael@0 546 masm.bind(&notzero);
michael@0 547 } else {
michael@0 548 MOZ_ASSERT(mir->fallible());
michael@0 549 if (!bailoutCmp32(Assembler::Zero, rhs, rhs, ins->snapshot()))
michael@0 550 return false;
michael@0 551 }
michael@0 552 }
michael@0 553
michael@0 554 // Handle an integer overflow exception from -2147483648 / -1.
michael@0 555 if (mir->canBeNegativeOverflow()) {
michael@0 556 Label notMinInt;
michael@0 557 masm.move32(Imm32(INT32_MIN), temp);
michael@0 558 masm.ma_b(lhs, temp, &notMinInt, Assembler::NotEqual, ShortJump);
michael@0 559
michael@0 560 masm.move32(Imm32(-1), temp);
michael@0 561 if (mir->canTruncateOverflow()) {
michael@0 562 // (-INT32_MIN)|0 == INT32_MIN
michael@0 563 Label skip;
michael@0 564 masm.ma_b(rhs, temp, &skip, Assembler::NotEqual, ShortJump);
michael@0 565 masm.move32(Imm32(INT32_MIN), dest);
michael@0 566 masm.ma_b(&done, ShortJump);
michael@0 567 masm.bind(&skip);
michael@0 568 } else {
michael@0 569 MOZ_ASSERT(mir->fallible());
michael@0 570 if (!bailoutCmp32(Assembler::Equal, rhs, temp, ins->snapshot()))
michael@0 571 return false;
michael@0 572 }
michael@0 573 masm.bind(&notMinInt);
michael@0 574 }
michael@0 575
michael@0 576 // Handle negative 0. (0/-Y)
michael@0 577 if (!mir->canTruncateNegativeZero() && mir->canBeNegativeZero()) {
michael@0 578 Label nonzero;
michael@0 579 masm.ma_b(lhs, lhs, &nonzero, Assembler::NonZero, ShortJump);
michael@0 580 if (!bailoutCmp32(Assembler::LessThan, rhs, Imm32(0), ins->snapshot()))
michael@0 581 return false;
michael@0 582 masm.bind(&nonzero);
michael@0 583 }
michael@0 584 // Note: above safety checks could not be verified as Ion seems to be
michael@0 585 // smarter and requires double arithmetic in such cases.
michael@0 586
michael@0 587 // All regular. Lets call div.
michael@0 588 if (mir->canTruncateRemainder()) {
michael@0 589 masm.as_div(lhs, rhs);
michael@0 590 masm.as_mflo(dest);
michael@0 591 } else {
michael@0 592 MOZ_ASSERT(mir->fallible());
michael@0 593
michael@0 594 Label remainderNonZero;
michael@0 595 masm.ma_div_branch_overflow(dest, lhs, rhs, &remainderNonZero);
michael@0 596 if (!bailoutFrom(&remainderNonZero, ins->snapshot()))
michael@0 597 return false;
michael@0 598 }
michael@0 599
michael@0 600 masm.bind(&done);
michael@0 601
michael@0 602 return true;
michael@0 603 }
michael@0 604
michael@0 605 bool
michael@0 606 CodeGeneratorMIPS::visitDivPowTwoI(LDivPowTwoI *ins)
michael@0 607 {
michael@0 608 Register lhs = ToRegister(ins->numerator());
michael@0 609 Register dest = ToRegister(ins->output());
michael@0 610 Register tmp = ToRegister(ins->getTemp(0));
michael@0 611 int32_t shift = ins->shift();
michael@0 612
michael@0 613 if (shift != 0) {
michael@0 614 MDiv *mir = ins->mir();
michael@0 615 if (!mir->isTruncated()) {
michael@0 616 // If the remainder is going to be != 0, bailout since this must
michael@0 617 // be a double.
michael@0 618 masm.ma_sll(tmp, lhs, Imm32(32 - shift));
michael@0 619 if (!bailoutCmp32(Assembler::NonZero, tmp, tmp, ins->snapshot()))
michael@0 620 return false;
michael@0 621 }
michael@0 622
michael@0 623 if (!mir->canBeNegativeDividend()) {
michael@0 624 // Numerator is unsigned, so needs no adjusting. Do the shift.
michael@0 625 masm.ma_sra(dest, lhs, Imm32(shift));
michael@0 626 return true;
michael@0 627 }
michael@0 628
michael@0 629 // Adjust the value so that shifting produces a correctly rounded result
michael@0 630 // when the numerator is negative. See 10-1 "Signed Division by a Known
michael@0 631 // Power of 2" in Henry S. Warren, Jr.'s Hacker's Delight.
michael@0 632 if (shift > 1) {
michael@0 633 masm.ma_sra(tmp, lhs, Imm32(31));
michael@0 634 masm.ma_srl(tmp, tmp, Imm32(32 - shift));
michael@0 635 masm.add32(lhs, tmp);
michael@0 636 } else {
michael@0 637 masm.ma_srl(tmp, lhs, Imm32(32 - shift));
michael@0 638 masm.add32(lhs, tmp);
michael@0 639 }
michael@0 640
michael@0 641 // Do the shift.
michael@0 642 masm.ma_sra(dest, tmp, Imm32(shift));
michael@0 643 } else {
michael@0 644 masm.move32(lhs, dest);
michael@0 645 }
michael@0 646
michael@0 647 return true;
michael@0 648
michael@0 649 }
michael@0 650
michael@0 651 bool
michael@0 652 CodeGeneratorMIPS::visitModI(LModI *ins)
michael@0 653 {
michael@0 654 // Extract the registers from this instruction
michael@0 655 Register lhs = ToRegister(ins->lhs());
michael@0 656 Register rhs = ToRegister(ins->rhs());
michael@0 657 Register dest = ToRegister(ins->output());
michael@0 658 Register callTemp = ToRegister(ins->callTemp());
michael@0 659 MMod *mir = ins->mir();
michael@0 660 Label done, prevent;
michael@0 661
michael@0 662 masm.move32(lhs, callTemp);
michael@0 663
michael@0 664 // Prevent INT_MIN % -1;
michael@0 665 // The integer division will give INT_MIN, but we want -(double)INT_MIN.
michael@0 666 if (mir->canBeNegativeDividend()) {
michael@0 667 masm.ma_b(lhs, Imm32(INT_MIN), &prevent, Assembler::NotEqual, ShortJump);
michael@0 668 if (mir->isTruncated()) {
michael@0 669 // (INT_MIN % -1)|0 == 0
michael@0 670 Label skip;
michael@0 671 masm.ma_b(rhs, Imm32(-1), &skip, Assembler::NotEqual, ShortJump);
michael@0 672 masm.move32(Imm32(0), dest);
michael@0 673 masm.ma_b(&done, ShortJump);
michael@0 674 masm.bind(&skip);
michael@0 675 } else {
michael@0 676 MOZ_ASSERT(mir->fallible());
michael@0 677 if (!bailoutCmp32(Assembler::Equal, rhs, Imm32(-1), ins->snapshot()))
michael@0 678 return false;
michael@0 679 }
michael@0 680 masm.bind(&prevent);
michael@0 681 }
michael@0 682
michael@0 683 // 0/X (with X < 0) is bad because both of these values *should* be
michael@0 684 // doubles, and the result should be -0.0, which cannot be represented in
michael@0 685 // integers. X/0 is bad because it will give garbage (or abort), when it
michael@0 686 // should give either \infty, -\infty or NAN.
michael@0 687
michael@0 688 // Prevent 0 / X (with X < 0) and X / 0
michael@0 689 // testing X / Y. Compare Y with 0.
michael@0 690 // There are three cases: (Y < 0), (Y == 0) and (Y > 0)
michael@0 691 // If (Y < 0), then we compare X with 0, and bail if X == 0
michael@0 692 // If (Y == 0), then we simply want to bail.
michael@0 693 // if (Y > 0), we don't bail.
michael@0 694
michael@0 695 if (mir->canBeDivideByZero()) {
michael@0 696 if (mir->isTruncated()) {
michael@0 697 Label skip;
michael@0 698 masm.ma_b(rhs, Imm32(0), &skip, Assembler::NotEqual, ShortJump);
michael@0 699 masm.move32(Imm32(0), dest);
michael@0 700 masm.ma_b(&done, ShortJump);
michael@0 701 masm.bind(&skip);
michael@0 702 } else {
michael@0 703 MOZ_ASSERT(mir->fallible());
michael@0 704 if (!bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot()))
michael@0 705 return false;
michael@0 706 }
michael@0 707 }
michael@0 708
michael@0 709 if (mir->canBeNegativeDividend()) {
michael@0 710 Label notNegative;
michael@0 711 masm.ma_b(rhs, Imm32(0), &notNegative, Assembler::GreaterThan, ShortJump);
michael@0 712 if (mir->isTruncated()) {
michael@0 713 // NaN|0 == 0 and (0 % -X)|0 == 0
michael@0 714 Label skip;
michael@0 715 masm.ma_b(lhs, Imm32(0), &skip, Assembler::NotEqual, ShortJump);
michael@0 716 masm.move32(Imm32(0), dest);
michael@0 717 masm.ma_b(&done, ShortJump);
michael@0 718 masm.bind(&skip);
michael@0 719 } else {
michael@0 720 MOZ_ASSERT(mir->fallible());
michael@0 721 if (!bailoutCmp32(Assembler::Equal, lhs, Imm32(0), ins->snapshot()))
michael@0 722 return false;
michael@0 723 }
michael@0 724 masm.bind(&notNegative);
michael@0 725 }
michael@0 726
michael@0 727 masm.as_div(lhs, rhs);
michael@0 728 masm.as_mfhi(dest);
michael@0 729
michael@0 730 // If X%Y == 0 and X < 0, then we *actually* wanted to return -0.0
michael@0 731 if (mir->canBeNegativeDividend()) {
michael@0 732 if (mir->isTruncated()) {
michael@0 733 // -0.0|0 == 0
michael@0 734 } else {
michael@0 735 MOZ_ASSERT(mir->fallible());
michael@0 736 // See if X < 0
michael@0 737 masm.ma_b(dest, Imm32(0), &done, Assembler::NotEqual, ShortJump);
michael@0 738 if (!bailoutCmp32(Assembler::Signed, callTemp, Imm32(0), ins->snapshot()))
michael@0 739 return false;
michael@0 740 }
michael@0 741 }
michael@0 742 masm.bind(&done);
michael@0 743 return true;
michael@0 744 }
michael@0 745
michael@0 746 bool
michael@0 747 CodeGeneratorMIPS::visitModPowTwoI(LModPowTwoI *ins)
michael@0 748 {
michael@0 749 Register in = ToRegister(ins->getOperand(0));
michael@0 750 Register out = ToRegister(ins->getDef(0));
michael@0 751 MMod *mir = ins->mir();
michael@0 752 Label negative, done;
michael@0 753
michael@0 754 masm.move32(in, out);
michael@0 755 masm.ma_b(in, in, &done, Assembler::Zero, ShortJump);
michael@0 756 // Switch based on sign of the lhs.
michael@0 757 // Positive numbers are just a bitmask
michael@0 758 masm.ma_b(in, in, &negative, Assembler::Signed, ShortJump);
michael@0 759 {
michael@0 760 masm.and32(Imm32((1 << ins->shift()) - 1), out);
michael@0 761 masm.ma_b(&done, ShortJump);
michael@0 762 }
michael@0 763
michael@0 764 // Negative numbers need a negate, bitmask, negate
michael@0 765 {
michael@0 766 masm.bind(&negative);
michael@0 767 masm.neg32(out);
michael@0 768 masm.and32(Imm32((1 << ins->shift()) - 1), out);
michael@0 769 masm.neg32(out);
michael@0 770 }
michael@0 771 if (mir->canBeNegativeDividend()) {
michael@0 772 if (!mir->isTruncated()) {
michael@0 773 MOZ_ASSERT(mir->fallible());
michael@0 774 if (!bailoutCmp32(Assembler::Equal, out, zero, ins->snapshot()))
michael@0 775 return false;
michael@0 776 } else {
michael@0 777 // -0|0 == 0
michael@0 778 }
michael@0 779 }
michael@0 780 masm.bind(&done);
michael@0 781 return true;
michael@0 782 }
michael@0 783
michael@0 784 bool
michael@0 785 CodeGeneratorMIPS::visitModMaskI(LModMaskI *ins)
michael@0 786 {
michael@0 787 Register src = ToRegister(ins->getOperand(0));
michael@0 788 Register dest = ToRegister(ins->getDef(0));
michael@0 789 Register tmp = ToRegister(ins->getTemp(0));
michael@0 790 MMod *mir = ins->mir();
michael@0 791
michael@0 792 if (!mir->isTruncated() && mir->canBeNegativeDividend()) {
michael@0 793 MOZ_ASSERT(mir->fallible());
michael@0 794
michael@0 795 Label bail;
michael@0 796 masm.ma_mod_mask(src, dest, tmp, ins->shift(), &bail);
michael@0 797 if (!bailoutFrom(&bail, ins->snapshot()))
michael@0 798 return false;
michael@0 799 } else {
michael@0 800 masm.ma_mod_mask(src, dest, tmp, ins->shift(), nullptr);
michael@0 801 }
michael@0 802 return true;
michael@0 803 }
michael@0 804 bool
michael@0 805 CodeGeneratorMIPS::visitBitNotI(LBitNotI *ins)
michael@0 806 {
michael@0 807 const LAllocation *input = ins->getOperand(0);
michael@0 808 const LDefinition *dest = ins->getDef(0);
michael@0 809 MOZ_ASSERT(!input->isConstant());
michael@0 810
michael@0 811 masm.ma_not(ToRegister(dest), ToRegister(input));
michael@0 812 return true;
michael@0 813 }
michael@0 814
michael@0 815 bool
michael@0 816 CodeGeneratorMIPS::visitBitOpI(LBitOpI *ins)
michael@0 817 {
michael@0 818 const LAllocation *lhs = ins->getOperand(0);
michael@0 819 const LAllocation *rhs = ins->getOperand(1);
michael@0 820 const LDefinition *dest = ins->getDef(0);
michael@0 821 // all of these bitops should be either imm32's, or integer registers.
michael@0 822 switch (ins->bitop()) {
michael@0 823 case JSOP_BITOR:
michael@0 824 if (rhs->isConstant())
michael@0 825 masm.ma_or(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)));
michael@0 826 else
michael@0 827 masm.ma_or(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
michael@0 828 break;
michael@0 829 case JSOP_BITXOR:
michael@0 830 if (rhs->isConstant())
michael@0 831 masm.ma_xor(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)));
michael@0 832 else
michael@0 833 masm.ma_xor(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
michael@0 834 break;
michael@0 835 case JSOP_BITAND:
michael@0 836 if (rhs->isConstant())
michael@0 837 masm.ma_and(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)));
michael@0 838 else
michael@0 839 masm.ma_and(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
michael@0 840 break;
michael@0 841 default:
michael@0 842 MOZ_ASSUME_UNREACHABLE("unexpected binary opcode");
michael@0 843 }
michael@0 844
michael@0 845 return true;
michael@0 846 }
michael@0 847
michael@0 848 bool
michael@0 849 CodeGeneratorMIPS::visitShiftI(LShiftI *ins)
michael@0 850 {
michael@0 851 Register lhs = ToRegister(ins->lhs());
michael@0 852 const LAllocation *rhs = ins->rhs();
michael@0 853 Register dest = ToRegister(ins->output());
michael@0 854
michael@0 855 if (rhs->isConstant()) {
michael@0 856 int32_t shift = ToInt32(rhs) & 0x1F;
michael@0 857 switch (ins->bitop()) {
michael@0 858 case JSOP_LSH:
michael@0 859 if (shift)
michael@0 860 masm.ma_sll(dest, lhs, Imm32(shift));
michael@0 861 else
michael@0 862 masm.move32(lhs, dest);
michael@0 863 break;
michael@0 864 case JSOP_RSH:
michael@0 865 if (shift)
michael@0 866 masm.ma_sra(dest, lhs, Imm32(shift));
michael@0 867 else
michael@0 868 masm.move32(lhs, dest);
michael@0 869 break;
michael@0 870 case JSOP_URSH:
michael@0 871 if (shift) {
michael@0 872 masm.ma_srl(dest, lhs, Imm32(shift));
michael@0 873 } else {
michael@0 874 // x >>> 0 can overflow.
michael@0 875 masm.move32(lhs, dest);
michael@0 876 if (ins->mir()->toUrsh()->fallible()) {
michael@0 877 if (!bailoutCmp32(Assembler::LessThan, dest, Imm32(0), ins->snapshot()))
michael@0 878 return false;
michael@0 879 }
michael@0 880 }
michael@0 881 break;
michael@0 882 default:
michael@0 883 MOZ_ASSUME_UNREACHABLE("Unexpected shift op");
michael@0 884 }
michael@0 885 } else {
michael@0 886 // The shift amounts should be AND'ed into the 0-31 range
michael@0 887 masm.ma_and(dest, ToRegister(rhs), Imm32(0x1F));
michael@0 888
michael@0 889 switch (ins->bitop()) {
michael@0 890 case JSOP_LSH:
michael@0 891 masm.ma_sll(dest, lhs, dest);
michael@0 892 break;
michael@0 893 case JSOP_RSH:
michael@0 894 masm.ma_sra(dest, lhs, dest);
michael@0 895 break;
michael@0 896 case JSOP_URSH:
michael@0 897 masm.ma_srl(dest, lhs, dest);
michael@0 898 if (ins->mir()->toUrsh()->fallible()) {
michael@0 899 // x >>> 0 can overflow.
michael@0 900 if (!bailoutCmp32(Assembler::LessThan, dest, Imm32(0), ins->snapshot()))
michael@0 901 return false;
michael@0 902 }
michael@0 903 break;
michael@0 904 default:
michael@0 905 MOZ_ASSUME_UNREACHABLE("Unexpected shift op");
michael@0 906 }
michael@0 907 }
michael@0 908
michael@0 909 return true;
michael@0 910 }
michael@0 911
michael@0 912 bool
michael@0 913 CodeGeneratorMIPS::visitUrshD(LUrshD *ins)
michael@0 914 {
michael@0 915 Register lhs = ToRegister(ins->lhs());
michael@0 916 Register temp = ToRegister(ins->temp());
michael@0 917
michael@0 918 const LAllocation *rhs = ins->rhs();
michael@0 919 FloatRegister out = ToFloatRegister(ins->output());
michael@0 920
michael@0 921 if (rhs->isConstant()) {
michael@0 922 masm.ma_srl(temp, lhs, Imm32(ToInt32(rhs)));
michael@0 923 } else {
michael@0 924 masm.ma_srl(temp, lhs, ToRegister(rhs));
michael@0 925 }
michael@0 926
michael@0 927 masm.convertUInt32ToDouble(temp, out);
michael@0 928 return true;
michael@0 929 }
michael@0 930
michael@0 931 bool
michael@0 932 CodeGeneratorMIPS::visitPowHalfD(LPowHalfD *ins)
michael@0 933 {
michael@0 934 FloatRegister input = ToFloatRegister(ins->input());
michael@0 935 FloatRegister output = ToFloatRegister(ins->output());
michael@0 936
michael@0 937 Label done, skip;
michael@0 938
michael@0 939 // Masm.pow(-Infinity, 0.5) == Infinity.
michael@0 940 masm.loadConstantDouble(NegativeInfinity<double>(), ScratchFloatReg);
michael@0 941 masm.ma_bc1d(input, ScratchFloatReg, &skip, Assembler::DoubleNotEqualOrUnordered, ShortJump);
michael@0 942 masm.as_negd(output, ScratchFloatReg);
michael@0 943 masm.ma_b(&done, ShortJump);
michael@0 944
michael@0 945 masm.bind(&skip);
michael@0 946 // Math.pow(-0, 0.5) == 0 == Math.pow(0, 0.5).
michael@0 947 // Adding 0 converts any -0 to 0.
michael@0 948 masm.loadConstantDouble(0.0, ScratchFloatReg);
michael@0 949 masm.as_addd(output, input, ScratchFloatReg);
michael@0 950 masm.as_sqrtd(output, output);
michael@0 951
michael@0 952 masm.bind(&done);
michael@0 953 return true;
michael@0 954 }
michael@0 955
michael@0 956 MoveOperand
michael@0 957 CodeGeneratorMIPS::toMoveOperand(const LAllocation *a) const
michael@0 958 {
michael@0 959 if (a->isGeneralReg())
michael@0 960 return MoveOperand(ToRegister(a));
michael@0 961 if (a->isFloatReg()) {
michael@0 962 return MoveOperand(ToFloatRegister(a));
michael@0 963 }
michael@0 964 MOZ_ASSERT((ToStackOffset(a) & 3) == 0);
michael@0 965 int32_t offset = ToStackOffset(a);
michael@0 966
michael@0 967 // The way the stack slots work, we assume that everything from
michael@0 968 // depth == 0 downwards is writable. However, since our frame is included
michael@0 969 // in this, ensure that the frame gets skipped.
michael@0 970 if (gen->compilingAsmJS())
michael@0 971 offset -= AlignmentMidPrologue;
michael@0 972
michael@0 973 return MoveOperand(StackPointer, offset);
michael@0 974 }
michael@0 975
michael@0 976 class js::jit::OutOfLineTableSwitch : public OutOfLineCodeBase<CodeGeneratorMIPS>
michael@0 977 {
michael@0 978 MTableSwitch *mir_;
michael@0 979 CodeLabel jumpLabel_;
michael@0 980
michael@0 981 bool accept(CodeGeneratorMIPS *codegen) {
michael@0 982 return codegen->visitOutOfLineTableSwitch(this);
michael@0 983 }
michael@0 984
michael@0 985 public:
michael@0 986 OutOfLineTableSwitch(MTableSwitch *mir)
michael@0 987 : mir_(mir)
michael@0 988 {}
michael@0 989
michael@0 990 MTableSwitch *mir() const {
michael@0 991 return mir_;
michael@0 992 }
michael@0 993
michael@0 994 CodeLabel *jumpLabel() {
michael@0 995 return &jumpLabel_;
michael@0 996 }
michael@0 997 };
michael@0 998
michael@0 999 bool
michael@0 1000 CodeGeneratorMIPS::visitOutOfLineTableSwitch(OutOfLineTableSwitch *ool)
michael@0 1001 {
michael@0 1002 MTableSwitch *mir = ool->mir();
michael@0 1003
michael@0 1004 masm.align(sizeof(void*));
michael@0 1005 masm.bind(ool->jumpLabel()->src());
michael@0 1006 if (!masm.addCodeLabel(*ool->jumpLabel()))
michael@0 1007 return false;
michael@0 1008
michael@0 1009 for (size_t i = 0; i < mir->numCases(); i++) {
michael@0 1010 LBlock *caseblock = mir->getCase(i)->lir();
michael@0 1011 Label *caseheader = caseblock->label();
michael@0 1012 uint32_t caseoffset = caseheader->offset();
michael@0 1013
michael@0 1014 // The entries of the jump table need to be absolute addresses and thus
michael@0 1015 // must be patched after codegen is finished.
michael@0 1016 CodeLabel cl;
michael@0 1017 masm.ma_li(ScratchRegister, cl.dest());
michael@0 1018 masm.branch(ScratchRegister);
michael@0 1019 cl.src()->bind(caseoffset);
michael@0 1020 if (!masm.addCodeLabel(cl))
michael@0 1021 return false;
michael@0 1022 }
michael@0 1023
michael@0 1024 return true;
michael@0 1025 }
michael@0 1026
michael@0 1027 bool
michael@0 1028 CodeGeneratorMIPS::emitTableSwitchDispatch(MTableSwitch *mir, const Register &index,
michael@0 1029 const Register &address)
michael@0 1030 {
michael@0 1031 Label *defaultcase = mir->getDefault()->lir()->label();
michael@0 1032
michael@0 1033 // Lower value with low value
michael@0 1034 if (mir->low() != 0)
michael@0 1035 masm.subPtr(Imm32(mir->low()), index);
michael@0 1036
michael@0 1037 // Jump to default case if input is out of range
michael@0 1038 int32_t cases = mir->numCases();
michael@0 1039 masm.branchPtr(Assembler::AboveOrEqual, index, ImmWord(cases), defaultcase);
michael@0 1040
michael@0 1041 // To fill in the CodeLabels for the case entries, we need to first
michael@0 1042 // generate the case entries (we don't yet know their offsets in the
michael@0 1043 // instruction stream).
michael@0 1044 OutOfLineTableSwitch *ool = new(alloc()) OutOfLineTableSwitch(mir);
michael@0 1045 if (!addOutOfLineCode(ool))
michael@0 1046 return false;
michael@0 1047
michael@0 1048 // Compute the position where a pointer to the right case stands.
michael@0 1049 masm.ma_li(address, ool->jumpLabel()->dest());
michael@0 1050 masm.lshiftPtr(Imm32(4), index);
michael@0 1051 masm.addPtr(index, address);
michael@0 1052
michael@0 1053 masm.branch(address);
michael@0 1054 return true;
michael@0 1055 }
michael@0 1056
michael@0 1057 bool
michael@0 1058 CodeGeneratorMIPS::visitMathD(LMathD *math)
michael@0 1059 {
michael@0 1060 const LAllocation *src1 = math->getOperand(0);
michael@0 1061 const LAllocation *src2 = math->getOperand(1);
michael@0 1062 const LDefinition *output = math->getDef(0);
michael@0 1063
michael@0 1064 switch (math->jsop()) {
michael@0 1065 case JSOP_ADD:
michael@0 1066 masm.as_addd(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
michael@0 1067 break;
michael@0 1068 case JSOP_SUB:
michael@0 1069 masm.as_subd(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
michael@0 1070 break;
michael@0 1071 case JSOP_MUL:
michael@0 1072 masm.as_muld(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
michael@0 1073 break;
michael@0 1074 case JSOP_DIV:
michael@0 1075 masm.as_divd(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
michael@0 1076 break;
michael@0 1077 default:
michael@0 1078 MOZ_ASSUME_UNREACHABLE("unexpected opcode");
michael@0 1079 }
michael@0 1080 return true;
michael@0 1081 }
michael@0 1082
michael@0 1083 bool
michael@0 1084 CodeGeneratorMIPS::visitMathF(LMathF *math)
michael@0 1085 {
michael@0 1086 const LAllocation *src1 = math->getOperand(0);
michael@0 1087 const LAllocation *src2 = math->getOperand(1);
michael@0 1088 const LDefinition *output = math->getDef(0);
michael@0 1089
michael@0 1090 switch (math->jsop()) {
michael@0 1091 case JSOP_ADD:
michael@0 1092 masm.as_adds(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
michael@0 1093 break;
michael@0 1094 case JSOP_SUB:
michael@0 1095 masm.as_subs(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
michael@0 1096 break;
michael@0 1097 case JSOP_MUL:
michael@0 1098 masm.as_muls(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
michael@0 1099 break;
michael@0 1100 case JSOP_DIV:
michael@0 1101 masm.as_divs(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
michael@0 1102 break;
michael@0 1103 default:
michael@0 1104 MOZ_ASSUME_UNREACHABLE("unexpected opcode");
michael@0 1105 }
michael@0 1106 return true;
michael@0 1107 }
michael@0 1108
michael@0 1109 bool
michael@0 1110 CodeGeneratorMIPS::visitFloor(LFloor *lir)
michael@0 1111 {
michael@0 1112 FloatRegister input = ToFloatRegister(lir->input());
michael@0 1113 FloatRegister scratch = ScratchFloatReg;
michael@0 1114 Register output = ToRegister(lir->output());
michael@0 1115
michael@0 1116 Label skipCheck, done;
michael@0 1117
michael@0 1118 // If Nan, 0 or -0 check for bailout
michael@0 1119 masm.loadConstantDouble(0.0, scratch);
michael@0 1120 masm.ma_bc1d(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump);
michael@0 1121
michael@0 1122 // If high part is not zero, it is NaN or -0, so we bail.
michael@0 1123 masm.moveFromDoubleHi(input, SecondScratchReg);
michael@0 1124 if (!bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()))
michael@0 1125 return false;
michael@0 1126
michael@0 1127 // Input was zero, so return zero.
michael@0 1128 masm.move32(Imm32(0), output);
michael@0 1129 masm.ma_b(&done, ShortJump);
michael@0 1130
michael@0 1131 masm.bind(&skipCheck);
michael@0 1132 masm.as_floorwd(scratch, input);
michael@0 1133 masm.moveFromDoubleLo(scratch, output);
michael@0 1134
michael@0 1135 if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()))
michael@0 1136 return false;
michael@0 1137
michael@0 1138 if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()))
michael@0 1139 return false;
michael@0 1140
michael@0 1141 masm.bind(&done);
michael@0 1142
michael@0 1143 return true;
michael@0 1144 }
michael@0 1145
michael@0 1146 bool
michael@0 1147 CodeGeneratorMIPS::visitFloorF(LFloorF *lir)
michael@0 1148 {
michael@0 1149 FloatRegister input = ToFloatRegister(lir->input());
michael@0 1150 FloatRegister scratch = ScratchFloatReg;
michael@0 1151 Register output = ToRegister(lir->output());
michael@0 1152
michael@0 1153 Label skipCheck, done;
michael@0 1154
michael@0 1155 // If Nan, 0 or -0 check for bailout
michael@0 1156 masm.loadConstantFloat32(0.0, scratch);
michael@0 1157 masm.ma_bc1s(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump);
michael@0 1158
michael@0 1159 // If binary value is not zero, it is NaN or -0, so we bail.
michael@0 1160 masm.moveFromDoubleLo(input, SecondScratchReg);
michael@0 1161 if (!bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()))
michael@0 1162 return false;
michael@0 1163
michael@0 1164 // Input was zero, so return zero.
michael@0 1165 masm.move32(Imm32(0), output);
michael@0 1166 masm.ma_b(&done, ShortJump);
michael@0 1167
michael@0 1168 masm.bind(&skipCheck);
michael@0 1169 masm.as_floorws(scratch, input);
michael@0 1170 masm.moveFromDoubleLo(scratch, output);
michael@0 1171
michael@0 1172 if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()))
michael@0 1173 return false;
michael@0 1174
michael@0 1175 if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()))
michael@0 1176 return false;
michael@0 1177
michael@0 1178 masm.bind(&done);
michael@0 1179
michael@0 1180 return true;
michael@0 1181 }
michael@0 1182
michael@0 1183 bool
michael@0 1184 CodeGeneratorMIPS::visitRound(LRound *lir)
michael@0 1185 {
michael@0 1186 FloatRegister input = ToFloatRegister(lir->input());
michael@0 1187 FloatRegister temp = ToFloatRegister(lir->temp());
michael@0 1188 FloatRegister scratch = ScratchFloatReg;
michael@0 1189 Register output = ToRegister(lir->output());
michael@0 1190
michael@0 1191 Label bail, negative, end, skipCheck;
michael@0 1192
michael@0 1193 // Load 0.5 in the temp register.
michael@0 1194 masm.loadConstantDouble(0.5, temp);
michael@0 1195
michael@0 1196 // Branch to a slow path for negative inputs. Doesn't catch NaN or -0.
michael@0 1197 masm.loadConstantDouble(0.0, scratch);
michael@0 1198 masm.ma_bc1d(input, scratch, &negative, Assembler::DoubleLessThan, ShortJump);
michael@0 1199
michael@0 1200 // If Nan, 0 or -0 check for bailout
michael@0 1201 masm.ma_bc1d(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump);
michael@0 1202
michael@0 1203 // If high part is not zero, it is NaN or -0, so we bail.
michael@0 1204 masm.moveFromDoubleHi(input, SecondScratchReg);
michael@0 1205 if (!bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()))
michael@0 1206 return false;
michael@0 1207
michael@0 1208 // Input was zero, so return zero.
michael@0 1209 masm.move32(Imm32(0), output);
michael@0 1210 masm.ma_b(&end, ShortJump);
michael@0 1211
michael@0 1212 masm.bind(&skipCheck);
michael@0 1213 masm.loadConstantDouble(0.5, scratch);
michael@0 1214 masm.addDouble(input, scratch);
michael@0 1215 masm.as_floorwd(scratch, scratch);
michael@0 1216
michael@0 1217 masm.moveFromDoubleLo(scratch, output);
michael@0 1218
michael@0 1219 if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()))
michael@0 1220 return false;
michael@0 1221
michael@0 1222 if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()))
michael@0 1223 return false;
michael@0 1224
michael@0 1225 masm.jump(&end);
michael@0 1226
michael@0 1227 // Input is negative, but isn't -0.
michael@0 1228 masm.bind(&negative);
michael@0 1229 masm.addDouble(input, temp);
michael@0 1230
michael@0 1231 // If input + 0.5 >= 0, input is a negative number >= -0.5 and the
michael@0 1232 // result is -0.
michael@0 1233 masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, temp, scratch, &bail);
michael@0 1234 if (!bailoutFrom(&bail, lir->snapshot()))
michael@0 1235 return false;
michael@0 1236
michael@0 1237 // Truncate and round toward zero.
michael@0 1238 // This is off-by-one for everything but integer-valued inputs.
michael@0 1239 masm.as_floorwd(scratch, temp);
michael@0 1240 masm.moveFromDoubleLo(scratch, output);
michael@0 1241
michael@0 1242 if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()))
michael@0 1243 return false;
michael@0 1244
michael@0 1245 masm.bind(&end);
michael@0 1246 return true;
michael@0 1247 }
michael@0 1248
michael@0 1249 bool
michael@0 1250 CodeGeneratorMIPS::visitRoundF(LRoundF *lir)
michael@0 1251 {
michael@0 1252 FloatRegister input = ToFloatRegister(lir->input());
michael@0 1253 FloatRegister temp = ToFloatRegister(lir->temp());
michael@0 1254 FloatRegister scratch = ScratchFloatReg;
michael@0 1255 Register output = ToRegister(lir->output());
michael@0 1256
michael@0 1257 Label bail, negative, end, skipCheck;
michael@0 1258
michael@0 1259 // Load 0.5 in the temp register.
michael@0 1260 masm.loadConstantFloat32(0.5, temp);
michael@0 1261
michael@0 1262 // Branch to a slow path for negative inputs. Doesn't catch NaN or -0.
michael@0 1263 masm.loadConstantFloat32(0.0, scratch);
michael@0 1264 masm.ma_bc1s(input, scratch, &negative, Assembler::DoubleLessThan, ShortJump);
michael@0 1265
michael@0 1266 // If Nan, 0 or -0 check for bailout
michael@0 1267 masm.ma_bc1s(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump);
michael@0 1268
michael@0 1269 // If binary value is not zero, it is NaN or -0, so we bail.
michael@0 1270 masm.moveFromFloat32(input, SecondScratchReg);
michael@0 1271 if (!bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot()))
michael@0 1272 return false;
michael@0 1273
michael@0 1274 // Input was zero, so return zero.
michael@0 1275 masm.move32(Imm32(0), output);
michael@0 1276 masm.ma_b(&end, ShortJump);
michael@0 1277
michael@0 1278 masm.bind(&skipCheck);
michael@0 1279 masm.loadConstantFloat32(0.5, scratch);
michael@0 1280 masm.as_adds(scratch, input, scratch);
michael@0 1281 masm.as_floorws(scratch, scratch);
michael@0 1282
michael@0 1283 masm.moveFromFloat32(scratch, output);
michael@0 1284
michael@0 1285 if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()))
michael@0 1286 return false;
michael@0 1287
michael@0 1288 if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot()))
michael@0 1289 return false;
michael@0 1290
michael@0 1291 masm.jump(&end);
michael@0 1292
michael@0 1293 // Input is negative, but isn't -0.
michael@0 1294 masm.bind(&negative);
michael@0 1295 masm.as_adds(temp, input, temp);
michael@0 1296
michael@0 1297 // If input + 0.5 >= 0, input is a negative number >= -0.5 and the
michael@0 1298 // result is -0.
michael@0 1299 masm.branchFloat(Assembler::DoubleGreaterThanOrEqual, temp, scratch, &bail);
michael@0 1300 if (!bailoutFrom(&bail, lir->snapshot()))
michael@0 1301 return false;
michael@0 1302
michael@0 1303 // Truncate and round toward zero.
michael@0 1304 // This is off-by-one for everything but integer-valued inputs.
michael@0 1305 masm.as_floorws(scratch, temp);
michael@0 1306 masm.moveFromFloat32(scratch, output);
michael@0 1307
michael@0 1308 if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot()))
michael@0 1309 return false;
michael@0 1310
michael@0 1311 masm.bind(&end);
michael@0 1312 return true;
michael@0 1313 }
michael@0 1314
michael@0 1315 bool
michael@0 1316 CodeGeneratorMIPS::visitTruncateDToInt32(LTruncateDToInt32 *ins)
michael@0 1317 {
michael@0 1318 return emitTruncateDouble(ToFloatRegister(ins->input()), ToRegister(ins->output()));
michael@0 1319 }
michael@0 1320
michael@0 1321 bool
michael@0 1322 CodeGeneratorMIPS::visitTruncateFToInt32(LTruncateFToInt32 *ins)
michael@0 1323 {
michael@0 1324 return emitTruncateFloat32(ToFloatRegister(ins->input()), ToRegister(ins->output()));
michael@0 1325 }
michael@0 1326
michael@0 1327 static const uint32_t FrameSizes[] = { 128, 256, 512, 1024 };
michael@0 1328
michael@0 1329 FrameSizeClass
michael@0 1330 FrameSizeClass::FromDepth(uint32_t frameDepth)
michael@0 1331 {
michael@0 1332 for (uint32_t i = 0; i < JS_ARRAY_LENGTH(FrameSizes); i++) {
michael@0 1333 if (frameDepth < FrameSizes[i])
michael@0 1334 return FrameSizeClass(i);
michael@0 1335 }
michael@0 1336
michael@0 1337 return FrameSizeClass::None();
michael@0 1338 }
michael@0 1339
michael@0 1340 FrameSizeClass
michael@0 1341 FrameSizeClass::ClassLimit()
michael@0 1342 {
michael@0 1343 return FrameSizeClass(JS_ARRAY_LENGTH(FrameSizes));
michael@0 1344 }
michael@0 1345
michael@0 1346 uint32_t
michael@0 1347 FrameSizeClass::frameSize() const
michael@0 1348 {
michael@0 1349 MOZ_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID);
michael@0 1350 MOZ_ASSERT(class_ < JS_ARRAY_LENGTH(FrameSizes));
michael@0 1351
michael@0 1352 return FrameSizes[class_];
michael@0 1353 }
michael@0 1354
michael@0 1355 ValueOperand
michael@0 1356 CodeGeneratorMIPS::ToValue(LInstruction *ins, size_t pos)
michael@0 1357 {
michael@0 1358 Register typeReg = ToRegister(ins->getOperand(pos + TYPE_INDEX));
michael@0 1359 Register payloadReg = ToRegister(ins->getOperand(pos + PAYLOAD_INDEX));
michael@0 1360 return ValueOperand(typeReg, payloadReg);
michael@0 1361 }
michael@0 1362
michael@0 1363 ValueOperand
michael@0 1364 CodeGeneratorMIPS::ToOutValue(LInstruction *ins)
michael@0 1365 {
michael@0 1366 Register typeReg = ToRegister(ins->getDef(TYPE_INDEX));
michael@0 1367 Register payloadReg = ToRegister(ins->getDef(PAYLOAD_INDEX));
michael@0 1368 return ValueOperand(typeReg, payloadReg);
michael@0 1369 }
michael@0 1370
michael@0 1371 ValueOperand
michael@0 1372 CodeGeneratorMIPS::ToTempValue(LInstruction *ins, size_t pos)
michael@0 1373 {
michael@0 1374 Register typeReg = ToRegister(ins->getTemp(pos + TYPE_INDEX));
michael@0 1375 Register payloadReg = ToRegister(ins->getTemp(pos + PAYLOAD_INDEX));
michael@0 1376 return ValueOperand(typeReg, payloadReg);
michael@0 1377 }
michael@0 1378
michael@0 1379 bool
michael@0 1380 CodeGeneratorMIPS::visitValue(LValue *value)
michael@0 1381 {
michael@0 1382 const ValueOperand out = ToOutValue(value);
michael@0 1383
michael@0 1384 masm.moveValue(value->value(), out);
michael@0 1385 return true;
michael@0 1386 }
michael@0 1387
michael@0 1388 bool
michael@0 1389 CodeGeneratorMIPS::visitBox(LBox *box)
michael@0 1390 {
michael@0 1391 const LDefinition *type = box->getDef(TYPE_INDEX);
michael@0 1392
michael@0 1393 MOZ_ASSERT(!box->getOperand(0)->isConstant());
michael@0 1394
michael@0 1395 // For NUNBOX32, the input operand and the output payload have the same
michael@0 1396 // virtual register. All that needs to be written is the type tag for
michael@0 1397 // the type definition.
michael@0 1398 masm.move32(Imm32(MIRTypeToTag(box->type())), ToRegister(type));
michael@0 1399 return true;
michael@0 1400 }
michael@0 1401
michael@0 1402 bool
michael@0 1403 CodeGeneratorMIPS::visitBoxFloatingPoint(LBoxFloatingPoint *box)
michael@0 1404 {
michael@0 1405 const LDefinition *payload = box->getDef(PAYLOAD_INDEX);
michael@0 1406 const LDefinition *type = box->getDef(TYPE_INDEX);
michael@0 1407 const LAllocation *in = box->getOperand(0);
michael@0 1408
michael@0 1409 FloatRegister reg = ToFloatRegister(in);
michael@0 1410 if (box->type() == MIRType_Float32) {
michael@0 1411 masm.convertFloat32ToDouble(reg, ScratchFloatReg);
michael@0 1412 reg = ScratchFloatReg;
michael@0 1413 }
michael@0 1414 masm.ma_mv(reg, ValueOperand(ToRegister(type), ToRegister(payload)));
michael@0 1415 return true;
michael@0 1416 }
michael@0 1417
michael@0 1418 bool
michael@0 1419 CodeGeneratorMIPS::visitUnbox(LUnbox *unbox)
michael@0 1420 {
michael@0 1421 // Note that for unbox, the type and payload indexes are switched on the
michael@0 1422 // inputs.
michael@0 1423 MUnbox *mir = unbox->mir();
michael@0 1424 Register type = ToRegister(unbox->type());
michael@0 1425
michael@0 1426 if (mir->fallible()) {
michael@0 1427 if (!bailoutCmp32(Assembler::NotEqual, type, Imm32(MIRTypeToTag(mir->type())),
michael@0 1428 unbox->snapshot()))
michael@0 1429 return false;
michael@0 1430 }
michael@0 1431 return true;
michael@0 1432 }
michael@0 1433
michael@0 1434 bool
michael@0 1435 CodeGeneratorMIPS::visitDouble(LDouble *ins)
michael@0 1436 {
michael@0 1437 const LDefinition *out = ins->getDef(0);
michael@0 1438
michael@0 1439 masm.loadConstantDouble(ins->getDouble(), ToFloatRegister(out));
michael@0 1440 return true;
michael@0 1441 }
michael@0 1442
michael@0 1443 bool
michael@0 1444 CodeGeneratorMIPS::visitFloat32(LFloat32 *ins)
michael@0 1445 {
michael@0 1446 const LDefinition *out = ins->getDef(0);
michael@0 1447 masm.loadConstantFloat32(ins->getFloat(), ToFloatRegister(out));
michael@0 1448 return true;
michael@0 1449 }
michael@0 1450
michael@0 1451 Register
michael@0 1452 CodeGeneratorMIPS::splitTagForTest(const ValueOperand &value)
michael@0 1453 {
michael@0 1454 return value.typeReg();
michael@0 1455 }
michael@0 1456
michael@0 1457 bool
michael@0 1458 CodeGeneratorMIPS::visitTestDAndBranch(LTestDAndBranch *test)
michael@0 1459 {
michael@0 1460 FloatRegister input = ToFloatRegister(test->input());
michael@0 1461
michael@0 1462 MBasicBlock *ifTrue = test->ifTrue();
michael@0 1463 MBasicBlock *ifFalse = test->ifFalse();
michael@0 1464
michael@0 1465 masm.loadConstantDouble(0.0, ScratchFloatReg);
michael@0 1466 // If 0, or NaN, the result is false.
michael@0 1467
michael@0 1468 if (isNextBlock(ifFalse->lir())) {
michael@0 1469 branchToBlock(Assembler::DoubleFloat, input, ScratchFloatReg, ifTrue,
michael@0 1470 Assembler::DoubleNotEqual);
michael@0 1471 } else {
michael@0 1472 branchToBlock(Assembler::DoubleFloat, input, ScratchFloatReg, ifFalse,
michael@0 1473 Assembler::DoubleEqualOrUnordered);
michael@0 1474 jumpToBlock(ifTrue);
michael@0 1475 }
michael@0 1476
michael@0 1477 return true;
michael@0 1478 }
michael@0 1479
michael@0 1480 bool
michael@0 1481 CodeGeneratorMIPS::visitTestFAndBranch(LTestFAndBranch *test)
michael@0 1482 {
michael@0 1483 FloatRegister input = ToFloatRegister(test->input());
michael@0 1484
michael@0 1485 MBasicBlock *ifTrue = test->ifTrue();
michael@0 1486 MBasicBlock *ifFalse = test->ifFalse();
michael@0 1487
michael@0 1488 masm.loadConstantFloat32(0.0, ScratchFloatReg);
michael@0 1489 // If 0, or NaN, the result is false.
michael@0 1490
michael@0 1491 if (isNextBlock(ifFalse->lir())) {
michael@0 1492 branchToBlock(Assembler::SingleFloat, input, ScratchFloatReg, ifTrue,
michael@0 1493 Assembler::DoubleNotEqual);
michael@0 1494 } else {
michael@0 1495 branchToBlock(Assembler::SingleFloat, input, ScratchFloatReg, ifFalse,
michael@0 1496 Assembler::DoubleEqualOrUnordered);
michael@0 1497 jumpToBlock(ifTrue);
michael@0 1498 }
michael@0 1499
michael@0 1500 return true;
michael@0 1501 }
michael@0 1502
michael@0 1503 bool
michael@0 1504 CodeGeneratorMIPS::visitCompareD(LCompareD *comp)
michael@0 1505 {
michael@0 1506 FloatRegister lhs = ToFloatRegister(comp->left());
michael@0 1507 FloatRegister rhs = ToFloatRegister(comp->right());
michael@0 1508 Register dest = ToRegister(comp->output());
michael@0 1509
michael@0 1510 Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop());
michael@0 1511 masm.ma_cmp_set_double(dest, lhs, rhs, cond);
michael@0 1512 return true;
michael@0 1513 }
michael@0 1514
michael@0 1515 bool
michael@0 1516 CodeGeneratorMIPS::visitCompareF(LCompareF *comp)
michael@0 1517 {
michael@0 1518 FloatRegister lhs = ToFloatRegister(comp->left());
michael@0 1519 FloatRegister rhs = ToFloatRegister(comp->right());
michael@0 1520 Register dest = ToRegister(comp->output());
michael@0 1521
michael@0 1522 Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop());
michael@0 1523 masm.ma_cmp_set_float32(dest, lhs, rhs, cond);
michael@0 1524 return true;
michael@0 1525 }
michael@0 1526
michael@0 1527
michael@0 1528 bool
michael@0 1529 CodeGeneratorMIPS::visitCompareDAndBranch(LCompareDAndBranch *comp)
michael@0 1530 {
michael@0 1531 FloatRegister lhs = ToFloatRegister(comp->left());
michael@0 1532 FloatRegister rhs = ToFloatRegister(comp->right());
michael@0 1533
michael@0 1534 Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->cmpMir()->jsop());
michael@0 1535 MBasicBlock *ifTrue = comp->ifTrue();
michael@0 1536 MBasicBlock *ifFalse = comp->ifFalse();
michael@0 1537
michael@0 1538 if (isNextBlock(ifFalse->lir())) {
michael@0 1539 branchToBlock(Assembler::DoubleFloat, lhs, rhs, ifTrue, cond);
michael@0 1540 } else {
michael@0 1541 branchToBlock(Assembler::DoubleFloat, lhs, rhs, ifFalse,
michael@0 1542 Assembler::InvertCondition(cond));
michael@0 1543 jumpToBlock(ifTrue);
michael@0 1544 }
michael@0 1545
michael@0 1546 return true;
michael@0 1547 }
michael@0 1548
michael@0 1549 bool
michael@0 1550 CodeGeneratorMIPS::visitCompareFAndBranch(LCompareFAndBranch *comp)
michael@0 1551 {
michael@0 1552 FloatRegister lhs = ToFloatRegister(comp->left());
michael@0 1553 FloatRegister rhs = ToFloatRegister(comp->right());
michael@0 1554
michael@0 1555 Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->cmpMir()->jsop());
michael@0 1556 MBasicBlock *ifTrue = comp->ifTrue();
michael@0 1557 MBasicBlock *ifFalse = comp->ifFalse();
michael@0 1558
michael@0 1559 if (isNextBlock(ifFalse->lir())) {
michael@0 1560 branchToBlock(Assembler::SingleFloat, lhs, rhs, ifTrue, cond);
michael@0 1561 } else {
michael@0 1562 branchToBlock(Assembler::SingleFloat, lhs, rhs, ifFalse,
michael@0 1563 Assembler::InvertCondition(cond));
michael@0 1564 jumpToBlock(ifTrue);
michael@0 1565 }
michael@0 1566
michael@0 1567 return true;
michael@0 1568 }
michael@0 1569
michael@0 1570 bool
michael@0 1571 CodeGeneratorMIPS::visitCompareB(LCompareB *lir)
michael@0 1572 {
michael@0 1573 MCompare *mir = lir->mir();
michael@0 1574
michael@0 1575 const ValueOperand lhs = ToValue(lir, LCompareB::Lhs);
michael@0 1576 const LAllocation *rhs = lir->rhs();
michael@0 1577 const Register output = ToRegister(lir->output());
michael@0 1578
michael@0 1579 MOZ_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE);
michael@0 1580 Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop());
michael@0 1581
michael@0 1582 Label notBoolean, done;
michael@0 1583 masm.branchTestBoolean(Assembler::NotEqual, lhs, &notBoolean);
michael@0 1584 {
michael@0 1585 if (rhs->isConstant())
michael@0 1586 masm.cmp32Set(cond, lhs.payloadReg(), Imm32(rhs->toConstant()->toBoolean()), output);
michael@0 1587 else
michael@0 1588 masm.cmp32Set(cond, lhs.payloadReg(), ToRegister(rhs), output);
michael@0 1589 masm.jump(&done);
michael@0 1590 }
michael@0 1591
michael@0 1592 masm.bind(&notBoolean);
michael@0 1593 {
michael@0 1594 masm.move32(Imm32(mir->jsop() == JSOP_STRICTNE), output);
michael@0 1595 }
michael@0 1596
michael@0 1597 masm.bind(&done);
michael@0 1598 return true;
michael@0 1599 }
michael@0 1600
michael@0 1601 bool
michael@0 1602 CodeGeneratorMIPS::visitCompareBAndBranch(LCompareBAndBranch *lir)
michael@0 1603 {
michael@0 1604 MCompare *mir = lir->cmpMir();
michael@0 1605 const ValueOperand lhs = ToValue(lir, LCompareBAndBranch::Lhs);
michael@0 1606 const LAllocation *rhs = lir->rhs();
michael@0 1607
michael@0 1608 MOZ_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE);
michael@0 1609
michael@0 1610 MBasicBlock *mirNotBoolean = (mir->jsop() == JSOP_STRICTEQ) ? lir->ifFalse() : lir->ifTrue();
michael@0 1611 branchToBlock(lhs.typeReg(), ImmType(JSVAL_TYPE_BOOLEAN), mirNotBoolean, Assembler::NotEqual);
michael@0 1612
michael@0 1613 Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop());
michael@0 1614 if (rhs->isConstant())
michael@0 1615 emitBranch(lhs.payloadReg(), Imm32(rhs->toConstant()->toBoolean()), cond, lir->ifTrue(),
michael@0 1616 lir->ifFalse());
michael@0 1617 else
michael@0 1618 emitBranch(lhs.payloadReg(), ToRegister(rhs), cond, lir->ifTrue(), lir->ifFalse());
michael@0 1619
michael@0 1620 return true;
michael@0 1621 }
michael@0 1622
michael@0 1623 bool
michael@0 1624 CodeGeneratorMIPS::visitCompareV(LCompareV *lir)
michael@0 1625 {
michael@0 1626 MCompare *mir = lir->mir();
michael@0 1627 Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop());
michael@0 1628 const ValueOperand lhs = ToValue(lir, LCompareV::LhsInput);
michael@0 1629 const ValueOperand rhs = ToValue(lir, LCompareV::RhsInput);
michael@0 1630 const Register output = ToRegister(lir->output());
michael@0 1631
michael@0 1632 MOZ_ASSERT(IsEqualityOp(mir->jsop()));
michael@0 1633
michael@0 1634 Label notEqual, done;
michael@0 1635 masm.ma_b(lhs.typeReg(), rhs.typeReg(), &notEqual, Assembler::NotEqual, ShortJump);
michael@0 1636 {
michael@0 1637 masm.cmp32Set(cond, lhs.payloadReg(), rhs.payloadReg(), output);
michael@0 1638 masm.ma_b(&done, ShortJump);
michael@0 1639 }
michael@0 1640 masm.bind(&notEqual);
michael@0 1641 {
michael@0 1642 masm.move32(Imm32(cond == Assembler::NotEqual), output);
michael@0 1643 }
michael@0 1644
michael@0 1645 masm.bind(&done);
michael@0 1646 return true;
michael@0 1647 }
michael@0 1648
michael@0 1649 bool
michael@0 1650 CodeGeneratorMIPS::visitCompareVAndBranch(LCompareVAndBranch *lir)
michael@0 1651 {
michael@0 1652 MCompare *mir = lir->cmpMir();
michael@0 1653 Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop());
michael@0 1654 const ValueOperand lhs = ToValue(lir, LCompareVAndBranch::LhsInput);
michael@0 1655 const ValueOperand rhs = ToValue(lir, LCompareVAndBranch::RhsInput);
michael@0 1656
michael@0 1657 MOZ_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ ||
michael@0 1658 mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE);
michael@0 1659
michael@0 1660 MBasicBlock *notEqual = (cond == Assembler::Equal) ? lir->ifFalse() : lir->ifTrue();
michael@0 1661
michael@0 1662 branchToBlock(lhs.typeReg(), rhs.typeReg(), notEqual, Assembler::NotEqual);
michael@0 1663 emitBranch(lhs.payloadReg(), rhs.payloadReg(), cond, lir->ifTrue(), lir->ifFalse());
michael@0 1664
michael@0 1665 return true;
michael@0 1666 }
michael@0 1667
michael@0 1668 bool
michael@0 1669 CodeGeneratorMIPS::visitBitAndAndBranch(LBitAndAndBranch *lir)
michael@0 1670 {
michael@0 1671 if (lir->right()->isConstant())
michael@0 1672 masm.ma_and(ScratchRegister, ToRegister(lir->left()), Imm32(ToInt32(lir->right())));
michael@0 1673 else
michael@0 1674 masm.ma_and(ScratchRegister, ToRegister(lir->left()), ToRegister(lir->right()));
michael@0 1675 emitBranch(ScratchRegister, ScratchRegister, Assembler::NonZero, lir->ifTrue(),
michael@0 1676 lir->ifFalse());
michael@0 1677 return true;
michael@0 1678 }
michael@0 1679
michael@0 1680 bool
michael@0 1681 CodeGeneratorMIPS::visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble *lir)
michael@0 1682 {
michael@0 1683 masm.convertUInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output()));
michael@0 1684 return true;
michael@0 1685 }
michael@0 1686
michael@0 1687 bool
michael@0 1688 CodeGeneratorMIPS::visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32 *lir)
michael@0 1689 {
michael@0 1690 masm.convertUInt32ToFloat32(ToRegister(lir->input()), ToFloatRegister(lir->output()));
michael@0 1691 return true;
michael@0 1692 }
michael@0 1693
michael@0 1694 bool
michael@0 1695 CodeGeneratorMIPS::visitNotI(LNotI *ins)
michael@0 1696 {
michael@0 1697 masm.cmp32Set(Assembler::Equal, ToRegister(ins->input()), Imm32(0),
michael@0 1698 ToRegister(ins->output()));
michael@0 1699 return true;
michael@0 1700 }
michael@0 1701
michael@0 1702 bool
michael@0 1703 CodeGeneratorMIPS::visitNotD(LNotD *ins)
michael@0 1704 {
michael@0 1705 // Since this operation is not, we want to set a bit if
michael@0 1706 // the double is falsey, which means 0.0, -0.0 or NaN.
michael@0 1707 FloatRegister in = ToFloatRegister(ins->input());
michael@0 1708 Register dest = ToRegister(ins->output());
michael@0 1709
michael@0 1710 Label falsey, done;
michael@0 1711 masm.loadConstantDouble(0.0, ScratchFloatReg);
michael@0 1712 masm.ma_bc1d(in, ScratchFloatReg, &falsey, Assembler::DoubleEqualOrUnordered, ShortJump);
michael@0 1713
michael@0 1714 masm.move32(Imm32(0), dest);
michael@0 1715 masm.ma_b(&done, ShortJump);
michael@0 1716
michael@0 1717 masm.bind(&falsey);
michael@0 1718 masm.move32(Imm32(1), dest);
michael@0 1719
michael@0 1720 masm.bind(&done);
michael@0 1721 return true;
michael@0 1722 }
michael@0 1723
michael@0 1724 bool
michael@0 1725 CodeGeneratorMIPS::visitNotF(LNotF *ins)
michael@0 1726 {
michael@0 1727 // Since this operation is not, we want to set a bit if
michael@0 1728 // the float32 is falsey, which means 0.0, -0.0 or NaN.
michael@0 1729 FloatRegister in = ToFloatRegister(ins->input());
michael@0 1730 Register dest = ToRegister(ins->output());
michael@0 1731
michael@0 1732 Label falsey, done;
michael@0 1733 masm.loadConstantFloat32(0.0, ScratchFloatReg);
michael@0 1734 masm.ma_bc1s(in, ScratchFloatReg, &falsey, Assembler::DoubleEqualOrUnordered, ShortJump);
michael@0 1735
michael@0 1736 masm.move32(Imm32(0), dest);
michael@0 1737 masm.ma_b(&done, ShortJump);
michael@0 1738
michael@0 1739 masm.bind(&falsey);
michael@0 1740 masm.move32(Imm32(1), dest);
michael@0 1741
michael@0 1742 masm.bind(&done);
michael@0 1743 return true;
michael@0 1744 }
michael@0 1745
michael@0 1746 bool
michael@0 1747 CodeGeneratorMIPS::visitLoadSlotV(LLoadSlotV *load)
michael@0 1748 {
michael@0 1749 const ValueOperand out = ToOutValue(load);
michael@0 1750 Register base = ToRegister(load->input());
michael@0 1751 int32_t offset = load->mir()->slot() * sizeof(js::Value);
michael@0 1752
michael@0 1753 masm.loadValue(Address(base, offset), out);
michael@0 1754 return true;
michael@0 1755 }
michael@0 1756
michael@0 1757 bool
michael@0 1758 CodeGeneratorMIPS::visitLoadSlotT(LLoadSlotT *load)
michael@0 1759 {
michael@0 1760 Register base = ToRegister(load->input());
michael@0 1761 int32_t offset = load->mir()->slot() * sizeof(js::Value);
michael@0 1762
michael@0 1763 if (load->mir()->type() == MIRType_Double)
michael@0 1764 masm.loadInt32OrDouble(Address(base, offset), ToFloatRegister(load->output()));
michael@0 1765 else
michael@0 1766 masm.load32(Address(base, offset + NUNBOX32_PAYLOAD_OFFSET), ToRegister(load->output()));
michael@0 1767 return true;
michael@0 1768 }
michael@0 1769
michael@0 1770 bool
michael@0 1771 CodeGeneratorMIPS::visitStoreSlotT(LStoreSlotT *store)
michael@0 1772 {
michael@0 1773 Register base = ToRegister(store->slots());
michael@0 1774 int32_t offset = store->mir()->slot() * sizeof(js::Value);
michael@0 1775
michael@0 1776 const LAllocation *value = store->value();
michael@0 1777 MIRType valueType = store->mir()->value()->type();
michael@0 1778
michael@0 1779 if (store->mir()->needsBarrier())
michael@0 1780 emitPreBarrier(Address(base, offset), store->mir()->slotType());
michael@0 1781
michael@0 1782 if (valueType == MIRType_Double) {
michael@0 1783 masm.storeDouble(ToFloatRegister(value), Address(base, offset));
michael@0 1784 return true;
michael@0 1785 }
michael@0 1786
michael@0 1787 // Store the type tag if needed.
michael@0 1788 if (valueType != store->mir()->slotType())
michael@0 1789 masm.storeTypeTag(ImmType(ValueTypeFromMIRType(valueType)), Address(base, offset));
michael@0 1790
michael@0 1791 // Store the payload.
michael@0 1792 if (value->isConstant())
michael@0 1793 masm.storePayload(*value->toConstant(), Address(base, offset));
michael@0 1794 else
michael@0 1795 masm.storePayload(ToRegister(value), Address(base, offset));
michael@0 1796
michael@0 1797 return true;
michael@0 1798 }
michael@0 1799
michael@0 1800 bool
michael@0 1801 CodeGeneratorMIPS::visitLoadElementT(LLoadElementT *load)
michael@0 1802 {
michael@0 1803 Register base = ToRegister(load->elements());
michael@0 1804 if (load->mir()->type() == MIRType_Double) {
michael@0 1805 FloatRegister fpreg = ToFloatRegister(load->output());
michael@0 1806 if (load->index()->isConstant()) {
michael@0 1807 Address source(base, ToInt32(load->index()) * sizeof(Value));
michael@0 1808 if (load->mir()->loadDoubles())
michael@0 1809 masm.loadDouble(source, fpreg);
michael@0 1810 else
michael@0 1811 masm.loadInt32OrDouble(source, fpreg);
michael@0 1812 } else {
michael@0 1813 Register index = ToRegister(load->index());
michael@0 1814 if (load->mir()->loadDoubles())
michael@0 1815 masm.loadDouble(BaseIndex(base, index, TimesEight), fpreg);
michael@0 1816 else
michael@0 1817 masm.loadInt32OrDouble(base, index, fpreg);
michael@0 1818 }
michael@0 1819 } else {
michael@0 1820 if (load->index()->isConstant()) {
michael@0 1821 Address source(base, ToInt32(load->index()) * sizeof(Value));
michael@0 1822 masm.load32(source, ToRegister(load->output()));
michael@0 1823 } else {
michael@0 1824 BaseIndex source(base, ToRegister(load->index()), TimesEight);
michael@0 1825 masm.load32(source, ToRegister(load->output()));
michael@0 1826 }
michael@0 1827 }
michael@0 1828 MOZ_ASSERT(!load->mir()->needsHoleCheck());
michael@0 1829 return true;
michael@0 1830 }
michael@0 1831
michael@0 1832 void
michael@0 1833 CodeGeneratorMIPS::storeElementTyped(const LAllocation *value, MIRType valueType,
michael@0 1834 MIRType elementType, const Register &elements,
michael@0 1835 const LAllocation *index)
michael@0 1836 {
michael@0 1837 if (index->isConstant()) {
michael@0 1838 Address dest = Address(elements, ToInt32(index) * sizeof(Value));
michael@0 1839 if (valueType == MIRType_Double) {
michael@0 1840 masm.storeDouble(ToFloatRegister(value), Address(dest.base, dest.offset));
michael@0 1841 return;
michael@0 1842 }
michael@0 1843
michael@0 1844 // Store the type tag if needed.
michael@0 1845 if (valueType != elementType)
michael@0 1846 masm.storeTypeTag(ImmType(ValueTypeFromMIRType(valueType)), dest);
michael@0 1847
michael@0 1848 // Store the payload.
michael@0 1849 if (value->isConstant())
michael@0 1850 masm.storePayload(*value->toConstant(), dest);
michael@0 1851 else
michael@0 1852 masm.storePayload(ToRegister(value), dest);
michael@0 1853 } else {
michael@0 1854 Register indexReg = ToRegister(index);
michael@0 1855 if (valueType == MIRType_Double) {
michael@0 1856 masm.storeDouble(ToFloatRegister(value), BaseIndex(elements, indexReg, TimesEight));
michael@0 1857 return;
michael@0 1858 }
michael@0 1859
michael@0 1860 // Store the type tag if needed.
michael@0 1861 if (valueType != elementType)
michael@0 1862 masm.storeTypeTag(ImmType(ValueTypeFromMIRType(valueType)), elements, indexReg);
michael@0 1863
michael@0 1864 // Store the payload.
michael@0 1865 if (value->isConstant())
michael@0 1866 masm.storePayload(*value->toConstant(), elements, indexReg);
michael@0 1867 else
michael@0 1868 masm.storePayload(ToRegister(value), elements, indexReg);
michael@0 1869 }
michael@0 1870 }
michael@0 1871
michael@0 1872 bool
michael@0 1873 CodeGeneratorMIPS::visitGuardShape(LGuardShape *guard)
michael@0 1874 {
michael@0 1875 Register obj = ToRegister(guard->input());
michael@0 1876 Register tmp = ToRegister(guard->tempInt());
michael@0 1877
michael@0 1878 masm.loadPtr(Address(obj, JSObject::offsetOfShape()), tmp);
michael@0 1879 return bailoutCmpPtr(Assembler::NotEqual, tmp, ImmGCPtr(guard->mir()->shape()),
michael@0 1880 guard->snapshot());
michael@0 1881 }
michael@0 1882
michael@0 1883 bool
michael@0 1884 CodeGeneratorMIPS::visitGuardObjectType(LGuardObjectType *guard)
michael@0 1885 {
michael@0 1886 Register obj = ToRegister(guard->input());
michael@0 1887 Register tmp = ToRegister(guard->tempInt());
michael@0 1888
michael@0 1889 masm.loadPtr(Address(obj, JSObject::offsetOfType()), tmp);
michael@0 1890 Assembler::Condition cond = guard->mir()->bailOnEquality()
michael@0 1891 ? Assembler::Equal
michael@0 1892 : Assembler::NotEqual;
michael@0 1893 return bailoutCmpPtr(cond, tmp, ImmGCPtr(guard->mir()->typeObject()), guard->snapshot());
michael@0 1894 }
michael@0 1895
michael@0 1896 bool
michael@0 1897 CodeGeneratorMIPS::visitGuardClass(LGuardClass *guard)
michael@0 1898 {
michael@0 1899 Register obj = ToRegister(guard->input());
michael@0 1900 Register tmp = ToRegister(guard->tempInt());
michael@0 1901
michael@0 1902 masm.loadObjClass(obj, tmp);
michael@0 1903 if (!bailoutCmpPtr(Assembler::NotEqual, tmp, Imm32((uint32_t)guard->mir()->getClass()),
michael@0 1904 guard->snapshot()))
michael@0 1905 return false;
michael@0 1906 return true;
michael@0 1907 }
michael@0 1908
michael@0 1909 bool
michael@0 1910 CodeGeneratorMIPS::visitImplicitThis(LImplicitThis *lir)
michael@0 1911 {
michael@0 1912 Register callee = ToRegister(lir->callee());
michael@0 1913 const ValueOperand out = ToOutValue(lir);
michael@0 1914
michael@0 1915 // The implicit |this| is always |undefined| if the function's environment
michael@0 1916 // is the current global.
michael@0 1917 masm.loadPtr(Address(callee, JSFunction::offsetOfEnvironment()), out.typeReg());
michael@0 1918 GlobalObject *global = &gen->info().script()->global();
michael@0 1919
michael@0 1920 // TODO: OOL stub path.
michael@0 1921 if (!bailoutCmpPtr(Assembler::NotEqual, out.typeReg(), ImmGCPtr(global), lir->snapshot()))
michael@0 1922 return false;
michael@0 1923
michael@0 1924 masm.moveValue(UndefinedValue(), out);
michael@0 1925 return true;
michael@0 1926 }
michael@0 1927
michael@0 1928 bool
michael@0 1929 CodeGeneratorMIPS::visitInterruptCheck(LInterruptCheck *lir)
michael@0 1930 {
michael@0 1931 OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing());
michael@0 1932 if (!ool)
michael@0 1933 return false;
michael@0 1934
michael@0 1935 masm.branch32(Assembler::NotEqual,
michael@0 1936 AbsoluteAddress(GetIonContext()->runtime->addressOfInterrupt()), Imm32(0),
michael@0 1937 ool->entry());
michael@0 1938 masm.bind(ool->rejoin());
michael@0 1939 return true;
michael@0 1940 }
michael@0 1941
michael@0 1942 bool
michael@0 1943 CodeGeneratorMIPS::generateInvalidateEpilogue()
michael@0 1944 {
michael@0 1945 // Ensure that there is enough space in the buffer for the OsiPoint
michael@0 1946 // patching to occur. Otherwise, we could overwrite the invalidation
michael@0 1947 // epilogue.
michael@0 1948 for (size_t i = 0; i < sizeof(void *); i += Assembler::nopSize())
michael@0 1949 masm.nop();
michael@0 1950
michael@0 1951 masm.bind(&invalidate_);
michael@0 1952
michael@0 1953 // Push the return address of the point that we bailed out at to the stack
michael@0 1954 masm.Push(ra);
michael@0 1955
michael@0 1956 // Push the Ion script onto the stack (when we determine what that
michael@0 1957 // pointer is).
michael@0 1958 invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1)));
michael@0 1959 JitCode *thunk = gen->jitRuntime()->getInvalidationThunk();
michael@0 1960
michael@0 1961 masm.branch(thunk);
michael@0 1962
michael@0 1963 // We should never reach this point in JIT code -- the invalidation thunk
michael@0 1964 // should pop the invalidated JS frame and return directly to its caller.
michael@0 1965 masm.assumeUnreachable("Should have returned directly to its caller instead of here.");
michael@0 1966 return true;
michael@0 1967 }
michael@0 1968
michael@0 1969 void
michael@0 1970 DispatchIonCache::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
michael@0 1971 {
michael@0 1972 // Can always use the scratch register on MIPS.
michael@0 1973 addState->dispatchScratch = ScratchRegister;
michael@0 1974 }
michael@0 1975
michael@0 1976 bool
michael@0 1977 CodeGeneratorMIPS::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins)
michael@0 1978 {
michael@0 1979 MOZ_ASSUME_UNREACHABLE("NYI");
michael@0 1980 }
michael@0 1981
michael@0 1982 bool
michael@0 1983 CodeGeneratorMIPS::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins)
michael@0 1984 {
michael@0 1985 MOZ_ASSUME_UNREACHABLE("NYI");
michael@0 1986 }
michael@0 1987
michael@0 1988 bool
michael@0 1989 CodeGeneratorMIPS::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins)
michael@0 1990 {
michael@0 1991 const MAsmJSLoadHeap *mir = ins->mir();
michael@0 1992 const LAllocation *ptr = ins->ptr();
michael@0 1993 const LDefinition *out = ins->output();
michael@0 1994
michael@0 1995 bool isSigned;
michael@0 1996 int size;
michael@0 1997 bool isFloat = false;
michael@0 1998 switch (mir->viewType()) {
michael@0 1999 case ArrayBufferView::TYPE_INT8: isSigned = true; size = 8; break;
michael@0 2000 case ArrayBufferView::TYPE_UINT8: isSigned = false; size = 8; break;
michael@0 2001 case ArrayBufferView::TYPE_INT16: isSigned = true; size = 16; break;
michael@0 2002 case ArrayBufferView::TYPE_UINT16: isSigned = false; size = 16; break;
michael@0 2003 case ArrayBufferView::TYPE_INT32: isSigned = true; size = 32; break;
michael@0 2004 case ArrayBufferView::TYPE_UINT32: isSigned = false; size = 32; break;
michael@0 2005 case ArrayBufferView::TYPE_FLOAT64: isFloat = true; size = 64; break;
michael@0 2006 case ArrayBufferView::TYPE_FLOAT32: isFloat = true; size = 32; break;
michael@0 2007 default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
michael@0 2008 }
michael@0 2009
michael@0 2010 if (ptr->isConstant()) {
michael@0 2011 MOZ_ASSERT(mir->skipBoundsCheck());
michael@0 2012 int32_t ptrImm = ptr->toConstant()->toInt32();
michael@0 2013 MOZ_ASSERT(ptrImm >= 0);
michael@0 2014 if (isFloat) {
michael@0 2015 if (size == 32) {
michael@0 2016 masm.loadFloat32(Address(HeapReg, ptrImm), ToFloatRegister(out));
michael@0 2017 } else {
michael@0 2018 masm.loadDouble(Address(HeapReg, ptrImm), ToFloatRegister(out));
michael@0 2019 }
michael@0 2020 } else {
michael@0 2021 masm.ma_load(ToRegister(out), Address(HeapReg, ptrImm),
michael@0 2022 static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
michael@0 2023 }
michael@0 2024 return true;
michael@0 2025 }
michael@0 2026
michael@0 2027 Register ptrReg = ToRegister(ptr);
michael@0 2028
michael@0 2029 if (mir->skipBoundsCheck()) {
michael@0 2030 if (isFloat) {
michael@0 2031 if (size == 32) {
michael@0 2032 masm.loadFloat32(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out));
michael@0 2033 } else {
michael@0 2034 masm.loadDouble(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out));
michael@0 2035 }
michael@0 2036 } else {
michael@0 2037 masm.ma_load(ToRegister(out), BaseIndex(HeapReg, ptrReg, TimesOne),
michael@0 2038 static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
michael@0 2039 }
michael@0 2040 return true;
michael@0 2041 }
michael@0 2042
michael@0 2043 BufferOffset bo = masm.ma_BoundsCheck(ScratchRegister);
michael@0 2044
michael@0 2045 Label outOfRange;
michael@0 2046 Label done;
michael@0 2047 masm.ma_b(ptrReg, ScratchRegister, &outOfRange, Assembler::AboveOrEqual, ShortJump);
michael@0 2048 // Offset is ok, let's load value.
michael@0 2049 if (isFloat) {
michael@0 2050 if (size == 32)
michael@0 2051 masm.loadFloat32(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out));
michael@0 2052 else
michael@0 2053 masm.loadDouble(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out));
michael@0 2054 } else {
michael@0 2055 masm.ma_load(ToRegister(out), BaseIndex(HeapReg, ptrReg, TimesOne),
michael@0 2056 static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
michael@0 2057 }
michael@0 2058 masm.ma_b(&done, ShortJump);
michael@0 2059 masm.bind(&outOfRange);
michael@0 2060 // Offset is out of range. Load default values.
michael@0 2061 if (isFloat) {
michael@0 2062 if (size == 32)
michael@0 2063 masm.convertDoubleToFloat32(NANReg, ToFloatRegister(out));
michael@0 2064 else
michael@0 2065 masm.moveDouble(NANReg, ToFloatRegister(out));
michael@0 2066 } else {
michael@0 2067 masm.move32(Imm32(0), ToRegister(out));
michael@0 2068 }
michael@0 2069 masm.bind(&done);
michael@0 2070
michael@0 2071 return gen->noteHeapAccess(AsmJSHeapAccess(bo.getOffset()));
michael@0 2072 }
michael@0 2073
michael@0 2074 bool
michael@0 2075 CodeGeneratorMIPS::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
michael@0 2076 {
michael@0 2077 const MAsmJSStoreHeap *mir = ins->mir();
michael@0 2078 const LAllocation *value = ins->value();
michael@0 2079 const LAllocation *ptr = ins->ptr();
michael@0 2080
michael@0 2081 bool isSigned;
michael@0 2082 int size;
michael@0 2083 bool isFloat = false;
michael@0 2084 switch (mir->viewType()) {
michael@0 2085 case ArrayBufferView::TYPE_INT8: isSigned = true; size = 8; break;
michael@0 2086 case ArrayBufferView::TYPE_UINT8: isSigned = false; size = 8; break;
michael@0 2087 case ArrayBufferView::TYPE_INT16: isSigned = true; size = 16; break;
michael@0 2088 case ArrayBufferView::TYPE_UINT16: isSigned = false; size = 16; break;
michael@0 2089 case ArrayBufferView::TYPE_INT32: isSigned = true; size = 32; break;
michael@0 2090 case ArrayBufferView::TYPE_UINT32: isSigned = false; size = 32; break;
michael@0 2091 case ArrayBufferView::TYPE_FLOAT64: isFloat = true; size = 64; break;
michael@0 2092 case ArrayBufferView::TYPE_FLOAT32: isFloat = true; size = 32; break;
michael@0 2093 default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
michael@0 2094 }
michael@0 2095
michael@0 2096 if (ptr->isConstant()) {
michael@0 2097 MOZ_ASSERT(mir->skipBoundsCheck());
michael@0 2098 int32_t ptrImm = ptr->toConstant()->toInt32();
michael@0 2099 MOZ_ASSERT(ptrImm >= 0);
michael@0 2100
michael@0 2101 if (isFloat) {
michael@0 2102 if (size == 32) {
michael@0 2103 masm.storeFloat32(ToFloatRegister(value), Address(HeapReg, ptrImm));
michael@0 2104 } else {
michael@0 2105 masm.storeDouble(ToFloatRegister(value), Address(HeapReg, ptrImm));
michael@0 2106 }
michael@0 2107 } else {
michael@0 2108 masm.ma_store(ToRegister(value), Address(HeapReg, ptrImm),
michael@0 2109 static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
michael@0 2110 }
michael@0 2111 return true;
michael@0 2112 }
michael@0 2113
michael@0 2114 Register ptrReg = ToRegister(ptr);
michael@0 2115 Address dstAddr(ptrReg, 0);
michael@0 2116
michael@0 2117 if (mir->skipBoundsCheck()) {
michael@0 2118 if (isFloat) {
michael@0 2119 if (size == 32) {
michael@0 2120 masm.storeFloat32(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne));
michael@0 2121 } else
michael@0 2122 masm.storeDouble(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne));
michael@0 2123 } else {
michael@0 2124 masm.ma_store(ToRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne),
michael@0 2125 static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
michael@0 2126 }
michael@0 2127 return true;
michael@0 2128 }
michael@0 2129
michael@0 2130 BufferOffset bo = masm.ma_BoundsCheck(ScratchRegister);
michael@0 2131
michael@0 2132 Label rejoin;
michael@0 2133 masm.ma_b(ptrReg, ScratchRegister, &rejoin, Assembler::AboveOrEqual, ShortJump);
michael@0 2134
michael@0 2135 // Offset is ok, let's store value.
michael@0 2136 if (isFloat) {
michael@0 2137 if (size == 32) {
michael@0 2138 masm.storeFloat32(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne));
michael@0 2139 } else
michael@0 2140 masm.storeDouble(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne));
michael@0 2141 } else {
michael@0 2142 masm.ma_store(ToRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne),
michael@0 2143 static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
michael@0 2144 }
michael@0 2145 masm.bind(&rejoin);
michael@0 2146
michael@0 2147 return gen->noteHeapAccess(AsmJSHeapAccess(bo.getOffset()));
michael@0 2148 }
michael@0 2149
michael@0 2150 bool
michael@0 2151 CodeGeneratorMIPS::visitAsmJSPassStackArg(LAsmJSPassStackArg *ins)
michael@0 2152 {
michael@0 2153 const MAsmJSPassStackArg *mir = ins->mir();
michael@0 2154 if (ins->arg()->isConstant()) {
michael@0 2155 masm.storePtr(ImmWord(ToInt32(ins->arg())), Address(StackPointer, mir->spOffset()));
michael@0 2156 } else {
michael@0 2157 if (ins->arg()->isGeneralReg()) {
michael@0 2158 masm.storePtr(ToRegister(ins->arg()), Address(StackPointer, mir->spOffset()));
michael@0 2159 } else {
michael@0 2160 masm.storeDouble(ToFloatRegister(ins->arg()), Address(StackPointer, mir->spOffset()));
michael@0 2161 }
michael@0 2162 }
michael@0 2163
michael@0 2164 return true;
michael@0 2165 }
michael@0 2166
michael@0 2167 bool
michael@0 2168 CodeGeneratorMIPS::visitUDiv(LUDiv *ins)
michael@0 2169 {
michael@0 2170 Register lhs = ToRegister(ins->lhs());
michael@0 2171 Register rhs = ToRegister(ins->rhs());
michael@0 2172 Register output = ToRegister(ins->output());
michael@0 2173
michael@0 2174 Label done;
michael@0 2175 if (ins->mir()->canBeDivideByZero()) {
michael@0 2176 if (ins->mir()->isTruncated()) {
michael@0 2177 Label notzero;
michael@0 2178 masm.ma_b(rhs, rhs, &notzero, Assembler::NonZero, ShortJump);
michael@0 2179 masm.move32(Imm32(0), output);
michael@0 2180 masm.ma_b(&done, ShortJump);
michael@0 2181 masm.bind(&notzero);
michael@0 2182 } else {
michael@0 2183 MOZ_ASSERT(ins->mir()->fallible());
michael@0 2184 if (!bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot()))
michael@0 2185 return false;
michael@0 2186 }
michael@0 2187 }
michael@0 2188
michael@0 2189 masm.as_divu(lhs, rhs);
michael@0 2190 masm.as_mflo(output);
michael@0 2191
michael@0 2192 if (!ins->mir()->isTruncated()) {
michael@0 2193 if (!bailoutCmp32(Assembler::LessThan, output, Imm32(0), ins->snapshot()))
michael@0 2194 return false;
michael@0 2195 }
michael@0 2196
michael@0 2197 masm.bind(&done);
michael@0 2198 return true;
michael@0 2199 }
michael@0 2200
michael@0 2201 bool
michael@0 2202 CodeGeneratorMIPS::visitUMod(LUMod *ins)
michael@0 2203 {
michael@0 2204 Register lhs = ToRegister(ins->lhs());
michael@0 2205 Register rhs = ToRegister(ins->rhs());
michael@0 2206 Register output = ToRegister(ins->output());
michael@0 2207 Label done;
michael@0 2208
michael@0 2209 if (ins->mir()->canBeDivideByZero()) {
michael@0 2210 if (ins->mir()->isTruncated()) {
michael@0 2211 // Infinity|0 == 0
michael@0 2212 Label notzero;
michael@0 2213 masm.ma_b(rhs, rhs, &notzero, Assembler::NonZero, ShortJump);
michael@0 2214 masm.move32(Imm32(0), output);
michael@0 2215 masm.ma_b(&done, ShortJump);
michael@0 2216 masm.bind(&notzero);
michael@0 2217 } else {
michael@0 2218 MOZ_ASSERT(ins->mir()->fallible());
michael@0 2219 if (!bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot()))
michael@0 2220 return false;
michael@0 2221 }
michael@0 2222 }
michael@0 2223
michael@0 2224 masm.as_divu(lhs, rhs);
michael@0 2225 masm.as_mfhi(output);
michael@0 2226
michael@0 2227 if (!ins->mir()->isTruncated()) {
michael@0 2228 if (!bailoutCmp32(Assembler::LessThan, output, Imm32(0), ins->snapshot()))
michael@0 2229 return false;
michael@0 2230 }
michael@0 2231
michael@0 2232 masm.bind(&done);
michael@0 2233 return true;
michael@0 2234 }
michael@0 2235
michael@0 2236 bool
michael@0 2237 CodeGeneratorMIPS::visitEffectiveAddress(LEffectiveAddress *ins)
michael@0 2238 {
michael@0 2239 const MEffectiveAddress *mir = ins->mir();
michael@0 2240 Register base = ToRegister(ins->base());
michael@0 2241 Register index = ToRegister(ins->index());
michael@0 2242 Register output = ToRegister(ins->output());
michael@0 2243
michael@0 2244 BaseIndex address(base, index, mir->scale(), mir->displacement());
michael@0 2245 masm.computeEffectiveAddress(address, output);
michael@0 2246 return true;
michael@0 2247 }
michael@0 2248
michael@0 2249 bool
michael@0 2250 CodeGeneratorMIPS::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins)
michael@0 2251 {
michael@0 2252 const MAsmJSLoadGlobalVar *mir = ins->mir();
michael@0 2253 unsigned addr = mir->globalDataOffset();
michael@0 2254 if (mir->type() == MIRType_Int32)
michael@0 2255 masm.load32(Address(GlobalReg, addr), ToRegister(ins->output()));
michael@0 2256 else if (mir->type() == MIRType_Float32)
michael@0 2257 masm.loadFloat32(Address(GlobalReg, addr), ToFloatRegister(ins->output()));
michael@0 2258 else
michael@0 2259 masm.loadDouble(Address(GlobalReg, addr), ToFloatRegister(ins->output()));
michael@0 2260 return true;
michael@0 2261 }
michael@0 2262
michael@0 2263 bool
michael@0 2264 CodeGeneratorMIPS::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins)
michael@0 2265 {
michael@0 2266 const MAsmJSStoreGlobalVar *mir = ins->mir();
michael@0 2267
michael@0 2268 MIRType type = mir->value()->type();
michael@0 2269 MOZ_ASSERT(IsNumberType(type));
michael@0 2270 unsigned addr = mir->globalDataOffset();
michael@0 2271 if (mir->value()->type() == MIRType_Int32)
michael@0 2272 masm.store32(ToRegister(ins->value()), Address(GlobalReg, addr));
michael@0 2273 else if (mir->value()->type() == MIRType_Float32)
michael@0 2274 masm.storeFloat32(ToFloatRegister(ins->value()), Address(GlobalReg, addr));
michael@0 2275 else
michael@0 2276 masm.storeDouble(ToFloatRegister(ins->value()), Address(GlobalReg, addr));
michael@0 2277 return true;
michael@0 2278 }
michael@0 2279
michael@0 2280 bool
michael@0 2281 CodeGeneratorMIPS::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr *ins)
michael@0 2282 {
michael@0 2283 const MAsmJSLoadFuncPtr *mir = ins->mir();
michael@0 2284
michael@0 2285 Register index = ToRegister(ins->index());
michael@0 2286 Register tmp = ToRegister(ins->temp());
michael@0 2287 Register out = ToRegister(ins->output());
michael@0 2288 unsigned addr = mir->globalDataOffset();
michael@0 2289
michael@0 2290 BaseIndex source(GlobalReg, index, TimesFour, addr);
michael@0 2291 masm.load32(source, out);
michael@0 2292 return true;
michael@0 2293 }
michael@0 2294
michael@0 2295 bool
michael@0 2296 CodeGeneratorMIPS::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc *ins)
michael@0 2297 {
michael@0 2298 const MAsmJSLoadFFIFunc *mir = ins->mir();
michael@0 2299 masm.loadPtr(Address(GlobalReg, mir->globalDataOffset()), ToRegister(ins->output()));
michael@0 2300 return true;
michael@0 2301 }
michael@0 2302
michael@0 2303 bool
michael@0 2304 CodeGeneratorMIPS::visitNegI(LNegI *ins)
michael@0 2305 {
michael@0 2306 Register input = ToRegister(ins->input());
michael@0 2307 Register output = ToRegister(ins->output());
michael@0 2308
michael@0 2309 masm.ma_negu(output, input);
michael@0 2310 return true;
michael@0 2311 }
michael@0 2312
michael@0 2313 bool
michael@0 2314 CodeGeneratorMIPS::visitNegD(LNegD *ins)
michael@0 2315 {
michael@0 2316 FloatRegister input = ToFloatRegister(ins->input());
michael@0 2317 FloatRegister output = ToFloatRegister(ins->output());
michael@0 2318
michael@0 2319 masm.as_negd(output, input);
michael@0 2320 return true;
michael@0 2321 }
michael@0 2322
michael@0 2323 bool
michael@0 2324 CodeGeneratorMIPS::visitNegF(LNegF *ins)
michael@0 2325 {
michael@0 2326 FloatRegister input = ToFloatRegister(ins->input());
michael@0 2327 FloatRegister output = ToFloatRegister(ins->output());
michael@0 2328
michael@0 2329 masm.as_negs(output, input);
michael@0 2330 return true;
michael@0 2331 }
michael@0 2332
michael@0 2333 bool
michael@0 2334 CodeGeneratorMIPS::visitForkJoinGetSlice(LForkJoinGetSlice *ins)
michael@0 2335 {
michael@0 2336 MOZ_ASSUME_UNREACHABLE("NYI");
michael@0 2337 }
michael@0 2338
michael@0 2339 JitCode *
michael@0 2340 JitRuntime::generateForkJoinGetSliceStub(JSContext *cx)
michael@0 2341 {
michael@0 2342 MOZ_ASSUME_UNREACHABLE("NYI");
michael@0 2343 }

mercurial