Backed out 4 changesets (bug 1564942) for causing SM bustage in pow-base-power-of-two.js CLOSED TREE
authorNoemi Erli <nerli@mozilla.com>
Tue, 09 Jun 2020 22:39:08 +0300
changeset 598836 b2df79a80c0303df9d710800ae37dce56847eef5
parent 598835 e8d01bb9df0e3ccdb1c881aae5529ef86c6a230c
child 598837 5a00363d2a4aac7cf407225adcdb8268839b7885
push id13310
push userffxbld-merge
push dateMon, 29 Jun 2020 14:50:06 +0000
treeherdermozilla-beta@15a59a0afa5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1564942
milestone79.0a1
backs outed869f61d92437944115e25abe6deecd2d4ce07a
cee3bb0132911d6944471973719c9eb2af52c397
91d3f5dc57c9b174d75be3a2ceab99ee1567fbb5
0017d61a5a0f1299d4c1f421f73ab7315650f93e
first release with
nightly linux32
b2df79a80c03 / 79.0a1 / 20200610043607 / files
nightly linux64
b2df79a80c03 / 79.0a1 / 20200610043607 / files
nightly mac
b2df79a80c03 / 79.0a1 / 20200610043607 / files
nightly win32
b2df79a80c03 / 79.0a1 / 20200610043607 / files
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
Backed out 4 changesets (bug 1564942) for causing SM bustage in pow-base-power-of-two.js CLOSED TREE Backed out changeset ed869f61d924 (bug 1564942) Backed out changeset cee3bb013291 (bug 1564942) Backed out changeset 91d3f5dc57c9 (bug 1564942) Backed out changeset 0017d61a5a0f (bug 1564942)
js/src/jit-test/tests/ion/pow-base-power-of-two-bailouts.js
js/src/jit-test/tests/ion/pow-base-power-of-two.js
js/src/jit-test/tests/ion/pow-constant-power.js
js/src/jit/CodeGenerator.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/Lowering.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/arm/Lowering-arm.cpp
js/src/jit/arm/Lowering-arm.h
js/src/jit/arm64/Lowering-arm64.cpp
js/src/jit/arm64/Lowering-arm64.h
js/src/jit/mips-shared/Lowering-mips-shared.cpp
js/src/jit/mips-shared/Lowering-mips-shared.h
js/src/jit/none/Lowering-none.h
js/src/jit/shared/LIR-shared.h
js/src/jit/x86-shared/Lowering-x86-shared.cpp
js/src/jit/x86-shared/Lowering-x86-shared.h
deleted file mode 100644
--- a/js/src/jit-test/tests/ion/pow-base-power-of-two-bailouts.js
+++ /dev/null
@@ -1,85 +0,0 @@
-// Lowering provides a specialisation when the base operand is a constant which
-// is a power of two.
-//
-// Test bailout conditions for this optimisation.
-
-function test(x) {
-    function pow(x, y) { return `Math.pow(${x}, ${y})` };
-    function exp(x, y) { return `((${x}) ** ${y})` };
-
-    function make(fn) {
-        return Function("y, z", `
-            // Load from array to prevent constant-folding.
-            // (Ion is currently not smart enough to realise that both array
-            // values are the same.)
-            var ys = [y, y];
-            var zs = [z, z];
-            for (var i = 0; i < 1000; ++i) {
-                assertEq(${fn(x, "ys[i & 1]")}, zs[i & 1]);
-            }
-        `);
-    }
-
-    function double(v) {
-        // NB: Math.cbrt() always returns a double value.
-        return Math.cbrt(v * v * v)
-    }
-
-    // Find the first power which will exceed the Int32 range by computing ⌈log_x(2 ^ 31)⌉.
-    var limit = Math.ceil(Math.log2(2 ** 31) / Math.log2(x));
-    assertEq(Math.pow(x, limit - 1) < 2 ** 31, true);
-    assertEq(Math.pow(x, limit) >= 2 ** 31, true);
-
-    function* args(first, last) {
-        // Run the test function a few times without a bailout.
-        for (var i = 0; i < 3; ++i) {
-            yield first;
-        }
-
-        // |last| should trigger a bailout.
-        yield last;
-    }
-
-    // Test precision loss when the result exceeds 2**31.
-    for (var fn of [make(pow), make(exp)]) {
-        for (var y of args(limit - 1, limit)) {
-            // Ensure the callee always sees a double to avoid an early Bailout_ArgumentCheck.
-            var z = double(Math.pow(x, y));
-            fn(y, z);
-        }
-    }
-
-    // Test precision loss when the result is a fractional number.
-    for (var fn of [make(pow), make(exp)]) {
-        for (var y of args(0, -1)) {
-            // Ensure the callee always sees a double to avoid an early Bailout_ArgumentCheck.
-            var z = double(Math.pow(x, y));
-            fn(y, z);
-        }
-    }
-
-    // Find the first negative power which can be represented as a double
-    var negLimit = -Math.floor(1074 / Math.log2(x));
-
-    // Test precision loss when the result is a non-zero, fractional number.
-    for (var fn of [make(pow), make(exp)]) {
-        for (var y of args(limit - 1, limit)) {
-            // Ensure the callee always sees a double to avoid an early Bailout_ArgumentCheck.
-            var z = double(Math.pow(x, y));
-            fn(y, z);
-        }
-    }
-}
-
-function* range(a, b, fn) {
-    for (var i = a; i <= b; ++i) {
-        yield fn(i);
-    }
-}
-
-// Only 2^i with |i| ∈ {1..8} currently triggers the optimisation, but also test
-// the next power-of-two values.
-
-for (var x of range(1, 10, i => 2 ** i)) {
-    test(x);
-}
deleted file mode 100644
--- a/js/src/jit-test/tests/ion/pow-base-power-of-two.js
+++ /dev/null
@@ -1,73 +0,0 @@
-// Lowering provides a specialisation when the base operand is a constant which
-// is a power of two.
-
-function test(x, y, z) {
-    function pow(x, y) { return `Math.pow(${x}, ${y})` };
-    function exp(x, y) { return `((${x}) ** ${y})` };
-
-    function make(fn, x, y, z) {
-        return Function(`
-            // Load from array to prevent constant-folding.
-            // (Ion is currently not smart enough to realise that both array
-            // values are the same.)
-            var ys = [${y}, ${y}];
-            var zs = [${z}, ${z}];
-            for (var i = 0; i < 1000; ++i) {
-                assertEq(${fn(x, "ys[i & 1]")}, zs[i & 1]);
-            }
-        `);
-    }
-
-    function double(v) {
-        // NB: Math.cbrt() always returns a double value.
-        return `Math.cbrt(${v * v * v})`;
-    }
-
-    function addTests(fn) {
-        tests.push(make(fn, x, y, z));
-        tests.push(make(fn, x, double(y), z));
-        tests.push(make(fn, double(x), y, z));
-        tests.push(make(fn, double(x), double(y), z));
-    }
-
-    var tests = [];
-    addTests(pow);
-    addTests(exp);
-
-    for (var i = 0; i < tests.length; ++i) {
-        for (var j = 0; j < 2; ++j) {
-            tests[i]();
-        }
-    }
-}
-
-function* range(a, b, fn) {
-    for (var i = a; i <= b; ++i) {
-        yield fn(i);
-    }
-}
-
-// Only 2^i with |i| ∈ {1..8} currently triggers the optimisation, but also test
-// the next power-of-two values, 1 and 0, and negative base-of-two values.
-var values = [
-    ...range(1, 10, i => 2 ** i),
-    1,
-    0,
-    ...range(1, 4, i => -(2 ** i)),
-];
-
-for (var x of values) {
-    test(x, 0, 1);
-    test(x, 1, x);
-    test(x, 2, x * x);
-
-    // 0**(negative) is Infinity, 1**(negative) is 1.
-    if (Math.abs(x) > 1) {
-        test(x, -1076, 0);
-    }
-
-    // (negative)**(odd-negative) is -0.
-    if (x > 1) {
-        test(x, -1075, 0);
-    }
-}
deleted file mode 100644
--- a/js/src/jit-test/tests/ion/pow-constant-power.js
+++ /dev/null
@@ -1,68 +0,0 @@
-// Ion provides specialisations when Math.pow() resp. the **-operator is used
-// with a constant power of one of [-0.5, 0.5, 1, 2, 3, 4].
-
-function test(x, y, z) {
-    function pow(x, y) { return `Math.pow(${x}, ${y})` };
-    function exp(x, y) { return `((${x}) ** ${y})` };
-
-    function make(fn, x, y, z) {
-        return Function(`
-            // Load from array to prevent constant-folding.
-            // (Ion is currently not smart enough to realise that both array
-            // values are the same.)
-            var xs = [${x}, ${x}];
-            var zs = [${z}, ${z}];
-            for (var i = 0; i < 1000; ++i) {
-                assertEq(${fn("xs[i & 1]", y)}, zs[i & 1]);
-            }
-        `);
-    }
-
-    function double(v) {
-        // NB: Math.cbrt() always returns a double value.
-        return `Math.cbrt(${v * v * v})`;
-    }
-
-    function addTests(fn) {
-        tests.push(make(fn, x, y, z));
-        tests.push(make(fn, x, double(y), z));
-        tests.push(make(fn, double(x), y, z));
-        tests.push(make(fn, double(x), double(y), z));
-    }
-
-    var tests = [];
-    addTests(pow);
-    addTests(exp);
-
-    for (var i = 0; i < tests.length; ++i) {
-        for (var j = 0; j < 2; ++j) {
-            tests[i]();
-        }
-    }
-}
-
-// Make sure the tests below test int32 and double return values.
-
-// Math.pow(x, -0.5)
-test( 1, -0.5, 1);
-test(16, -0.5, 0.25);
-
-// Math.pow(x, 0.5)
-test(16, 0.5, 4);
-test( 2, 0.5, Math.SQRT2);
-
-// Math.pow(x, 1)
-test(5,   1, 5);
-test(0.5, 1, 0.5);
-
-// Math.pow(x, 2)
-test(5,   2, 25);
-test(0.5, 2, 0.25);
-
-// Math.pow(x, 3)
-test(5,   3, 125);
-test(0.5, 3, 0.125);
-
-// Math.pow(x, 3)
-test(5,   4, 625);
-test(0.5, 4, 0.0625);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -8260,49 +8260,16 @@ void CodeGenerator::visitPowD(LPowD* ins
   masm.setupUnalignedABICall(temp);
   masm.passABIArg(value, MoveOp::DOUBLE);
   masm.passABIArg(power, MoveOp::DOUBLE);
   masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ecmaPow), MoveOp::DOUBLE);
 
   MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
 }
 
