Bug 1640587 part 4 - Add Int32 specialization for MPow. r=anba
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 04 Jun 2020 09:29:32 +0000
changeset 597936 b4e9103ffa2e9523c606a01e10258d0efeaca15c
parent 597935 0294692dcbe0bea7bdcea59dea95c4cad8a5a385
child 597937 b445193d595b01e3351441d54019bdd9950ba541
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)
reviewersanba
bugs1640587, 1564942
milestone79.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 1640587 part 4 - Add Int32 specialization for MPow. r=anba Code mostly written by André Bargull for bug 1564942. Differential Revision: https://phabricator.services.mozilla.com/D77778
js/src/jit/CodeGenerator.cpp
js/src/jit/Lowering.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/shared/LIR-shared.h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -8424,16 +8424,28 @@ void CodeGenerator::visitAbsD(LAbsD* ins
 
 void CodeGenerator::visitAbsF(LAbsF* ins) {
   FloatRegister input = ToFloatRegister(ins->input());
   MOZ_ASSERT(input == ToFloatRegister(ins->output()));
 
   masm.absFloat32(input, input);
 }
 
+void CodeGenerator::visitPowII(LPowII* ins) {
+  Register value = ToRegister(ins->value());
+  Register power = ToRegister(ins->power());
+  Register output = ToRegister(ins->output());
+  Register temp1 = ToRegister(ins->temp1());
+  Register temp2 = ToRegister(ins->temp2());
+
+  Label bailout;
+  masm.pow32(value, power, output, temp1, temp2, &bailout);
+  bailoutFrom(&bailout, ins->snapshot());
+}
+
 void CodeGenerator::visitPowI(LPowI* ins) {
   FloatRegister value = ToFloatRegister(ins->value());
   Register power = ToRegister(ins->power());
   Register temp = ToRegister(ins->temp());
 
   MOZ_ASSERT(power != temp);
 
   masm.setupUnalignedABICall(temp);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1520,16 +1520,27 @@ void LIRGenerator::visitHypot(MHypot* in
 
   defineReturn(lir, ins);
 }
 
 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);
+
+    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);
   MOZ_ASSERT(input->type() == MIRType::Double);
   MOZ_ASSERT(power->type() == MIRType::Int32 ||
              power->type() == MIRType::Double);
 
   LInstruction* lir;
   if (power->type() == MIRType::Int32) {
     // Note: useRegisterAtStart here is safe, the temp is a GP register so
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2953,40 +2953,63 @@ MDefinition* MMinMax::foldsTo(TempAlloca
     }
   }
 
   return this;
 }
 
 MDefinition* MPow::foldsConstant(TempAllocator& alloc) {
   // Both `x` and `p` in `x^p` must be constants in order to precompute.
-  if (!(input()->isConstant() && power()->isConstant())) return nullptr;
-  if (!power()->toConstant()->isTypeRepresentableAsDouble()) return nullptr;
-  if (!input()->toConstant()->isTypeRepresentableAsDouble()) return nullptr;
+  if (!input()->isConstant() || !power()->isConstant()) {
+    return nullptr;
+  }
+  if (!power()->toConstant()->isTypeRepresentableAsDouble()) {
+    return nullptr;
+  }
+  if (!input()->toConstant()->isTypeRepresentableAsDouble()) {
+    return nullptr;
+  }
 
   double x = input()->toConstant()->numberToDouble();
   double p = power()->toConstant()->numberToDouble();
-  return MConstant::New(alloc, DoubleValue(js::ecmaPow(x, p)));
+  double result = js::ecmaPow(x, p);
+  if (type() == MIRType::Int32) {
+    int32_t cast;
+    if (!mozilla::NumberIsInt32(result, &cast)) {
+      // Reject folding if the result isn't an int32, because we'll bail anyway.
+      return nullptr;
+    }
+    return MConstant::New(alloc, Int32Value(cast));
+  }
+  return MConstant::New(alloc, DoubleValue(result));
 }
 
 MDefinition* MPow::foldsConstantPower(TempAllocator& alloc) {
   // If `p` in `x^p` isn't constant, we can't apply these folds.
-  if (!power()->isConstant()) return nullptr;
-  if (!power()->toConstant()->isTypeRepresentableAsDouble()) return nullptr;
+  if (!power()->isConstant()) {
+    return nullptr;
+  }
+  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.
   if (pow == -0.5) {
+    MOZ_ASSERT(type() == MIRType::Double);
     MPowHalf* half = MPowHalf::New(alloc, input());
     block()->insertBefore(this, half);
     MConstant* one = MConstant::New(alloc, DoubleValue(1.0));
     block()->insertBefore(this, one);
     return MDiv::New(alloc, one, half, MIRType::Double);
   }
 
   // Math.pow(x, 1) == x.
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -5201,17 +5201,17 @@ class MPow : public MBinaryInstruction, 
 
   bool congruentTo(const MDefinition* ins) const override {
     if (!ins->isPow() || ins->toPow()->powerIsInt32() != powerIsInt32()) {
       return false;
     }
     return congruentIfOperandsEqual(ins);
   }
   AliasSet getAliasSet() const override { return AliasSet::None(); }
-  bool possiblyCalls() const override { return true; }
+  bool possiblyCalls() const override { return type() != MIRType::Int32; }
   MOZ_MUST_USE bool writeRecoverData(
       CompactBufferWriter& writer) const override;
   bool canRecoverOnBailout() const override { return true; }
 
   MDefinition* foldsTo(TempAllocator& alloc) override;
 
   ALLOW_CLONE(MPow)
 };
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -2478,16 +2478,37 @@ class LPowI : public LCallInstructionHel
     setTemp(0, temp);
   }
 
   const LAllocation* value() { return getOperand(0); }
   const LAllocation* power() { return getOperand(1); }
   const LDefinition* temp() { return getTemp(0); }
 };
 
+// Integer raised to an integer power.
+class LPowII : public LInstructionHelper<1, 2, 2> {
+ public:
+  LIR_HEADER(PowII)
+  LPowII(const LAllocation& value, const LAllocation& power,
+         const LDefinition& temp1, const LDefinition& temp2)
+      : LInstructionHelper(classOpcode) {
+    setOperand(0, value);
+    setOperand(1, power);
+    setTemp(0, temp1);
+    setTemp(1, temp2);
+  }
+
+  const LAllocation* value() { return getOperand(0); }
+  const LAllocation* power() { return getOperand(1); }
+  const LDefinition* temp1() { return getTemp(0); }
+  const LDefinition* temp2() { return getTemp(1); }
+
+  MPow* mir() const { return mir_->toPow(); }
+};
+
 // Double raised to a double power.
 class LPowD : public LCallInstructionHelper<1, 2, 1> {
  public:
   LIR_HEADER(PowD)
   LPowD(const LAllocation& value, const LAllocation& power,
         const LDefinition& temp)
       : LCallInstructionHelper(classOpcode) {
     setOperand(0, value);