Implement JSOP_SUB (bug 685695, r=sstangl).
authorDavid Anderson <danderson@mozilla.com>
Thu, 08 Sep 2011 18:01:21 -0700
changeset 105247 4129e39cffcdc7a690ef76307f51e8c3a6701c7f
parent 105246 ab38a3d96333092b9356bb53cc2b03297cf22c8e
child 105248 9738af4a0433ebfa4ef573c814be3ff7c5112c0f
push id14706
push usereakhgari@mozilla.com
push dateTue, 11 Sep 2012 20:39:52 +0000
treeherdermozilla-inbound@d50bf1edaabe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstangl
bugs685695
milestone9.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
Implement JSOP_SUB (bug 685695, r=sstangl).
js/src/ion/IonBuilder.cpp
js/src/ion/LIR-Common.h
js/src/ion/LOpcodes.h
js/src/ion/Lowering.cpp
js/src/ion/Lowering.h
js/src/ion/MIR.cpp
js/src/ion/MIR.h
js/src/ion/MOpcodes.h
js/src/ion/shared/Assembler-x86-shared.h
js/src/ion/shared/CodeGenerator-x86-shared.cpp
js/src/ion/shared/CodeGenerator-x86-shared.h
js/src/jit-test/tests/ion/testSubtract.js
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -363,16 +363,17 @@ IonBuilder::inspectOpcode(JSOp op)
       case JSOP_BITOR:
       case JSOP_BITXOR:
       case JSOP_LSH:
       case JSOP_RSH:
       case JSOP_URSH:
         return jsop_bitop(op);
 
       case JSOP_ADD:
+      case JSOP_SUB:
       case JSOP_MUL:
       	return jsop_binary(op);
 
       case JSOP_NEG:
         return jsop_neg();
 
       case JSOP_LOCALINC:
       case JSOP_INCLOCAL:
@@ -1600,16 +1601,20 @@ IonBuilder::jsop_binary(JSOp op)
     MDefinition *left = current->pop();
 
     MBinaryArithInstruction *ins;
     switch (op) {
       case JSOP_ADD:
         ins = MAdd::New(left, right);
         break;
 
+      case JSOP_SUB:
+        ins = MSub::New(left, right);
+        break;
+
       case JSOP_MUL:
         ins = MMul::New(left, right);
         break;
 
       default:
         JS_NOT_REACHED("unexpected binary opcode");
         return false;
     }
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -511,42 +511,64 @@ class LShiftOp : public LInstructionHelp
 // Returns from the function being compiled (not used in inlined frames). The
 // input must be a box.
 class LReturn : public LInstructionHelper<0, BOX_PIECES, 0>
 {
   public:
     LIR_HEADER(Return);
 };
 
+template <size_t Temps>
+class LBinaryMath : public LInstructionHelper<1, 2, Temps>
+{
+  public:
+    const LAllocation *lhs() {
+        return this->getOperand(0);
+    }
+    const LAllocation *rhs() {
+        return this->getOperand(1);
+    }
+    const LDefinition *output() {
+        return this->getDef(0);
+    }
+};
+
 // Adds two integers, returning an integer value.
-class LAddI : public LInstructionHelper<1, 2, 0>
+class LAddI : public LBinaryMath<0>
 {
   public:
     LIR_HEADER(AddI);
 };
 
+// Subtracts two integers, returning an integer value.
+class LSubI : public LBinaryMath<0>
+{
+  public:
+    LIR_HEADER(SubI);
+};
+
 // Adds two integers, returning an integer value.
-class LMulI : public LInstructionHelper<1, 2, 0>
+class LMulI : public LBinaryMath<0>
 {
     MMul *mir_;
 
   public:
     LIR_HEADER(MulI);
 
     LMulI(MMul *mir)
       : mir_(mir)
     { }
 
     MMul *mir() {
         return mir_;
     }
 };
 
 // Performs an add, sub, mul, or div on two double values.
-class LMathD : public LInstructionHelper<1, 2, 0>
+class LMathD : public LBinaryMath<0>
 {
     JSOp jsop_;
 
   public:
     LIR_HEADER(MathD);
 
     LMathD(JSOp jsop)
       : jsop_(jsop)
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -61,16 +61,17 @@
     _(TestIAndBranch)               \
     _(TestDAndBranch)               \
     _(TestVAndBranch)               \
     _(CompareI)                     \
     _(CompareD)                     \
     _(CompareIAndBranch)            \
     _(CompareDAndBranch)            \
     _(AddI)                         \
+    _(SubI)                         \
     _(MulI)                         \
     _(MathD)                        \
     _(Int32ToDouble)                \
     _(ValueToDouble)                \
     _(ValueToInt32)                 \
     _(TruncateDToInt32)
 
 #if defined(JS_CPU_X86)
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -363,21 +363,44 @@ LIRGenerator::visitAdd(MAdd *ins)
         return lowerForFPU(new LMathD(JSOP_ADD), ins, lhs, rhs);
     }
 
     JS_NOT_REACHED("NYI");
     return false;
 }
 
 bool