-void CodeGenerator::visitPowOfTwoI(LPowOfTwoI* ins) {
-  Register power = ToRegister(ins->power());
-  Register output = ToRegister(ins->output());
-
-  uint32_t base = ins->base();
-  MOZ_ASSERT(mozilla::IsPowerOfTwo(base));
-
-  uint32_t n = mozilla::FloorLog2(base);
-  MOZ_ASSERT(n != 0);
-
-  // Hacker's Delight, 2nd edition, theorem D2.
-  auto ceilingDiv = [](uint32_t x, uint32_t y) { return (x + y - 1) / y; };
-
-  // Take bailout if |power| is greater-or-equals |log_y(2^31)| or is negative.
-  // |2^(n*y) < 2^31| must hold, hence |n*y < 31| resp. |y < 31/n|.
-  //
-  // Note: it's important for this condition to match the code in CacheIR.cpp
-  // (CanAttachInt32Pow) to prevent failure loops.
-  bailoutCmp32(Assembler::AboveOrEqual, power, Imm32(ceilingDiv(31, n)),
-               ins->snapshot());
-
-  // Compute (2^n)^y as 2^(n*y) using repeated shifts. We could directly scale
-  // |power| and perform a single shift, but due to the lack of necessary
-  // MacroAssembler functionality, like multiplying a register with an
-  // immediate, we restrict the number of generated shift instructions when
-  // lowering this operation.
-  masm.move32(Imm32(1), output);
-  do {
-    masm.lshift32(power, output);
-    n--;
-  } while (n > 0);
-}
-
 void CodeGenerator::visitSqrtD(LSqrtD* ins) {
   FloatRegister input = ToFloatRegister(ins->input());
   FloatRegister output = ToFloatRegister(ins->output());
   masm.sqrtDouble(input, output);
 }
 
 void CodeGenerator::visitSqrtF(LSqrtF* ins) {
   FloatRegister input = ToFloatRegister(ins->input());
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -3607,17 +3607,16 @@ AbortReasonOr<Ok> IonBuilder::powTrySpec
 
   MPow* pow = MPow::New(alloc(), base, power, MIRType::Double);
   current->add(pow);
   output = pow;
 
   // Cast to the right type
   if (outputType == MIRType::Int32 && output->type() != MIRType::Int32) {
     auto* toInt = MToNumberInt32::New(alloc(), output);
-    toInt->setCanBeNegativeZero(pow->canBeNegativeZero());
     current->add(toInt);
     output = toInt;
   }
   if (outputType == MIRType::Double && output->type() != MIRType::Double) {
     MToDouble* toDouble = MToDouble::New(alloc(), output);
     current->add(toDouble);
     output = toDouble;
   }
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3,17 +3,16 @@
  * 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 "jit/Lowering.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/EndianUtils.h"
-#include "mozilla/MathAlgorithms.h"
 
 #include <type_traits>
 
 #include "jit/JitSpewer.h"
 #include "jit/LIR.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
 #include "util/Memory.h"
@@ -1528,26 +1527,16 @@ void LIRGenerator::visitHypot(MHypot* in
 void LIRGenerator::visitPow(MPow* ins) {
   MDefinition* input = ins->input();
   MDefinition* power = ins->power();
 
   if (ins->type() == MIRType::Int32) {
     MOZ_ASSERT(input->type() == MIRType::Int32);
     MOZ_ASSERT(power->type() == MIRType::Int32);
 
-    if (input->isConstant()) {
-      // Restrict this optimization to |base <= 256| to avoid generating too
-      // many consecutive shift instructions.
-      int32_t base = input->toConstant()->toInt32();
-      if (2 <= base && base <= 256 && mozilla::IsPowerOfTwo(uint32_t(base))) {
-        lowerPowOfTwoI(ins);
-        return;
-      }
-    }
-
     auto* lir = new (alloc())
         LPowII(useRegister(input), useRegister(power), temp(), temp());
     assignSnapshot(lir, Bailout_PrecisionLoss);
     define(lir, ins);
     return;
   }
 
   MOZ_ASSERT(ins->type() == MIRType::Double);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2989,16 +2989,17 @@ MDefinition* MPow::foldsConstantPower(Te
   }
   if (!power()->toConstant()->isTypeRepresentableAsDouble()) {
     return nullptr;
   }
 
   MOZ_ASSERT(type() == MIRType::Double || type() == MIRType::Int32);
 
   double pow = power()->toConstant()->numberToDouble();
+  MIRType outputType = type();
 
   // Math.pow(x, 0.5) is a sqrt with edge-case detection.
   if (pow == 0.5) {
     MOZ_ASSERT(type() == MIRType::Double);
     return MPowHalf::New(alloc, input());
   }
 
   // Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5), even for edge cases.
@@ -3011,54 +3012,42 @@ MDefinition* MPow::foldsConstantPower(Te
     return MDiv::New(alloc, one, half, MIRType::Double);
   }
 
   // Math.pow(x, 1) == x.
   if (pow == 1.0) {
     return input();
   }
 
-  auto multiply = [this, &alloc](MDefinition* lhs, MDefinition* rhs) {
-    MMul* mul = MMul::New(alloc, lhs, rhs, type());
-
-    // Multiplying the same number can't yield negative zero.
-    mul->setCanBeNegativeZero(lhs != rhs && canBeNegativeZero());
-    return mul;
-  };
-
   // Math.pow(x, 2) == x*x.
   if (pow == 2.0) {
-    return multiply(input(), input());
+    return MMul::New(alloc, input(), input(), outputType);
   }
 
   // Math.pow(x, 3) == x*x*x.
   if (pow == 3.0) {
-    MMul* mul1 = multiply(input(), input());
+    MMul* mul1 = MMul::New(alloc, input(), input(), outputType);
     block()->insertBefore(this, mul1);
-    return multiply(input(), mul1);
+    return MMul::New(alloc, input(), mul1, outputType);
   }
 
   // Math.pow(x, 4) == y*y, where y = x*x.
   if (pow == 4.0) {
-    MMul* y = multiply(input(), input());
+    MMul* y = MMul::New(alloc, input(), input(), outputType);
     block()->insertBefore(this, y);
-    return multiply(y, y);
+    return MMul::New(alloc, y, y, outputType);
   }
 
   // No optimization
   return nullptr;
 }
 
 MDefinition* MPow::foldsTo(TempAllocator& alloc) {
-  if (MDefinition* def = foldsConstant(alloc)) {
-    return def;
-  }
-  if (MDefinition* def = foldsConstantPower(alloc)) {
-    return def;
-  }
+  if (MDefinition* def = foldsConstant(alloc)) return def;
+  if (MDefinition* def = foldsConstantPower(alloc)) return def;
   return this;
 }
 
 bool MAbs::fallible() const {
   return !implicitTruncate_ && (!range() || !range()->hasInt32Bounds());
 }
 
 void MAbs::trySpecializeFloat32(TempAllocator& alloc) {
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -5169,47 +5169,29 @@ class MHypot : public MVariadicInstructi
 
   MInstruction* clone(TempAllocator& alloc,
                       const MDefinitionVector& inputs) const override {
     return MHypot::New(alloc, inputs);
   }
 };
 
 // Inline implementation of Math.pow().
-//
-// Supports the following three specializations:
-//
-// 1. MPow(FloatingPoint, FloatingPoint) -> Double
-//   - The most general mode, calls js::ecmaPow.
-//   - Never performs a bailout.
-// 2. MPow(FloatingPoint, Int32) -> Double
-//   - Optimization to call js::powi instead of js::ecmaPow.
-//   - Never performs a bailout.
-// 3. MPow(Int32, Int32) -> Int32
-//   - Performs the complete exponentiation operation in assembly code.
-//   - Bails out if the result doesn't fit in Int32.
 class MPow : public MBinaryInstruction, public PowPolicy::Data {
   // If true, convert the power operand to int32 instead of double (this only
   // affects the Double specialization). This exists because we can sometimes
   // get more precise types during MIR building than in type analysis.
-  bool powerIsInt32_ : 1;
-
-  // If true, the result is guaranteed to never be negative zero.
-  bool canBeNegativeZero_ : 1;
+  bool powerIsInt32_;
 
   MPow(MDefinition* input, MDefinition* power, MIRType specialization)
       : MBinaryInstruction(classOpcode, input, power),
         powerIsInt32_(power->type() == MIRType::Int32) {
     MOZ_ASSERT(specialization == MIRType::Int32 ||
                specialization == MIRType::Double);
     setResultType(specialization);
     setMovable();
-
-    // The result can't be negative zero if the base is an Int32 value.
-    canBeNegativeZero_ = input->type() != MIRType::Int32;
   }
 
   // Helpers for `foldsTo`
   MDefinition* foldsConstant(TempAllocator& alloc);
   MDefinition* foldsConstantPower(TempAllocator& alloc);
 
  public:
   INSTRUCTION_HEADER(Pow)
@@ -5225,17 +5207,16 @@ class MPow : public MBinaryInstruction, 
     }
     return congruentIfOperandsEqual(ins);
   }
   AliasSet getAliasSet() const override { return AliasSet::None(); }
   bool possiblyCalls() const override { return type() != MIRType::Int32; }
   MOZ_MUST_USE bool writeRecoverData(
       CompactBufferWriter& writer) const override;
   bool canRecoverOnBailout() const override { return true; }
-  bool canBeNegativeZero() const { return canBeNegativeZero_; }
 
   MDefinition* foldsTo(TempAllocator& alloc) override;
 
   ALLOW_CLONE(MPow)
 };
 
 // Inline implementation of Math.pow(x, 0.5), which subtly differs from
 // Math.sqrt(x).
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -466,25 +466,16 @@ void LIRGeneratorARM::lowerUrshD(MUrsh* 
   MOZ_ASSERT(lhs->type() == MIRType::Int32);
   MOZ_ASSERT(rhs->type() == MIRType::Int32);
 
   LUrshD* lir = new (alloc())
       LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp());
   define(lir, mir);
 }
 
