Bug 969375 - MIPS port: Added Lowering code. r=jandem
authorBranislav Rankov <branislav.rankov@imgtec.com>
Tue, 18 Mar 2014 16:43:18 +0100
changeset 179936 b035f5a9c20e34a8d6aff18b05fc2f6190edca04
parent 179935 ac10d2fcb25da489d0def5703c558a84704f868c
child 179937 b65cb4bc310fe4922ce042a78a0e7cfbdd940dea
push id26649
push userryanvm@gmail.com
push dateThu, 24 Apr 2014 17:20:01 +0000
treeherdermozilla-central@7fdae4f893df [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs969375
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 969375 - MIPS port: Added Lowering code. r=jandem
js/src/jit/mips/LIR-mips.h
js/src/jit/mips/LOpcodes-mips.h
js/src/jit/mips/Lowering-mips.cpp
js/src/jit/mips/Lowering-mips.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit/mips/LIR-mips.h
@@ -0,0 +1,404 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_mips_LIR_mips_h
+#define jit_mips_LIR_mips_h
+
+namespace js {
+namespace jit {
+
+class LBox : public LInstructionHelper<2, 1, 0>
+{
+    MIRType type_;
+
+  public:
+    LIR_HEADER(Box);
+
+    LBox(const LAllocation &in_payload, MIRType type)
+      : type_(type)
+    {
+        setOperand(0, in_payload);
+    }
+
+    MIRType type() const {
+        return type_;
+    }
+    const char *extraName() const {
+        return StringFromMIRType(type_);
+    }
+};
+
+class LBoxFloatingPoint : public LInstructionHelper<2, 1, 1>
+{
+    MIRType type_;
+
+  public:
+    LIR_HEADER(BoxFloatingPoint);
+
+    LBoxFloatingPoint(const LAllocation &in, const LDefinition &temp, MIRType type)
+      : type_(type)
+    {
+        setOperand(0, in);
+        setTemp(0, temp);
+    }
+
+    MIRType type() const {
+        return type_;
+    }
+    const char *extraName() const {
+        return StringFromMIRType(type_);
+    }
+};
+
+class LUnbox : public LInstructionHelper<1, 2, 0>
+{
+  public:
+    LIR_HEADER(Unbox);
+
+    MUnbox *mir() const {
+        return mir_->toUnbox();
+    }
+    const LAllocation *payload() {
+        return getOperand(0);
+    }
+    const LAllocation *type() {
+        return getOperand(1);
+    }
+    const char *extraName() const {
+        return StringFromMIRType(mir()->type());
+    }
+};
+
+class LUnboxFloatingPoint : public LInstructionHelper<1, 2, 0>
+{
+    MIRType type_;
+
+  public:
+    LIR_HEADER(UnboxFloatingPoint);
+
+    static const size_t Input = 0;
+
+    LUnboxFloatingPoint(MIRType type)
+      : type_(type)
+    { }
+
+    MUnbox *mir() const {
+        return mir_->toUnbox();
+    }
+
+    MIRType type() const {
+        return type_;
+    }
+    const char *extraName() const {
+        return StringFromMIRType(type_);
+    }
+};
+
+// Convert a 32-bit unsigned integer to a double.
+class LAsmJSUInt32ToDouble : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(AsmJSUInt32ToDouble)
+
+    LAsmJSUInt32ToDouble(const LAllocation &input) {
+        setOperand(0, input);
+    }
+};
+
+// Convert a 32-bit unsigned integer to a float32.
+class LAsmJSUInt32ToFloat32 : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(AsmJSUInt32ToFloat32)
+
+    LAsmJSUInt32ToFloat32(const LAllocation &input) {
+        setOperand(0, input);
+    }
+};
+
+
+class LDivI : public LBinaryMath<1>
+{
+  public:
+    LIR_HEADER(DivI);
+
+    LDivI(const LAllocation &lhs, const LAllocation &rhs,
+          const LDefinition &temp) {
+        setOperand(0, lhs);
+        setOperand(1, rhs);
+        setTemp(0, temp);
+    }
+
+    MDiv *mir() const {
+        return mir_->toDiv();
+    }
+};
+
+class LDivPowTwoI : public LInstructionHelper<1, 1, 1>
+{
+    const int32_t shift_;
+
+  public:
+    LIR_HEADER(DivPowTwoI)
+
+    LDivPowTwoI(const LAllocation &lhs, int32_t shift, const LDefinition &temp)
+      : shift_(shift)
+    {
+        setOperand(0, lhs);
+        setTemp(0, temp);
+    }
+
+    const LAllocation *numerator() {
+        return getOperand(0);
+    }
+
+    int32_t shift() {
+        return shift_;
+    }
+
+    MDiv *mir() const {
+        return mir_->toDiv();
+    }
+};
+
+class LModI : public LBinaryMath<1>
+{
+  public:
+    LIR_HEADER(ModI);
+
+    LModI(const LAllocation &lhs, const LAllocation &rhs,
+          const LDefinition &callTemp)
+    {
+        setOperand(0, lhs);
+        setOperand(1, rhs);
+        setTemp(0, callTemp);
+    }
+
+    const LDefinition *callTemp() {
+        return getTemp(0);
+    }
+
+    MMod *mir() const {
+        return mir_->toMod();
+    }
+};
+
+class LModPowTwoI : public LInstructionHelper<1, 1, 0>
+{
+    const int32_t shift_;
+
+  public:
+    LIR_HEADER(ModPowTwoI);
+    int32_t shift()
+    {
+        return shift_;
+    }
+
+    LModPowTwoI(const LAllocation &lhs, int32_t shift)
+      : shift_(shift)
+    {
+        setOperand(0, lhs);
+    }
+
+    MMod *mir() const {
+        return mir_->toMod();
+    }
+};
+
+class LModMaskI : public LInstructionHelper<1, 1, 1>
+{
+    const int32_t shift_;
+
+  public:
+    LIR_HEADER(ModMaskI);
+
+    LModMaskI(const LAllocation &lhs, const LDefinition &temp1, int32_t shift)
+      : shift_(shift)
+    {
+        setOperand(0, lhs);
+        setTemp(0, temp1);
+    }
+
+    int32_t shift() const {
+        return shift_;
+    }
+
+    MMod *mir() const {
+        return mir_->toMod();
+    }
+};
+
+class LPowHalfD : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(PowHalfD);
+    LPowHalfD(const LAllocation &input) {
+        setOperand(0, input);
+    }
+
+    const LAllocation *input() {
+        return getOperand(0);
+    }
+    const LDefinition *output() {
+        return getDef(0);
+    }
+};
+
+// Takes a tableswitch with an integer to decide
+class LTableSwitch : public LInstructionHelper<0, 1, 2>
+{
+  public:
+    LIR_HEADER(TableSwitch);
+
+    LTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
+                 const LDefinition &jumpTablePointer, MTableSwitch *ins) {
+        setOperand(0, in);
+        setTemp(0, inputCopy);
+        setTemp(1, jumpTablePointer);
+        setMir(ins);
+    }
+
+    MTableSwitch *mir() const {
+        return mir_->toTableSwitch();
+    }
+
+    const LAllocation *index() {
+        return getOperand(0);
+    }
+    const LDefinition *tempInt() {
+        return getTemp(0);
+    }
+    // This is added to share the same CodeGenerator prefixes.
+    const LDefinition *tempPointer() {
+        return getTemp(1);
+    }
+};
+
+// Takes a tableswitch with an integer to decide
+class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 3>
+{
+  public:
+    LIR_HEADER(TableSwitchV);
+
+    LTableSwitchV(const LDefinition &inputCopy, const LDefinition &floatCopy,
+                  const LDefinition &jumpTablePointer, MTableSwitch *ins)
+    {
+        setTemp(0, inputCopy);
+        setTemp(1, floatCopy);
+        setTemp(2, jumpTablePointer);
+        setMir(ins);
+    }
+
+    MTableSwitch *mir() const {
+        return mir_->toTableSwitch();
+    }
+
+    static const size_t InputValue = 0;
+
+    const LDefinition *tempInt() {
+        return getTemp(0);
+    }
+    const LDefinition *tempFloat() {
+        return getTemp(1);
+    }
+    const LDefinition *tempPointer() {
+        return getTemp(2);
+    }
+};
+
+class LGuardShape : public LInstructionHelper<0, 1, 1>
+{
+  public:
+    LIR_HEADER(GuardShape);
+
+    LGuardShape(const LAllocation &in, const LDefinition &temp) {
+        setOperand(0, in);
+        setTemp(0, temp);
+    }
+    const MGuardShape *mir() const {
+        return mir_->toGuardShape();
+    }
+    const LDefinition *tempInt() {
+        return getTemp(0);
+    }
+};
+
+class LGuardObjectType : public LInstructionHelper<0, 1, 1>
+{
+  public:
+    LIR_HEADER(GuardObjectType);
+
+    LGuardObjectType(const LAllocation &in, const LDefinition &temp) {
+        setOperand(0, in);
+        setTemp(0, temp);
+    }
+    const MGuardObjectType *mir() const {
+        return mir_->toGuardObjectType();
+    }
+    const LDefinition *tempInt() {
+        return getTemp(0);
+    }
+};
+
+class LInterruptCheck : public LInstructionHelper<0, 0, 0>
+{
+  public:
+    LIR_HEADER(InterruptCheck);
+};
+
+class LMulI : public LBinaryMath<0>
+{
+  public:
+    LIR_HEADER(MulI);
+
+    MMul *mir() {
+        return mir_->toMul();
+    }
+};
+
+class LUDiv : public LBinaryMath<0>
+{
+  public:
+    LIR_HEADER(UDiv);
+
+    MDiv *mir() {
+        return mir_->toDiv();
+    }
+};
+
+class LUMod : public LBinaryMath<0>
+{
+  public:
+    LIR_HEADER(UMod);
+
+    MMod *mir() {
+        return mir_->toMod();
+    }
+};
+
+class LAsmJSLoadFuncPtr : public LInstructionHelper<1, 1, 1>
+{
+  public:
+    LIR_HEADER(AsmJSLoadFuncPtr);
+    LAsmJSLoadFuncPtr(const LAllocation &index, const LDefinition &temp) {
+        setOperand(0, index);
+        setTemp(0, temp);
+    }
+    const MAsmJSLoadFuncPtr *mir() const {
+        return mir_->toAsmJSLoadFuncPtr();
+    }
+    const LAllocation *index() {
+        return getOperand(0);
+    }
+    const LDefinition *temp() {
+        return getTemp(0);
+    }
+};
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_mips_LIR_mips_h */
new file mode 100644
--- /dev/null
+++ b/js/src/jit/mips/LOpcodes-mips.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_mips_LOpcodes_mips_h__
+#define jit_mips_LOpcodes_mips_h__
+
+#define LIR_CPU_OPCODE_LIST(_)  \
+    _(Unbox)                    \
+    _(UnboxFloatingPoint)       \
+    _(Box)                      \
+    _(BoxFloatingPoint)         \
+    _(DivI)                     \
+    _(DivPowTwoI)               \
+    _(ModI)                     \
+    _(ModPowTwoI)               \
+    _(ModMaskI)                 \
+    _(PowHalfD)                 \
+    _(AsmJSUInt32ToDouble)      \
+    _(AsmJSUInt32ToFloat32)     \
+    _(UDiv)                     \
+    _(UMod)                     \
+    _(AsmJSLoadFuncPtr)
+
+#endif // jit_mips_LOpcodes_mips_h__
new file mode 100644
--- /dev/null
+++ b/js/src/jit/mips/Lowering-mips.cpp
@@ -0,0 +1,531 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/MathAlgorithms.h"
+
+
+#include "jit/Lowering.h"
+#include "jit/mips/Assembler-mips.h"
+#include "jit/MIR.h"
+
+#include "jit/shared/Lowering-shared-inl.h"
+
+using namespace js;
+using namespace js::jit;
+
+using mozilla::FloorLog2;
+
+bool
+LIRGeneratorMIPS::useBox(LInstruction *lir, size_t n, MDefinition *mir,
+                         LUse::Policy policy, bool useAtStart)
+{
+    MOZ_ASSERT(mir->type() == MIRType_Value);
+
+    if (!ensureDefined(mir))
+        return false;
+    lir->setOperand(n, LUse(mir->virtualRegister(), policy, useAtStart));
+    lir->setOperand(n + 1, LUse(VirtualRegisterOfPayload(mir), policy, useAtStart));
+    return true;
+}
+
+bool
+LIRGeneratorMIPS::useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1,
+                              Register reg2)
+{
+    MOZ_ASSERT(mir->type() == MIRType_Value);
+    MOZ_ASSERT(reg1 != reg2);
+
+    if (!ensureDefined(mir))
+        return false;
+    lir->setOperand(n, LUse(reg1, mir->virtualRegister()));
+    lir->setOperand(n + 1, LUse(reg2, VirtualRegisterOfPayload(mir)));
+    return true;
+}
+
+LAllocation
+LIRGeneratorMIPS::useByteOpRegister(MDefinition *mir)
+{
+    return useRegister(mir);
+}
+
+LAllocation
+LIRGeneratorMIPS::useByteOpRegisterOrNonDoubleConstant(MDefinition *mir)
+{
+    return useRegisterOrNonDoubleConstant(mir);
+}
+
+bool
+LIRGeneratorMIPS::lowerConstantDouble(double d, MInstruction *mir)
+{
+    return define(new(alloc()) LDouble(d), mir);
+}
+
+bool
+LIRGeneratorMIPS::lowerConstantFloat32(float d, MInstruction *mir)
+{
+    return define(new(alloc()) LFloat32(d), mir);
+}
+
+bool
+LIRGeneratorMIPS::visitConstant(MConstant *ins)
+{
+    if (ins->type() == MIRType_Double)
+        return lowerConstantDouble(ins->value().toDouble(), ins);
+
+    if (ins->type() == MIRType_Float32)
+        return lowerConstantFloat32(ins->value().toDouble(), ins);
+
+    // Emit non-double constants at their uses.
+    if (ins->canEmitAtUses())
+        return emitAtUses(ins);
+
+    return LIRGeneratorShared::visitConstant(ins);
+}
+
+bool
+LIRGeneratorMIPS::visitBox(MBox *box)
+{
+    MDefinition *inner = box->getOperand(0);
+
+    // If the box wrapped a double, it needs a new register.
+    if (IsFloatingPointType(inner->type()))
+        return defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner),
+                                                        tempCopy(inner, 0), inner->type()), box);
+
+    if (box->canEmitAtUses())
+        return emitAtUses(box);
+
+    if (inner->isConstant())
+        return defineBox(new(alloc()) LValue(inner->toConstant()->value()), box);
+
+    LBox *lir = new(alloc()) LBox(use(inner), inner->type());
+
+    // Otherwise, we should not define a new register for the payload portion
+    // of the output, so bypass defineBox().
+    uint32_t vreg = getVirtualRegister();
+    if (vreg >= MAX_VIRTUAL_REGISTERS)
+        return false;
+
+    // Note that because we're using PASSTHROUGH, we do not change the type of
+    // the definition. We also do not define the first output as "TYPE",
+    // because it has no corresponding payload at (vreg + 1). Also note that
+    // although we copy the input's original type for the payload half of the
+    // definition, this is only for clarity. PASSTHROUGH definitions are
+    // ignored.
+    lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL));
+    lir->setDef(1, LDefinition(inner->virtualRegister(), LDefinition::TypeFrom(inner->type()),
+                               LDefinition::PASSTHROUGH));
+    box->setVirtualRegister(vreg);
+    return add(lir);
+}
+
+bool
+LIRGeneratorMIPS::visitUnbox(MUnbox *unbox)
+{
+    // An unbox on mips reads in a type tag (either in memory or a register) and
+    // a payload. Unlike most instructions consuming a box, we ask for the type
+    // second, so that the result can re-use the first input.
+    MDefinition *inner = unbox->getOperand(0);
+
+    if (!ensureDefined(inner))
+        return false;
+
+    if (IsFloatingPointType(unbox->type())) {
+        LUnboxFloatingPoint *lir = new(alloc()) LUnboxFloatingPoint(unbox->type());
+        if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
+            return false;
+        if (!useBox(lir, LUnboxFloatingPoint::Input, inner))
+            return false;
+        return define(lir, unbox);
+    }
+
+    // Swap the order we use the box pieces so we can re-use the payload
+    // register.
+    LUnbox *lir = new(alloc()) LUnbox;
+    lir->setOperand(0, usePayloadInRegisterAtStart(inner));
+    lir->setOperand(1, useType(inner, LUse::REGISTER));
+
+    if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
+        return false;
+
+    // Note that PASSTHROUGH here is illegal, since types and payloads form two
+    // separate intervals. If the type becomes dead before the payload, it
+    // could be used as a Value without the type being recoverable. Unbox's
+    // purpose is to eagerly kill the definition of a type tag, so keeping both
+    // alive (for the purpose of gcmaps) is unappealing. Instead, we create a
+    // new virtual register.
+    return defineReuseInput(lir, unbox, 0);
+}
+
+bool
+LIRGeneratorMIPS::visitReturn(MReturn *ret)
+{
+    MDefinition *opd = ret->getOperand(0);
+    MOZ_ASSERT(opd->type() == MIRType_Value);
+
+    LReturn *ins = new(alloc()) LReturn;
+    ins->setOperand(0, LUse(JSReturnReg_Type));
+    ins->setOperand(1, LUse(JSReturnReg_Data));
+    return fillBoxUses(ins, 0, opd) && add(ins);
+}
+
+// x = !y
+bool
+LIRGeneratorMIPS::lowerForALU(LInstructionHelper<1, 1, 0> *ins,
+                              MDefinition *mir, MDefinition *input)
+{
+    ins->setOperand(0, useRegister(input));
+    return define(ins, mir,
+                  LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::DEFAULT));
+}
+
+// z = x+y
+bool
+LIRGeneratorMIPS::lowerForALU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
+                              MDefinition *lhs, MDefinition *rhs)
+{
+    ins->setOperand(0, useRegister(lhs));
+    ins->setOperand(1, useRegisterOrConstant(rhs));
+    return define(ins, mir,
+                  LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::DEFAULT));
+}
+
+bool
+LIRGeneratorMIPS::lowerForFPU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir,
+                              MDefinition *input)
+{
+    ins->setOperand(0, useRegister(input));
+    return define(ins, mir,
+                  LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::DEFAULT));
+}
+
+bool
+LIRGeneratorMIPS::lowerForFPU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
+                              MDefinition *lhs, MDefinition *rhs)
+{
+    ins->setOperand(0, useRegister(lhs));
+    ins->setOperand(1, useRegister(rhs));
+    return define(ins, mir,
+                  LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::DEFAULT));
+}
+
+bool
+LIRGeneratorMIPS::lowerForBitAndAndBranch(LBitAndAndBranch *baab, MInstruction *mir,
+                                          MDefinition *lhs, MDefinition *rhs)
+{
+    baab->setOperand(0, useRegisterAtStart(lhs));
+    baab->setOperand(1, useRegisterOrConstantAtStart(rhs));
+    return add(baab, mir);
+}
+
+bool
+LIRGeneratorMIPS::defineUntypedPhi(MPhi *phi, size_t lirIndex)
+{
+    LPhi *type = current->getPhi(lirIndex + VREG_TYPE_OFFSET);
+    LPhi *payload = current->getPhi(lirIndex + VREG_DATA_OFFSET);
+
+    uint32_t typeVreg = getVirtualRegister();
+    if (typeVreg >= MAX_VIRTUAL_REGISTERS)
+        return false;
+
+    phi->setVirtualRegister(typeVreg);
+
+    uint32_t payloadVreg = getVirtualRegister();
+    if (payloadVreg >= MAX_VIRTUAL_REGISTERS)
+        return false;
+    MOZ_ASSERT(typeVreg + 1 == payloadVreg);
+
+    type->setDef(0, LDefinition(typeVreg, LDefinition::TYPE));
+    payload->setDef(0, LDefinition(payloadVreg, LDefinition::PAYLOAD));
+    annotate(type);
+    annotate(payload);
+    return true;
+}
+
+void
+LIRGeneratorMIPS::lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition,
+                                       LBlock *block, size_t lirIndex)
+{
+    MDefinition *operand = phi->getOperand(inputPosition);
+    LPhi *type = block->getPhi(lirIndex + VREG_TYPE_OFFSET);
+    LPhi *payload = block->getPhi(lirIndex + VREG_DATA_OFFSET);
+    type->setOperand(inputPosition, LUse(operand->virtualRegister() + VREG_TYPE_OFFSET,
+                                         LUse::ANY));
+    payload->setOperand(inputPosition, LUse(VirtualRegisterOfPayload(operand), LUse::ANY));
+}
+
+bool
+LIRGeneratorMIPS::lowerForShift(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
+                                MDefinition *lhs, MDefinition *rhs)
+{
+    ins->setOperand(0, useRegister(lhs));
+    ins->setOperand(1, useRegisterOrConstant(rhs));
+    return define(ins, mir);
+}
+
+bool
+LIRGeneratorMIPS::lowerDivI(MDiv *div)
+{
+    if (div->isUnsigned())
+        return lowerUDiv(div);
+
+    // Division instructions are slow. Division by constant denominators can be
+    // rewritten to use other instructions.
+    if (div->rhs()->isConstant()) {
+        int32_t rhs = div->rhs()->toConstant()->value().toInt32();
+        // Check for division by a positive power of two, which is an easy and
+        // important case to optimize. Note that other optimizations are also
+        // possible; division by negative powers of two can be optimized in a
+        // similar manner as positive powers of two, and division by other
+        // constants can be optimized by a reciprocal multiplication technique.
+        int32_t shift = FloorLog2(rhs);
+        if (rhs > 0 && 1 << shift == rhs) {
+            LDivPowTwoI *lir = new(alloc()) LDivPowTwoI(useRegister(div->lhs()), shift, temp());
+            if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
+                return false;
+            return define(lir, div);
+        }
+    }
+
+    LDivI *lir = new(alloc()) LDivI(useRegister(div->lhs()), useRegister(div->rhs()), temp());
+    if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
+        return false;
+    return define(lir, div);
+}
+
+bool
+LIRGeneratorMIPS::lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs)
+{
+    LMulI *lir = new(alloc()) LMulI;
+    if (mul->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
+        return false;
+
+    return lowerForALU(lir, mul, lhs, rhs);
+}
+
+bool
+LIRGeneratorMIPS::lowerModI(MMod *mod)
+{
+    if (mod->isUnsigned())
+        return lowerUMod(mod);
+
+    if (mod->rhs()->isConstant()) {
+        int32_t rhs = mod->rhs()->toConstant()->value().toInt32();
+        int32_t shift = FloorLog2(rhs);
+        if (rhs > 0 && 1 << shift == rhs) {
+            LModPowTwoI *lir = new(alloc()) LModPowTwoI(useRegister(mod->lhs()), shift);
+            if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
+                return false;
+            return define(lir, mod);
+        } else if (shift < 31 && (1 << (shift + 1)) - 1 == rhs) {
+            LModMaskI *lir = new(alloc()) LModMaskI(useRegister(mod->lhs()),
+                                           temp(LDefinition::GENERAL), shift + 1);
+            if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
+                return false;
+            return define(lir, mod);
+        }
+    }
+    LModI *lir = new(alloc()) LModI(useRegister(mod->lhs()), useRegister(mod->rhs()),
+                           temp(LDefinition::GENERAL));
+
+    if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
+        return false;
+    return define(lir, mod);
+}
+
+bool
+LIRGeneratorMIPS::visitPowHalf(MPowHalf *ins)
+{
+    MDefinition *input = ins->input();
+    MOZ_ASSERT(input->type() == MIRType_Double);
+    LPowHalfD *lir = new(alloc()) LPowHalfD(useRegisterAtStart(input));
+    return defineReuseInput(lir, ins, 0);
+}
+
+LTableSwitch *
+LIRGeneratorMIPS::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
+                                  MTableSwitch *tableswitch)
+{
+    return new(alloc()) LTableSwitch(in, inputCopy, temp(), tableswitch);
+}
+
+LTableSwitchV *
+LIRGeneratorMIPS::newLTableSwitchV(MTableSwitch *tableswitch)
+{
+    return new(alloc()) LTableSwitchV(temp(), tempFloat32(), temp(), tableswitch);
+}
+
+bool
+LIRGeneratorMIPS::visitGuardShape(MGuardShape *ins)
+{
+    MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
+
+    LDefinition tempObj = temp(LDefinition::OBJECT);
+    LGuardShape *guard = new(alloc()) LGuardShape(useRegister(ins->obj()), tempObj);
+    if (!assignSnapshot(guard, ins->bailoutKind()))
+        return false;
+    if (!add(guard, ins))
+        return false;
+    return redefine(ins, ins->obj());
+}
+
+bool
+LIRGeneratorMIPS::visitGuardObjectType(MGuardObjectType *ins)
+{
+    MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
+
+    LDefinition tempObj = temp(LDefinition::OBJECT);
+    LGuardObjectType *guard = new(alloc()) LGuardObjectType(useRegister(ins->obj()), tempObj);
+    if (!assignSnapshot(guard))
+        return false;
+    if (!add(guard, ins))
+        return false;
+    return redefine(ins, ins->obj());
+}
+
+bool
+LIRGeneratorMIPS::lowerUrshD(MUrsh *mir)
+{
+    MDefinition *lhs = mir->lhs();
+    MDefinition *rhs = mir->rhs();
+
+    MOZ_ASSERT(lhs->type() == MIRType_Int32);
+    MOZ_ASSERT(rhs->type() == MIRType_Int32);
+
+    LUrshD *lir = new(alloc()) LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp());
+    return define(lir, mir);
+}
+
+bool
+LIRGeneratorMIPS::visitAsmJSNeg(MAsmJSNeg *ins)
+{
+    if (ins->type() == MIRType_Int32)
+        return define(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins);
+
+    if (ins->type() == MIRType_Float32)
+    return define(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins);
+
+    MOZ_ASSERT(ins->type() == MIRType_Double);
+    return define(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins);
+}
+
+bool
+LIRGeneratorMIPS::lowerUDiv(MDiv *div)
+{
+    MDefinition *lhs = div->getOperand(0);
+    MDefinition *rhs = div->getOperand(1);
+
+    LUDiv *lir = new(alloc()) LUDiv;
+    lir->setOperand(0, useRegister(lhs));
+    lir->setOperand(1, useRegister(rhs));
+    if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
+        return false;
+
+    return define(lir, div);
+}
+
+bool
+LIRGeneratorMIPS::lowerUMod(MMod *mod)
+{
+    MDefinition *lhs = mod->getOperand(0);
+    MDefinition *rhs = mod->getOperand(1);
+
+    LUMod *lir = new(alloc()) LUMod;
+    lir->setOperand(0, useRegister(lhs));
+    lir->setOperand(1, useRegister(rhs));
+    if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
+        return false;
+
+    return define(lir, mod);
+}
+
+bool
+LIRGeneratorMIPS::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins)
+{
+    MOZ_ASSERT(ins->input()->type() == MIRType_Int32);
+    LAsmJSUInt32ToDouble *lir = new(alloc()) LAsmJSUInt32ToDouble(useRegisterAtStart(ins->input()));
+    return define(lir, ins);
+}
+
+bool
+LIRGeneratorMIPS::visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins)
+{
+    MOZ_ASSERT(ins->input()->type() == MIRType_Int32);
+    LAsmJSUInt32ToFloat32 *lir = new(alloc()) LAsmJSUInt32ToFloat32(useRegisterAtStart(ins->input()));
+    return define(lir, ins);
+}
+
+bool
+LIRGeneratorMIPS::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins)
+{
+    MDefinition *ptr = ins->ptr();
+    MOZ_ASSERT(ptr->type() == MIRType_Int32);
+    LAllocation ptrAlloc;
+
+    // For MIPS it is best to keep the 'ptr' in a register if a bounds check
+    // is needed.
+    if (ptr->isConstant() && ins->skipBoundsCheck()) {
+        int32_t ptrValue = ptr->toConstant()->value().toInt32();
+        // A bounds check is only skipped for a positive index.
+        MOZ_ASSERT(ptrValue >= 0);
+        ptrAlloc = LAllocation(ptr->toConstant()->vp());
+    } else
+        ptrAlloc = useRegisterAtStart(ptr);
+
+    return define(new(alloc()) LAsmJSLoadHeap(ptrAlloc), ins);
+}
+
+bool
+LIRGeneratorMIPS::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins)
+{
+    MDefinition *ptr = ins->ptr();
+    MOZ_ASSERT(ptr->type() == MIRType_Int32);
+    LAllocation ptrAlloc;
+
+    if (ptr->isConstant() && ins->skipBoundsCheck()) {
+        MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0);
+        ptrAlloc = LAllocation(ptr->toConstant()->vp());
+    } else
+        ptrAlloc = useRegisterAtStart(ptr);
+
+    return add(new(alloc()) LAsmJSStoreHeap(ptrAlloc, useRegisterAtStart(ins->value())), ins);
+}
+
+bool
+LIRGeneratorMIPS::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins)
+{
+    return define(new(alloc()) LAsmJSLoadFuncPtr(useRegister(ins->index()), temp()), ins);
+}
+
+bool
+LIRGeneratorMIPS::lowerTruncateDToInt32(MTruncateToInt32 *ins)
+{
+    MDefinition *opd = ins->input();
+    MOZ_ASSERT(opd->type() == MIRType_Double);
+
+    return define(new(alloc()) LTruncateDToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
+}
+
+bool
+LIRGeneratorMIPS::lowerTruncateFToInt32(MTruncateToInt32 *ins)
+{
+    MDefinition *opd = ins->input();
+    MOZ_ASSERT(opd->type() == MIRType_Float32);
+
+    return define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
+}
+
+bool
+LIRGeneratorMIPS::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins)
+{
+    MOZ_ASSUME_UNREACHABLE("NYI");
+}
+
+bool
+LIRGeneratorMIPS::visitForkJoinGetSlice(MForkJoinGetSlice *ins)
+{
+    MOZ_ASSUME_UNREACHABLE("NYI");
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit/mips/Lowering-mips.h
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_mips_Lowering_mips_h
+#define jit_mips_Lowering_mips_h
+
+#include "jit/shared/Lowering-shared.h"
+
+namespace js {
+namespace jit {
+
+class LIRGeneratorMIPS : public LIRGeneratorShared
+{
+  protected:
+    LIRGeneratorMIPS(MIRGenerator *gen, MIRGraph &graph, LIRGraph &lirGraph)
+      : LIRGeneratorShared(gen, graph, lirGraph)
+    { }
+
+  protected:
+    // Adds a box input to an instruction, setting operand |n| to the type and
+    // |n+1| to the payload.
+    bool useBox(LInstruction *lir, size_t n, MDefinition *mir,
+                LUse::Policy policy = LUse::REGISTER, bool useAtStart = false);
+    bool useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1, Register reg2);
+
+    // x86 has constraints on what registers can be formatted for 1-byte
+    // stores and loads; on MIPS all registers are okay.
+    LAllocation useByteOpRegister(MDefinition *mir);
+    LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition *mir);
+
+    inline LDefinition tempToUnbox() {
+        return LDefinition::BogusTemp();
+    }
+
+    // MIPS has a scratch register, so no need for another temp for dispatch
+    // ICs.
+    LDefinition tempForDispatchCache(MIRType outputType = MIRType_None) {
+        return LDefinition::BogusTemp();
+    }
+
+    void lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex);
+    bool defineUntypedPhi(MPhi *phi, size_t lirIndex);
+    bool lowerForShift(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir, MDefinition *lhs,
+                       MDefinition *rhs);
+    bool lowerUrshD(MUrsh *mir);
+
+    bool lowerForALU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir,
+                     MDefinition *input);
+    bool lowerForALU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
+                     MDefinition *lhs, MDefinition *rhs);
+
+    bool lowerForFPU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir,
+                     MDefinition *src);
+    bool lowerForFPU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
+                     MDefinition *lhs, MDefinition *rhs);
+    bool lowerForBitAndAndBranch(LBitAndAndBranch *baab, MInstruction *mir,
+                                 MDefinition *lhs, MDefinition *rhs);
+    bool lowerConstantDouble(double d, MInstruction *ins);
+    bool lowerConstantFloat32(float d, MInstruction *ins);
+    bool lowerTruncateDToInt32(MTruncateToInt32 *ins);
+    bool lowerTruncateFToInt32(MTruncateToInt32 *ins);
+    bool lowerDivI(MDiv *div);
+    bool lowerModI(MMod *mod);
+    bool lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs);
+    bool lowerUDiv(MDiv *div);
+    bool lowerUMod(MMod *mod);
+    bool visitPowHalf(MPowHalf *ins);
+    bool visitAsmJSNeg(MAsmJSNeg *ins);
+
+    LTableSwitch *newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
+                                  MTableSwitch *ins);
+    LTableSwitchV *newLTableSwitchV(MTableSwitch *ins);
+
+  public:
+    bool visitConstant(MConstant *ins);
+    bool visitBox(MBox *box);
+    bool visitUnbox(MUnbox *unbox);
+    bool visitReturn(MReturn *ret);
+    bool lowerPhi(MPhi *phi);
+    bool visitGuardShape(MGuardShape *ins);
+    bool visitGuardObjectType(MGuardObjectType *ins);
+    bool visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins);
+    bool visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins);
+    bool visitAsmJSLoadHeap(MAsmJSLoadHeap *ins);
+    bool visitAsmJSStoreHeap(MAsmJSStoreHeap *ins);
+    bool visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins);
+    bool visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins);
+    bool visitForkJoinGetSlice(MForkJoinGetSlice *ins);
+
+    static bool allowFloat32Optimizations() {
+        return true;
+    }
+};
+
+typedef LIRGeneratorMIPS LIRGeneratorSpecific;
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_mips_Lowering_mips_h */