+LIRGenerator::visitSub(MSub *ins)
+{
+    MDefinition *lhs = ins->lhs();
+    MDefinition *rhs = ins->rhs();
+
+    JS_ASSERT(lhs->type() == rhs->type());
+
+    if (ins->specialization() == MIRType_Int32) {
+        JS_ASSERT(lhs->type() == MIRType_Int32);
+        LSubI *lir = new LSubI;
+        if (!assignSnapshot(lir))
+            return false;
+        return lowerForALU(lir, ins, lhs, rhs);
+    }
+    if (ins->specialization() == MIRType_Double) {
+        JS_ASSERT(lhs->type() == MIRType_Double);
+        return lowerForFPU(new LMathD(JSOP_SUB), ins, lhs, rhs);
+    }
+
+    JS_NOT_REACHED("NYI");
+    return false;
+}
+
+bool
 LIRGenerator::visitMul(MMul *ins)
 {
-    MDefinition *lhs = ins->getOperand(0);
-    MDefinition *rhs = ins->getOperand(1);
-
+    MDefinition *lhs = ins->lhs();
+    MDefinition *rhs = ins->rhs();
     JS_ASSERT(lhs->type() == rhs->type());
 
     if (ins->specialization() == MIRType_Int32) {
         JS_ASSERT(lhs->type() == MIRType_Int32);
         ReorderCommutative(&lhs, &rhs);
         LMulI *lir = new LMulI(ins);
         if (ins->fallible() && !assignSnapshot(lir))
             return false;
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -112,16 +112,17 @@ class LIRGenerator : public LIRGenerator
     bool visitBitNot(MBitNot *ins);
     bool visitBitAnd(MBitAnd *ins);
     bool visitBitOr(MBitOr *ins);
     bool visitBitXor(MBitXor *ins);
     bool visitLsh(MLsh *ins);
     bool visitRsh(MRsh *ins);
     bool visitUrsh(MUrsh *ins);
     bool visitAdd(MAdd *ins);
+    bool visitSub(MSub *ins);
     bool visitMul(MMul *ins);
     bool visitStart(MStart *start);
     bool visitToDouble(MToDouble *convert);
     bool visitToInt32(MToInt32 *convert);
     bool visitTruncateToInt32(MTruncateToInt32 *truncate);
     bool visitCopy(MCopy *ins);
 };
 
--- a/js/src/ion/MIR.cpp
+++ b/js/src/ion/MIR.cpp
@@ -79,46 +79,49 @@ EvaluateConstantOperands(MBinaryInstruct
     if (!left->isConstant() || !right->isConstant())
         return NULL;
 
     js::Value lhs = left->toConstant()->value();
     js::Value rhs = right->toConstant()->value();
     js::Value ret;
 
     switch(ins->op()) {
-        case MDefinition::Op_BitAnd:
-            ret = Int32Value(lhs.toInt32() & rhs.toInt32());
-            break;
-        case MDefinition::Op_BitOr:
-            ret = Int32Value(lhs.toInt32() | rhs.toInt32());
-            break;
-        case MDefinition::Op_BitXor:
-            ret = Int32Value(lhs.toInt32() ^ rhs.toInt32());
-            break;
-        case MDefinition::Op_Lsh:
-            ret = Int32Value(lhs.toInt32() << (rhs.toInt32() & 0x1F));
-            break;
-        case MDefinition::Op_Rsh:
-            ret = Int32Value(lhs.toInt32() >> (rhs.toInt32() & 0x1F));
-            break;
-        case MDefinition::Op_Ursh: {
-            if (lhs.toInt32() < 0 && rhs.toInt32() == 0)
-                return NULL;
-            uint32 unsignedLhs = (uint32_t)lhs.toInt32();
-            ret = Int32Value(uint32(unsignedLhs >> (rhs.toInt32() & 0x1F)));
-            break;
-        }
-        case MDefinition::Op_Add:
-            ret.setNumber(lhs.toNumber() + rhs.toNumber());
-            break;
-        case MDefinition::Op_Mul:
-            ret.setNumber(lhs.toNumber() * rhs.toNumber());
-            break;
-        default:
-            JS_NOT_REACHED("NYI");
+      case MDefinition::Op_BitAnd:
+        ret = Int32Value(lhs.toInt32() & rhs.toInt32());
+        break;
+      case MDefinition::Op_BitOr:
+        ret = Int32Value(lhs.toInt32() | rhs.toInt32());
+        break;
+      case MDefinition::Op_BitXor:
+        ret = Int32Value(lhs.toInt32() ^ rhs.toInt32());
+        break;
+      case MDefinition::Op_Lsh:
+        ret = Int32Value(lhs.toInt32() << (rhs.toInt32() & 0x1F));
+        break;
+      case MDefinition::Op_Rsh:
+        ret = Int32Value(lhs.toInt32() >> (rhs.toInt32() & 0x1F));
+        break;
+      case MDefinition::Op_Ursh: {
+        if (lhs.toInt32() < 0 && rhs.toInt32() == 0)
+            return NULL;
+        uint32 unsignedLhs = (uint32_t)lhs.toInt32();
+        ret = Int32Value(uint32(unsignedLhs >> (rhs.toInt32() & 0x1F)));
+        break;
+      }
+      case MDefinition::Op_Add:
+        ret.setNumber(lhs.toNumber() + rhs.toNumber());
+        break;
+      case MDefinition::Op_Sub:
+        ret.setNumber(lhs.toNumber() - rhs.toNumber());
+        break;
+      case MDefinition::Op_Mul:
+        ret.setNumber(lhs.toNumber() * rhs.toNumber());
+        break;
+      default:
+        JS_NOT_REACHED("NYI");
     }
 
     if (ins->type() != MIRTypeFromValue(ret))
         return NULL;
 
     return MConstant::New(ret);
 }
 
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -1344,16 +1344,22 @@ class MBinaryArithInstruction
     { }
 
     TypePolicy *typePolicy() {
         return this;
     }
     MIRType specialization() const {
         return specialization_;
     }
+    MDefinition *lhs() const {
+        return getOperand(0);
+    }
+    MDefinition *rhs() const {
+        return getOperand(1);
+    }
 
     MDefinition *foldsTo(bool useValueNumbers);
 
     virtual double getIdentity() = 0;
 
     void infer(const TypeOracle::Binary &b);
 };
 