-void LIRGeneratorARM::lowerPowOfTwoI(MPow* mir) {
-  int32_t base = mir->input()->toConstant()->toInt32();
-  MDefinition* power = mir->power();
-
-  auto* lir = new (alloc()) LPowOfTwoI(base, useRegister(power));
-  assignSnapshot(lir, Bailout_PrecisionLoss);
-  define(lir, mir);
-}
-
 void LIRGenerator::visitWasmNeg(MWasmNeg* ins) {
   if (ins->type() == MIRType::Int32) {
     define(new (alloc()) LNegI(useRegisterAtStart(ins->input())), ins);
   } else if (ins->type() == MIRType::Float32) {
     define(new (alloc()) LNegF(useRegisterAtStart(ins->input())), ins);
   } else {
     MOZ_ASSERT(ins->type() == MIRType::Double);
     define(new (alloc()) LNegD(useRegisterAtStart(ins->input())), ins);
--- a/js/src/jit/arm/Lowering-arm.h
+++ b/js/src/jit/arm/Lowering-arm.h
@@ -37,18 +37,16 @@ class LIRGeneratorARM : public LIRGenera
   void lowerInt64PhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block,
                           size_t lirIndex);
   void defineInt64Phi(MPhi* phi, size_t lirIndex);
 
   void lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
                      MDefinition* lhs, MDefinition* rhs);
   void lowerUrshD(MUrsh* mir);
 
