Bug 1415772: Implement MNearbyInt recover instruction draft
authorJeff Hemphill <jthemphill@gmail.com>
Thu, 09 Nov 2017 20:33:02 -0800
changeset 696033 a678c880543329ba57ce993eda838fe2b967b04b
parent 695940 ed94dc665071d8d510688ff50bbedad2c7cb33ee
child 739769 7b47714f5135c7eb8c200c447f0d1c53addb9f24
push id88617
push userbmo:jthemphill@gmail.com
push dateFri, 10 Nov 2017 04:35:00 +0000
bugs1415772
milestone58.0a1
Bug 1415772: Implement MNearbyInt recover instruction MozReview-Commit-ID: D7JdEHjDl2W
js/src/jit-test/tests/ion/dce-with-rinstructions.js
js/src/jit-test/tests/ion/rinstructions-no-sse4.js
js/src/jit/MIR.h
js/src/jit/Recover.cpp
js/src/jit/Recover.h
--- a/js/src/jit-test/tests/ion/dce-with-rinstructions.js
+++ b/js/src/jit-test/tests/ion/dce-with-rinstructions.js
@@ -490,25 +490,43 @@ function rfloor_object(i) {
     var x = Math.floor(o);
     t = 1000.1111;
     if (uceFault_floor_object(i) || uceFault_floor_object(i))
         assertEq(x, i);
     assertRecoveredOnBailout(x, false);
     return i;
 }
 
+let uceFault_floor_double = eval(uneval(uceFault).replace('uceFault', 'uceFault_floor_double'));
+function rfloor_double(i) {
+    const x = Math.floor(i + (-1 >>> 0));
+    if (uceFault_floor_double(i) || uceFault_floor_double(i))
+        assertEq(x, 99 + (-1 >>> 0)); /* = i + 2 ^ 32 - 1 */
+    assertRecoveredOnBailout(x, true);
+    return i;
+}
+
 var uceFault_ceil_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_ceil_number'));
 function rceil_number(i) {
     var x = Math.ceil(-i - 0.12010799100);
     if (uceFault_ceil_number(i) || uceFault_ceil_number(i))
         assertEq(x, -i);
     assertRecoveredOnBailout(x, true);
     return i;
 }
 
+let uceFault_ceil_double = eval(uneval(uceFault).replace('uceFault', 'uceFault_ceil_double'));
+function rceil_double(i) {
+    const x = Math.floor(i + (-1 >>> 0));
+    if (uceFault_ceil_double(i) || uceFault_ceil_double(i))
+        assertEq(x, 99 + (-1 >>> 0)); /* = i + 2 ^ 32 - 1 */
+    assertRecoveredOnBailout(x, true);
+    return i;
+}
+
 var uceFault_round_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_round'));
 function rround_number(i) {
     var x = Math.round(i + 1.4);
     if (uceFault_round_number(i) || uceFault_round_number(i))
         assertEq(x, 100); /* = i + 1*/
     assertRecoveredOnBailout(x, true);
     return i;
 }