@@ -1371,16 +1377,35 @@ class MAdd : public MBinaryArithInstruct
         return new MAdd(left, right);
     }
 
     double getIdentity() {
         return 0;
     }
 };
 
+class MSub : public MBinaryArithInstruction
+{
+    MSub(MDefinition *left, MDefinition *right)
+      : MBinaryArithInstruction(left, right)
+    {
+        setResultType(MIRType_Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(Sub);
+    static MSub *New(MDefinition *left, MDefinition *right) {
+        return new MSub(left, right);
+    }
+
+    double getIdentity() {
+        return 0;
+    }
+};
+
 class MMul : public MBinaryArithInstruction
 {
     bool canOverflow_;
     bool canBeNegativeZero_;
 
     MMul(MDefinition *left, MDefinition *right)
       : MBinaryArithInstruction(left, right),
         canOverflow_(true),
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -60,16 +60,17 @@ namespace ion {
     _(BitNot)                                                               \
     _(BitAnd)                                                               \
     _(BitOr)                                                                \
     _(BitXor)                                                               \
     _(Lsh)                                                                  \
     _(Rsh)                                                                  \
     _(Ursh)                                                                 \
     _(Add)                                                                  \
+    _(Sub)                                                                  \
     _(Mul)                                                                  \
     _(Return)                                                               \
     _(Copy)                                                                 \
     _(Box)                                                                  \
     _(Unbox)                                                                \
     _(ToDouble)                                                             \
     _(ToInt32)                                                              \
     _(TruncateToInt32)                                                      \
--- a/js/src/ion/shared/Assembler-x86-shared.h
+++ b/js/src/ion/shared/Assembler-x86-shared.h
@@ -700,16 +700,19 @@ class AssemblerX86Shared
         masm.movd_rr(src.code(), dest.code());
     }
     void movd(const FloatRegister &src, const Register &dest) {
         masm.movd_rr(src.code(), dest.code());
     }
     void addsd(const FloatRegister &src, const FloatRegister &dest) {
         masm.addsd_rr(src.code(), dest.code());
     }
+    void subsd(const FloatRegister &src, const FloatRegister &dest) {
+        masm.subsd_rr(src.code(), dest.code());
+    }
     void mulsd(const FloatRegister &src, const FloatRegister &dest) {
         masm.mulsd_rr(src.code(), dest.code());
     }
     void xorpd(const FloatRegister &src, const FloatRegister &dest) {
         masm.xorpd_rr(src.code(), dest.code());
     }
 };
 
--- a/js/src/ion/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.cpp
@@ -357,35 +357,44 @@ CodeGeneratorX86Shared::visitOutOfLineBa
     masm.push(Imm32(ool->snapshot()->snapshotOffset()));
     masm.jmp(deoptLabel_);
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitAddI(LAddI *ins)
 {
-    const LAllocation *lhs = ins->getOperand(0);
-    const LAllocation *rhs = ins->getOperand(1);
-
-    if (rhs->isConstant())
-        masm.addl(Imm32(ToInt32(rhs)), ToOperand(lhs));
+    if (ins->rhs()->isConstant())
+        masm.addl(Imm32(ToInt32(ins->rhs())), ToOperand(ins->lhs()));
     else
-        masm.addl(ToOperand(rhs), ToRegister(lhs));
+        masm.addl(ToOperand(ins->rhs()), ToRegister(ins->lhs()));
 
     if (ins->snapshot() && !bailoutIf(Assembler::Overflow, ins->snapshot()))
         return false;
+    return true;
+}
 
+bool
+CodeGeneratorX86Shared::visitSubI(LSubI *ins)
+{
+    if (ins->rhs()->isConstant())
+        masm.subl(Imm32(ToInt32(ins->rhs())), ToOperand(ins->lhs()));
+    else
+        masm.subl(ToOperand(ins->rhs()), ToRegister(ins->lhs()));
+
+    if (ins->snapshot() && !bailoutIf(Assembler::Overflow, ins->snapshot()))
+        return false;
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitMulI(LMulI *ins)
 {
-    const LAllocation *lhs = ins->getOperand(0);
-    const LAllocation *rhs = ins->getOperand(1);
+    const LAllocation *lhs = ins->lhs();
+    const LAllocation *rhs = ins->rhs();
     MMul *mul = ins->mir();
 
     if (rhs->isConstant()) {
         // Bailout on -0.0
         int32 constant = ToInt32(rhs);
         if (mul->canBeNegativeZero() && constant <= 0) {
             Assembler::Condition bailoutCond = (constant == 0) ? Assembler::Signed : Assembler::Equal;
             masm.testl(ToRegister(lhs), ToRegister(lhs));
@@ -714,16 +723,19 @@ CodeGeneratorX86Shared::visitMathD(LMath
 {
     const LAllocation *input = math->getOperand(1);
     const LDefinition *output = math->getDef(0);
 
     switch (math->jsop()) {
       case JSOP_ADD:
         masm.addsd(ToFloatRegister(input), ToFloatRegister(output));
         break;
+      case JSOP_SUB:
+        masm.subsd(ToFloatRegister(input), ToFloatRegister(output));
+        break;
       case JSOP_MUL:
         masm.mulsd(ToFloatRegister(input), ToFloatRegister(output));
         break;
       default:
         JS_NOT_REACHED("unexpected opcode");
         return false;
     }
     return true;
--- a/js/src/ion/shared/CodeGenerator-x86-shared.h
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.h
@@ -101,16 +101,17 @@ class CodeGeneratorX86Shared : public Co
 
   public:
     CodeGeneratorX86Shared(MIRGenerator *gen, LIRGraph &graph);
 
   public:
     // Instruction visitors.
     virtual bool visitGoto(LGoto *jump);
     virtual bool visitAddI(LAddI *ins);
+    virtual bool visitSubI(LSubI *ins);
     virtual bool visitMulI(LMulI *ins);
     virtual bool visitBitNot(LBitNot *ins);
     virtual bool visitBitOp(LBitOp *ins);
     virtual bool visitShiftOp(LShiftOp *ins);
     virtual bool visitMoveGroup(LMoveGroup *group);
     virtual bool visitInteger(LInteger *ins);
     virtual bool visitTestIAndBranch(LTestIAndBranch *test);
     virtual bool visitTestDAndBranch(LTestDAndBranch *test);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/testSubtract.js
@@ -0,0 +1,20 @@
+// vim: set ts=4 sw=4 tw=99 et:
+function f_int(x, y) {
+    return x - y;
+}
+function f_double(x, y) {
+    return x - y;
+}
+
+for (var i = 0; i < 1000; i++) {
+    assertEq(f_int(5, 3), 2);
+    assertEq(f_int(3, 5), -2);
+    assertEq(f_int(-2147483648, 1), -2147483649);
+}
+
+
+for (var i = 0; i < 1000; i++) {
+    assertEq(f_double(5.5, 3.2), 2.3);
+    assertEq(f_double(2.5, 3.0), -0.5);
+}
+