-  void lowerPowOfTwoI(MPow* mir);
-
   void lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
                    MDefinition* input);
   void lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
                    MDefinition* lhs, MDefinition* rhs);
 
   void lowerForALUInt64(
       LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins,
       MDefinition* mir, MDefinition* lhs, MDefinition* rhs);
--- a/js/src/jit/arm64/Lowering-arm64.cpp
+++ b/js/src/jit/arm64/Lowering-arm64.cpp
@@ -309,25 +309,16 @@ void LIRGeneratorARM64::lowerUrshD(MUrsh
   MOZ_ASSERT(lhs->type() == MIRType::Int32);
   MOZ_ASSERT(rhs->type() == MIRType::Int32);
 
   LUrshD* lir = new (alloc())
       LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp());
   define(lir, mir);
 }
 
-void LIRGeneratorARM64::lowerPowOfTwoI(MPow* mir) {
-  int32_t base = mir->input()->toConstant()->toInt32();
-  MDefinition* power = mir->power();
-
-  auto* lir = new (alloc()) LPowOfTwoI(base, useRegister(power));
-  assignSnapshot(lir, Bailout_PrecisionLoss);
-  define(lir, mir);
-}
-
 void LIRGenerator::visitWasmNeg(MWasmNeg* ins) {
   switch (ins->type()) {
     case MIRType::Int32:
       define(new (alloc()) LNegI(useRegisterAtStart(ins->input())), ins);
       break;
     case MIRType::Float32:
       define(new (alloc()) LNegF(useRegisterAtStart(ins->input())), ins);
       break;
--- a/js/src/jit/arm64/Lowering-arm64.h
+++ b/js/src/jit/arm64/Lowering-arm64.h
@@ -39,18 +39,16 @@ class LIRGeneratorARM64 : public LIRGene
   void lowerInt64PhiInput(MPhi*, uint32_t, LBlock*, size_t) {
     MOZ_CRASH("NYI");
   }
   void defineInt64Phi(MPhi*, size_t) { MOZ_CRASH("NYI"); }
   void lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
                      MDefinition* lhs, MDefinition* rhs);
   void lowerUrshD(MUrsh* mir);
 
-  void lowerPowOfTwoI(MPow* mir);
-
   void lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
                    MDefinition* input);
   void lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
                    MDefinition* lhs, MDefinition* rhs);
 
   void lowerForALUInt64(
       LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins,
       MDefinition* mir, MDefinition* lhs, MDefinition* rhs);