@@ -1386,18 +1404,20 @@ for (j = 100 - max; j < 100; j++) {
     rconcat_string(i);
     rconcat_number(i);
     rstring_length(i);
     rarguments_length_1(i);
     rarguments_length_3(i, 0, 1);
     rinline_arguments_length_1(i);
     rinline_arguments_length_3(i, 0, 1);
     rfloor_number(i);
+    rfloor_double(i);
     rfloor_object(i);
     rceil_number(i);
+    rceil_double(i);
     rround_number(i);
     rround_double(i);
     rcharCodeAt(i);
     rfrom_char_code(i);
     rfrom_char_code_non_ascii(i);
     rpow_number(i);
     rpow_object(i);
     rpowhalf_number(i);
--- a/js/src/jit-test/tests/ion/rinstructions-no-sse4.js
+++ b/js/src/jit-test/tests/ion/rinstructions-no-sse4.js
@@ -13,25 +13,38 @@ const max = 200;
 // of uceFault, and ensure that the bailout is correct when uceFault
 // is replaced (which cause an invalidation bailout)
 let uceFault = function (i) {
     if (i > 98)
         uceFault = function (i) { return true; };
     return false;
 };
 
+let uceFault_ceil_double = eval(
+    uneval(uceFault)
+        .replace('uceFault', 'uceFault_ceil_double')
+);
+function rceil_double(i) {
+    const x = Math.ceil(i + (-1 >>> 0));
+    if (uceFault_ceil_double(i) || uceFault_ceil_double(i))
+        assertEq(x, 99 + (-1 >>> 0)); /* = i + 2 ^ 32 - 1 */
+    assertRecoveredOnBailout(x, true);
+    return i;
+}
+
 let uceFault_floor_double = eval(
     uneval(uceFault)
         .replace('uceFault', 'uceFault_floor_double')
 );
 function rfloor_double(i) {
     const x = Math.floor(i + (-1 >>> 0));
     if (uceFault_floor_double(i) || uceFault_floor_double(i))
         assertEq(x, 99 + (-1 >>> 0)); /* = i + 2 ^ 32 - 1 */
     assertRecoveredOnBailout(x, true);
     return i;
 }
 
 for (let j = 100 - max; j < 100; j++) {
     with({}){} // Do not Ion-compile this loop.
     const i = j < 2 ? (Math.abs(j) % 50) + 2 : j;
+    rceil_double(i);
     rfloor_double(i);
 }
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -7012,16 +7012,17 @@ class MMathFunction
     void computeRange(TempAllocator& alloc) override;
     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
     bool canRecoverOnBailout() const override {
         if (input()->type() == MIRType::SinCosDouble)
             return false;
         switch(function_) {
           case Sin:
           case Log:
+          case Ceil:
           case Floor:
           case Round:
             return true;
           default:
             return false;
         }
     }
 
@@ -12618,16 +12619,28 @@ class MNearbyInt
 
     bool congruentTo(const MDefinition* ins) const override {
         return congruentIfOperandsEqual(ins) &&
                ins->toNearbyInt()->roundingMode() == roundingMode_;
     }
 
     void printOpcode(GenericPrinter& out) const override;
 
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+
+    bool canRecoverOnBailout() const override {
+        switch (roundingMode_) {
+          case RoundingMode::Up:
+          case RoundingMode::Down:
+            return true;
+          default:
+            return false;
+        }
+    }
+
     ALLOW_CLONE(MNearbyInt)
 };
 
 class MGetIteratorCache
   : public MUnaryInstruction,
     public BoxExceptPolicy<0, MIRType::Object>::Data
 {
     explicit MGetIteratorCache(MDefinition* val)
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -953,20 +953,50 @@ RHypot::recover(JSContext* cx, SnapshotI
     if(!js::math_hypot_handle(cx, vec, &result))
         return false;
 
     iter.storeInstructionResult(result);
     return true;
 }
 
 bool
+MNearbyInt::writeRecoverData(CompactBufferWriter& writer) const
+{
+    MOZ_ASSERT(canRecoverOnBailout());
+    switch (roundingMode_) {
+      case RoundingMode::Up:
+        writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));
+        return true;
+      case RoundingMode::Down:
+        writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));
+        return true;
+      default:
+        MOZ_CRASH("Unsupported rounding mode.");
+    }
+}
+
+RNearbyInt::RNearbyInt(CompactBufferReader& reader)
+{
+    roundingMode_ = reader.readByte();
+}
+
+bool
+RNearbyInt::recover(JSContext* cx, SnapshotIterator& iter) const
+{
+    MOZ_CRASH("Unsupported rounding mode.");
+}
+
+bool
 MMathFunction::writeRecoverData(CompactBufferWriter& writer) const
 {
     MOZ_ASSERT(canRecoverOnBailout());
     switch (function_) {
+      case Ceil:
+        writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));
+        return true;
       case Floor:
         writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));
         return true;
       case Round:
         writer.writeUnsigned(uint32_t(RInstruction::Recover_Round));
         return true;
       case Sin:
       case Log:
--- a/js/src/jit/Recover.h
+++ b/js/src/jit/Recover.h
@@ -82,16 +82,17 @@ namespace jit {
     _(FromCharCode)                             \
     _(Pow)                                      \
     _(PowHalf)                                  \
     _(MinMax)                                   \
     _(Abs)                                      \
     _(Sqrt)                                     \
     _(Atan2)                                    \
     _(Hypot)                                    \
+    _(NearbyInt)                                \
     _(MathFunction)                             \
     _(Random)                                   \
     _(StringSplit)                              \
     _(NaNToZero)                                \
     _(RegExpMatcher)                            \
     _(RegExpSearcher)                           \
     _(RegExpTester)                             \
     _(StringReplace)                            \
@@ -461,16 +462,27 @@ class RHypot final : public RInstruction
 
      uint32_t numOperands() const override {
          return numOperands_;
      }
 
      MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override;
 };
 
+class RNearbyInt final : public RInstruction
+{
+  private:
+    uint8_t roundingMode_;
+
+  public:
+    RINSTRUCTION_HEADER_NUM_OP_(NearbyInt, 1)
+
+    MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override;
+};
+
 class RMathFunction final : public RInstruction
 {
   private:
     uint8_t function_;
 
   public:
     RINSTRUCTION_HEADER_NUM_OP_(MathFunction, 1)