Bug 1073576 - Optimize strict compares with equal operands. r=h4writer
authorTom Schuster <evilpies@gmail.com>
Sun, 05 Oct 2014 15:26:40 +0200
changeset 233430 e5d631abcd562d12ec5112d81bf2d28d1599e8f5
parent 233429 a80a2d8bbd47ba91063cacd50c0ed20e1c2c603a
child 233432 0ca09645655e6e2c534b49a2a5bb61777b87bd34
push id611
push userraliiev@mozilla.com
push dateMon, 05 Jan 2015 23:23:16 +0000
treeherdermozilla-release@345cd3b9c445 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs1073576
milestone35.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 1073576 - Optimize strict compares with equal operands. r=h4writer
js/src/jit-test/tests/basic/strict-compare-same-operands.js
js/src/jit/MIR.cpp
js/src/jit/MIR.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/strict-compare-same-operands.js
@@ -0,0 +1,49 @@
+function f(l, m) {
+    var a = NaN;
+    var b = 13;
+    var c = "test";
+    var d = undefined;
+    var e = null;
+    var f = 15.7;
+    var g = Math.fround(189777.111);
+    var h = "ABC";
+    var i = String.fromCharCode(65, 65, 65);
+    var j = {};
+    var k = Math.fround("".charCodeAt(15));
+
+    // Special case rigt here:
+    assertEq(a === a, false);
+    assertEq(a !== a, true);
+    assertEq(k === k, false);
+    assertEq(k !== k, true);
+    assertEq(l === l, false);
+    assertEq(l !== l, true);
+
+    assertEq(b === b, true);
+    assertEq(b !== b, false);
+    assertEq(c === c, true);
+    assertEq(c !== c, false);
+    assertEq(d === d, true);
+    assertEq(d !== d, false);
+    assertEq(e === e, true);
+    assertEq(e !== e, false);
+    assertEq(f === f, true);
+    assertEq(f !== f, false);
+    assertEq(g === g, true);
+    assertEq(g !== g, false);
+    assertEq(h === h, true);
+    assertEq(h !== h, false);
+    assertEq(i === i, true);
+    assertEq(i !== i, false);
+    assertEq(j === j, true);
+    assertEq(j !== j, false);
+    assertEq(m === m, true);
+    assertEq(m !== m, false);
+}
+
+function test() {
+    for (var i = 0; i < 100; i++)
+        f("".charCodeAt(15), 42);
+}
+
+test();
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2834,20 +2834,59 @@ MClampToUint8::foldsTo(TempAllocator &al
             int32_t clamped = ClampIntForUint8Array(v.toInt32());
             return MConstant::New(alloc, Int32Value(clamped));
         }
     }
     return this;
 }
 
 bool
+MCompare::tryFoldEqualOperands(bool *result)
+{
+    if (lhs() != rhs())
+        return false;
+
+    // Intuitively somebody would think that if lhs == rhs,
+    // then we can just return true. (Or false for !==)
+    // However NaN !== NaN is true! So we spend some time trying
+    // to eliminate this case.
+
+    if (jsop() != JSOP_STRICTEQ && jsop() != JSOP_STRICTNE)
+        return false;
+
+    if (compareType_ == Compare_Unknown)
+        return false;
+
+    MOZ_ASSERT(compareType_ == Compare_Undefined || compareType_ == Compare_Null ||
+               compareType_ == Compare_Boolean || compareType_ == Compare_Int32 ||
+               compareType_ == Compare_Int32MaybeCoerceBoth ||
+               compareType_ == Compare_Int32MaybeCoerceLHS ||
+               compareType_ == Compare_Int32MaybeCoerceRHS || compareType_ == Compare_UInt32 ||
+               compareType_ == Compare_Double || compareType_ == Compare_DoubleMaybeCoerceLHS ||
+               compareType_ == Compare_DoubleMaybeCoerceRHS || compareType_ == Compare_Float32 ||
+               compareType_ == Compare_String || compareType_ == Compare_StrictString ||
+               compareType_ == Compare_Object || compareType_ == Compare_Value);
+
+    if (isDoubleComparison() || isFloat32Comparison()) {
+        if (!operandsAreNeverNaN())
+            return false;
+    }
+
+    *result = (jsop() == JSOP_STRICTEQ);
+    return true;
+}
+
+bool
 MCompare::tryFold(bool *result)
 {
     JSOp op = jsop();
 
+    if (tryFoldEqualOperands(result))
+        return true;
+
     if (compareType_ == Compare_Null || compareType_ == Compare_Undefined) {
         MOZ_ASSERT(op == JSOP_EQ || op == JSOP_STRICTEQ ||
                    op == JSOP_NE || op == JSOP_STRICTNE);
 
         // The LHS is the value we want to test against null or undefined.
         switch (lhs()->type()) {
           case MIRType_Value:
             return false;
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -3468,16 +3468,18 @@ class MCompare
         // Both sides of the compare can be Float32
         return compareType_ == Compare_Float32;
     }
 # endif
 
     ALLOW_CLONE(MCompare)
 
   protected:
+    bool tryFoldEqualOperands(bool *result);
+
     bool congruentTo(const MDefinition *ins) const {
         if (!binaryCongruentTo(ins))
             return false;
         return compareType() == ins->toCompare()->compareType() &&
                jsop() == ins->toCompare()->jsop();
     }
 };