--- a/js/src/jit/mips-shared/Lowering-mips-shared.cpp
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.cpp
@@ -297,25 +297,16 @@ void LIRGeneratorMIPSShared::lowerUrshD(
   MOZ_ASSERT(lhs->type() == MIRType::Int32);
   MOZ_ASSERT(rhs->type() == MIRType::Int32);
 
   LUrshD* lir = new (alloc())
       LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp());
   define(lir, mir);
 }
 
-void LIRGeneratorMIPSShared::lowerPowOfTwoI(MPow* mir) {
-  int32_t base = mir->input()->toConstant()->toInt32();
-  MDefinition* power = mir->power();
-
-  auto* lir = new (alloc()) LPowOfTwoI(base, useRegister(power));
-  assignSnapshot(lir, Bailout_PrecisionLoss);
-  define(lir, mir);
-}
-
 void LIRGenerator::visitWasmNeg(MWasmNeg* ins) {
   if (ins->type() == MIRType::Int32) {
     define(new (alloc()) LNegI(useRegisterAtStart(ins->input())), ins);
   } else if (ins->type() == MIRType::Float32) {
     define(new (alloc()) LNegF(useRegisterAtStart(ins->input())), ins);
   } else {
     MOZ_ASSERT(ins->type() == MIRType::Double);
     define(new (alloc()) LNegD(useRegisterAtStart(ins->input())), ins);
--- a/js/src/jit/mips-shared/Lowering-mips-shared.h
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.h
@@ -25,18 +25,16 @@ class LIRGeneratorMIPSShared : public LI
   LDefinition tempByteOpRegister();
 
   bool needTempForPostBarrier() { return false; }
 
   void lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
                      MDefinition* lhs, MDefinition* rhs);
   void lowerUrshD(MUrsh* mir);
 
-  void lowerPowOfTwoI(MPow* mir);
-
   void lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
                    MDefinition* input);
   void lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
                    MDefinition* lhs, MDefinition* rhs);
 
   void lowerForALUInt64(
       LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins,
       MDefinition* mir, MDefinition* lhs, MDefinition* rhs);
