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

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

mercurial