Bug 1640587 part 3 - Refactor MPow type policy. r=anba
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 04 Jun 2020 09:29:19 +0000
changeset 597935 0294692dcbe0bea7bdcea59dea95c4cad8a5a385
parent 597934 1654b08e4fbd02c966fdc5d368505f46beef0a6e
child 597936 b4e9103ffa2e9523c606a01e10258d0efeaca15c
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
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 3 - Refactor MPow type policy. r=anba Remove the specialization_ field and the powerType use. Use the return type instead. For now we only use the Double specialization, although this already adds the TypePolicy code for Int32 specialization. Differential Revision: https://phabricator.services.mozilla.com/D77777
js/src/jit/IonBuilder.cpp
js/src/jit/Lowering.cpp
js/src/jit/MIR.h
js/src/jit/TypePolicy.cpp
js/src/jit/TypePolicy.h
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -3600,21 +3600,17 @@ AbortReasonOr<Ok> IonBuilder::powTrySpec
   }
   if (!IsNumberType(baseType)) {
     return Ok();
   }
   if (!IsNumberType(powerType)) {
     return Ok();
   }
 
-  if (powerType == MIRType::Float32) {
-    powerType = MIRType::Double;
-  }
-
-  MPow* pow = MPow::New(alloc(), base, power, powerType);
+  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);
     current->add(toInt);
     output = toInt;
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1520,16 +1520,17 @@ void LIRGenerator::visitHypot(MHypot* in
 
   defineReturn(lir, ins);
 }
 
 void LIRGenerator::visitPow(MPow* ins) {
   MDefinition* input = ins->input();
   MDefinition* power = ins->power();
 
+  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
     // it will never get the same register.
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -5168,35 +5168,46 @@ class MHypot : public MVariadicInstructi
   MInstruction* clone(TempAllocator& alloc,
                       const MDefinitionVector& inputs) const override {
     return MHypot::New(alloc, inputs);
   }
 };
 
 // Inline implementation of Math.pow().
 class MPow : public MBinaryInstruction, public PowPolicy::Data {
-  MPow(MDefinition* input, MDefinition* power, MIRType powerType)
-      : MBinaryInstruction(classOpcode, input, power) {
-    MOZ_ASSERT(powerType == MIRType::Double || powerType == MIRType::Int32);
-    specialization_ = powerType;
-    setResultType(MIRType::Double);
+  // 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_;
+
+  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();
   }
 
   // Helpers for `foldsTo`
   MDefinition* foldsConstant(TempAllocator& alloc);
   MDefinition* foldsConstantPower(TempAllocator& alloc);
 
  public:
   INSTRUCTION_HEADER(Pow)
   TRIVIAL_NEW_WRAPPERS
 
   MDefinition* input() const { return lhs(); }
   MDefinition* power() const { return rhs(); }
-  bool congruentTo(const MDefinition* ins) const override {
+  bool powerIsInt32() const { return powerIsInt32_; }
+
+  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; }
   MOZ_MUST_USE bool writeRecoverData(
       CompactBufferWriter& writer) const override;
   bool canRecoverOnBailout() const override { return true; }
 
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -417,36 +417,37 @@ bool BitwisePolicy::adjustInputs(TempAll
       return false;
     }
   }
 
   return true;
 }
 
 bool PowPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const {
-  MIRType specialization = ins->typePolicySpecialization();
-  MOZ_ASSERT(specialization == MIRType::Int32 ||
-             specialization == MIRType::Double ||
-             specialization == MIRType::None);
+  MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::Double);
 
-  // Inputs will be boxed if either is non-numeric.
-  if (specialization == MIRType::None) {
-    return BoxInputsPolicy::staticAdjustInputs(alloc, ins);
+  if (ins->type() == MIRType::Int32) {
+    // Both operands must be int32.
+    return UnboxedInt32Policy<0>::staticAdjustInputs(alloc, ins) &&
+           UnboxedInt32Policy<1>::staticAdjustInputs(alloc, ins);
   }
 
   // Otherwise, input must be a double.
   if (!DoublePolicy<0>::staticAdjustInputs(alloc, ins)) {
     return false;
   }
 
   // Power may be an int32 or a double. Integers receive a faster path.
-  if (specialization == MIRType::Double) {
-    return DoublePolicy<1>::staticAdjustInputs(alloc, ins);
+  if (ins->toPow()->power()->type() == MIRType::Int32) {
+    return true;
   }
-  return UnboxedInt32Policy<1>::staticAdjustInputs(alloc, ins);
+  if (ins->toPow()->powerIsInt32()) {
+    return UnboxedInt32Policy<1>::staticAdjustInputs(alloc, ins);
+  }
+  return DoublePolicy<1>::staticAdjustInputs(alloc, ins);
 }
 
 bool SignPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const {
   MOZ_ASSERT(ins->isSign());
   MIRType specialization = ins->typePolicySpecialization();
 
   // MSign is specialized for int32 input types.
   if (specialization == MIRType::Int32) {
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -141,21 +141,25 @@ class TypeBarrierPolicy final : public T
 class CallPolicy final : public TypePolicy {
  public:
   constexpr CallPolicy() = default;
   EMPTY_DATA_;
   MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc,
                                  MInstruction* def) const override;
 };
 
-// Policy for MPow. First operand Double; second Double or Int32.
+// Policy for MPow:
+//
+// * If return type is MIRType::Double, we need (Double, Double) or
+//   (Double, Int32) operands.
+// * If return type is MIRType::Int32, we need (Int32, Int32) operands.
 class PowPolicy final : public TypePolicy {
  public:
   constexpr PowPolicy() = default;
-  SPECIALIZATION_DATA_;
+  EMPTY_DATA_;
   MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc,
                                  MInstruction* ins) const override;
 };
 
 // Policy for MSign. Operand is either Double or Int32.
 class SignPolicy final : public TypePolicy {
  public:
   constexpr SignPolicy() = default;