--- a/js/src/jit/none/Lowering-none.h
+++ b/js/src/jit/none/Lowering-none.h
@@ -35,17 +35,16 @@ class LIRGeneratorNone : public LIRGener
   void lowerUntypedPhiInput(MPhi*, uint32_t, LBlock*, size_t) { MOZ_CRASH(); }
   void lowerInt64PhiInput(MPhi*, uint32_t, LBlock*, size_t) { MOZ_CRASH(); }
   void defineInt64Phi(MPhi*, size_t) { MOZ_CRASH(); }
   void lowerForShift(LInstructionHelper<1, 2, 0>*, MDefinition*, MDefinition*,
                      MDefinition*) {
     MOZ_CRASH();
   }
   void lowerUrshD(MUrsh*) { MOZ_CRASH(); }
-  void lowerPowOfTwoI(MPow*) { MOZ_CRASH(); }
   template <typename T>
   void lowerForALU(T, MDefinition*, MDefinition*, MDefinition* v = nullptr) {
     MOZ_CRASH();
   }
   template <typename T>
   void lowerForFPU(T, MDefinition*, MDefinition*, MDefinition* v = nullptr) {
     MOZ_CRASH();
   }
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -2516,31 +2516,16 @@ class LPowD : public LCallInstructionHel
     setTemp(0, temp);
   }
 
   const LAllocation* value() { return getOperand(0); }
   const LAllocation* power() { return getOperand(1); }
   const LDefinition* temp() { return getTemp(0); }
 };
 
-// Constant of a power of two raised to an integer power.
-class LPowOfTwoI : public LInstructionHelper<1, 1, 0> {
-  uint32_t base_;
-
- public:
-  LIR_HEADER(PowOfTwoI)
-  LPowOfTwoI(uint32_t base, const LAllocation& power)
-      : LInstructionHelper(classOpcode), base_(base) {
-    setOperand(0, power);
-  }
-
-  uint32_t base() const { return base_; }
-  const LAllocation* power() { return getOperand(0); }
-};
-
 // Sign value of an integer.
 class LSignI : public LInstructionHelper<1, 1, 0> {
  public:
   LIR_HEADER(SignI)
   explicit LSignI(const LAllocation& input) : LInstructionHelper(classOpcode) {
     setOperand(0, input);
   }
 };
--- a/js/src/jit/x86-shared/Lowering-x86-shared.cpp
+++ b/js/src/jit/x86-shared/Lowering-x86-shared.cpp
@@ -145,19 +145,18 @@ void LIRGeneratorX86Shared::lowerForBitA
   baab->setOperand(1, useRegisterOrConstantAtStart(rhs));
   add(baab, mir);
 }
 
 void LIRGeneratorX86Shared::lowerMulI(MMul* mul, MDefinition* lhs,
                                       MDefinition* rhs) {
   // Note: If we need a negative zero check, lhs is used twice.
   LAllocation lhsCopy = mul->canBeNegativeZero() ? use(lhs) : LAllocation();
-  LMulI* lir = new (alloc()) LMulI(
-      useRegisterAtStart(lhs),
-      lhs != rhs ? useOrConstant(rhs) : useOrConstantAtStart(rhs), lhsCopy);
+  LMulI* lir =
+      new (alloc()) LMulI(useRegisterAtStart(lhs), useOrConstant(rhs), lhsCopy);
   if (mul->fallible()) {
     assignSnapshot(lir, Bailout_DoubleOutput);
   }
   defineReuseInput(lir, mul, 0);
 }
 
 void LIRGeneratorX86Shared::lowerDivI(MDiv* div) {
   if (div->isUnsigned()) {
@@ -434,27 +433,16 @@ void LIRGeneratorX86Shared::lowerUrshD(M
   LUse lhsUse = useRegisterAtStart(lhs);
   LAllocation rhsAlloc =
       rhs->isConstant() ? useOrConstant(rhs) : useFixed(rhs, ecx);
 
   LUrshD* lir = new (alloc()) LUrshD(lhsUse, rhsAlloc, tempCopy(lhs, 0));
   define(lir, mir);
 }
 
-void LIRGeneratorX86Shared::lowerPowOfTwoI(MPow* mir) {
-  int32_t base = mir->input()->toConstant()->toInt32();
-  MDefinition* power = mir->power();
-
-  // shift operator should be in register ecx;
-  // x86 can't shift a non-ecx register.
-  auto* lir = new (alloc()) LPowOfTwoI(base, useFixed(power, ecx));
-  assignSnapshot(lir, Bailout_PrecisionLoss);
-  define(lir, mir);
-}
-
 void LIRGeneratorX86Shared::lowerTruncateDToInt32(MTruncateToInt32* ins) {
   MDefinition* opd = ins->input();
   MOZ_ASSERT(opd->type() == MIRType::Double);
 
   LDefinition maybeTemp =
       Assembler::HasSSE3() ? LDefinition::BogusTemp() : tempDouble();
   define(new (alloc()) LTruncateDToInt32(useRegister(opd), maybeTemp), ins);
 }
--- a/js/src/jit/x86-shared/Lowering-x86-shared.h
+++ b/js/src/jit/x86-shared/Lowering-x86-shared.h
@@ -40,17 +40,16 @@ class LIRGeneratorX86Shared : public LIR
   void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir,
                                MDefinition* lhs, MDefinition* rhs);
   void lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs);
   void lowerDivI(MDiv* div);
   void lowerModI(MMod* mod);
   void lowerUDiv(MDiv* div);
   void lowerUMod(MMod* mod);
   void lowerUrshD(MUrsh* mir);
-  void lowerPowOfTwoI(MPow* mir);
   void lowerTruncateDToInt32(MTruncateToInt32* ins);
   void lowerTruncateFToInt32(MTruncateToInt32* ins);
   void lowerCompareExchangeTypedArrayElement(
       MCompareExchangeTypedArrayElement* ins, bool useI386ByteRegisters);
   void lowerAtomicExchangeTypedArrayElement(
       MAtomicExchangeTypedArrayElement* ins, bool useI386ByteRegisters);
   void lowerAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins,
                                          bool useI386ByteRegisters);