Revision: 12265
Author:   [email protected]
Date:     Mon Aug  6 07:28:27 2012
Log:      Refactor Math.min/max to be a single HInstruction.

That allows us to dynamically compute representations and insert appropriate HChange instructions.

Review URL: https://chromiumcodereview.appspot.com/10829169
http://code.google.com/p/v8/source/detail?r=12265

Modified:
 /branches/bleeding_edge/src/arm/lithium-arm.cc
 /branches/bleeding_edge/src/arm/lithium-arm.h
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/arm/simulator-arm.cc
 /branches/bleeding_edge/src/arm/simulator-arm.h
 /branches/bleeding_edge/src/hydrogen-instructions.cc
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/ia32/assembler-ia32.cc
 /branches/bleeding_edge/src/ia32/assembler-ia32.h
 /branches/bleeding_edge/src/ia32/disasm-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-ia32.h
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-x64.cc
 /branches/bleeding_edge/src/x64/lithium-x64.h

=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc      Mon Aug  6 07:13:09 2012
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc      Mon Aug  6 07:28:27 2012
@@ -1357,6 +1357,25 @@
     return DoArithmeticT(Token::ADD, instr);
   }
 }
+
+
+LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
+  LOperand* left = NULL;
+  LOperand* right = NULL;
+  if (instr->representation().IsInteger32()) {
+    ASSERT(instr->left()->representation().IsInteger32());
+    ASSERT(instr->right()->representation().IsInteger32());
+    left = UseRegisterAtStart(instr->LeastConstantOperand());
+    right = UseOrConstantAtStart(instr->MostConstantOperand());
+  } else {
+    ASSERT(instr->representation().IsDouble());
+    ASSERT(instr->left()->representation().IsDouble());
+    ASSERT(instr->right()->representation().IsDouble());
+    left = UseRegisterAtStart(instr->left());
+    right = UseRegisterAtStart(instr->right());
+  }
+  return DefineAsRegister(new(zone()) LMathMinMax(left, right));
+}


 LInstruction* LChunkBuilder::DoPower(HPower* instr) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.h       Mon Aug  6 07:13:09 2012
+++ /branches/bleeding_edge/src/arm/lithium-arm.h       Mon Aug  6 07:28:27 2012
@@ -115,7 +115,6 @@
   V(IsStringAndBranch)                          \
   V(IsSmiAndBranch)                             \
   V(IsUndetectableAndBranch)                    \
-  V(StringCompareAndBranch)                     \
   V(JSArrayLength)                              \
   V(Label)                                      \
   V(LazyBailout)                                \
@@ -133,6 +132,7 @@
   V(LoadNamedFieldPolymorphic)                  \
   V(LoadNamedGeneric)                           \
   V(MathFloorOfDiv)                             \
+  V(MathMinMax)                                 \
   V(ModI)                                       \
   V(MulI)                                       \
   V(NumberTagD)                                 \
@@ -163,6 +163,7 @@
   V(StringAdd)                                  \
   V(StringCharCodeAt)                           \
   V(StringCharFromCode)                         \
+  V(StringCompareAndBranch)                     \
   V(StringLength)                               \
   V(SubI)                                       \
   V(TaggedToI)                                  \
@@ -1084,6 +1085,18 @@
 };


+class LMathMinMax: public LTemplateInstruction<1, 2, 0> {
+ public:
+  LMathMinMax(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max")
+  DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
+};
+
+
 class LPower: public LTemplateInstruction<1, 2, 0> {
  public:
   LPower(LOperand* left, LOperand* right) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Aug 6 07:13:09 2012 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Aug 6 07:28:27 2012
@@ -1647,6 +1647,68 @@
     DeoptimizeIf(vs, instr->environment());
   }
 }
+
+
+void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
+  LOperand* left = instr->InputAt(0);
+  LOperand* right = instr->InputAt(1);
+  HMathMinMax::Operation operation = instr->hydrogen()->operation();
+  Condition condition = (operation == HMathMinMax::kMathMin) ? le : ge;
+  if (instr->hydrogen()->representation().IsInteger32()) {
+    Register left_reg = ToRegister(left);
+    Operand right_op = (right->IsRegister() || right->IsConstantOperand())
+        ? ToOperand(right)
+        : Operand(EmitLoadRegister(right, ip));
+    Register result_reg = ToRegister(instr->result());
+    __ cmp(left_reg, right_op);
+    if (!result_reg.is(left_reg)) {
+      __ mov(result_reg, left_reg, LeaveCC, condition);
+    }
+    __ mov(result_reg, right_op, LeaveCC, NegateCondition(condition));
+  } else {
+    ASSERT(instr->hydrogen()->representation().IsDouble());
+    DoubleRegister left_reg = ToDoubleRegister(left);
+    DoubleRegister right_reg = ToDoubleRegister(right);
+    DoubleRegister result_reg = ToDoubleRegister(instr->result());
+    Label check_nan_left, check_zero, return_left, return_right, done;
+    __ VFPCompareAndSetFlags(left_reg, right_reg);
+    __ b(vs, &check_nan_left);
+    __ b(eq, &check_zero);
+    __ b(condition, &return_left);
+    __ b(al, &return_right);
+
+    __ bind(&check_zero);
+    __ VFPCompareAndSetFlags(left_reg, 0.0);
+    __ b(ne, &return_left);  // left == right != 0.
+    // At this point, both left and right are either 0 or -0.
+    if (operation == HMathMinMax::kMathMin) {
+ // We could use a single 'vorr' instruction here if we had NEON support.
+      __ vneg(left_reg, left_reg);
+      __ vsub(result_reg, left_reg, right_reg);
+      __ vneg(result_reg, result_reg);
+    } else {
+ // Since we operate on +0 and/or -0, vadd and vand have the same effect;
+      // the decision for vadd is easy because vand is a NEON instruction.
+      __ vadd(result_reg, left_reg, right_reg);
+    }
+    __ b(al, &done);
+
+    __ bind(&check_nan_left);
+    __ VFPCompareAndSetFlags(left_reg, left_reg);
+    __ b(vs, &return_left);  // left == NaN.
+    __ bind(&return_right);
+    if (!right_reg.is(result_reg)) {
+      __ vmov(result_reg, right_reg);
+    }
+    __ b(al, &done);
+
+    __ bind(&return_left);
+    if (!left_reg.is(result_reg)) {
+      __ vmov(result_reg, left_reg);
+    }
+    __ bind(&done);
+  }
+}


 void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Thu Jun 14 08:04:27 2012 +++ /branches/bleeding_edge/src/arm/simulator-arm.cc Mon Aug 6 07:28:27 2012
@@ -945,73 +945,31 @@
 }


-void Simulator::set_s_register_from_float(int sreg, const float flt) {
-  ASSERT((sreg >= 0) && (sreg < num_s_registers));
-  // Read the bits from the single precision floating point value
- // into the unsigned integer element of vfp_register[] given by index=sreg.
-  char buffer[sizeof(vfp_register[0])];
-  memcpy(buffer, &flt, sizeof(vfp_register[0]));
-  memcpy(&vfp_register[sreg], buffer, sizeof(vfp_register[0]));
-}
-
-
-void Simulator::set_s_register_from_sinteger(int sreg, const int sint) {
-  ASSERT((sreg >= 0) && (sreg < num_s_registers));
- // Read the bits from the integer value into the unsigned integer element of
-  // vfp_register[] given by index=sreg.
-  char buffer[sizeof(vfp_register[0])];
-  memcpy(buffer, &sint, sizeof(vfp_register[0]));
-  memcpy(&vfp_register[sreg], buffer, sizeof(vfp_register[0]));
+template<class InputType, int register_size>
+void Simulator::SetVFPRegister(int reg_index, const InputType& value) {
+  ASSERT(reg_index >= 0);
+  if (register_size == 1) ASSERT(reg_index < num_s_registers);
+  if (register_size == 2) ASSERT(reg_index < num_d_registers);
+
+  char buffer[register_size * sizeof(vfp_register[0])];
+  memcpy(buffer, &value, register_size * sizeof(vfp_register[0]));
+  memcpy(&vfp_register[reg_index * register_size], buffer,
+         register_size * sizeof(vfp_register[0]));
 }


-void Simulator::set_d_register_from_double(int dreg, const double& dbl) {
-  ASSERT((dreg >= 0) && (dreg < num_d_registers));
- // Read the bits from the double precision floating point value into the two
-  // consecutive unsigned integer elements of vfp_register[] given by index
-  // 2*sreg and 2*sreg+1.
-  char buffer[2 * sizeof(vfp_register[0])];
-  memcpy(buffer, &dbl, 2 * sizeof(vfp_register[0]));
-  memcpy(&vfp_register[dreg * 2], buffer, 2 * sizeof(vfp_register[0]));
-}
-
-
-float Simulator::get_float_from_s_register(int sreg) {
-  ASSERT((sreg >= 0) && (sreg < num_s_registers));
-
-  float sm_val = 0.0;
-  // Read the bits from the unsigned integer vfp_register[] array
-  // into the single precision floating point value and return it.
-  char buffer[sizeof(vfp_register[0])];
-  memcpy(buffer, &vfp_register[sreg], sizeof(vfp_register[0]));
-  memcpy(&sm_val, buffer, sizeof(vfp_register[0]));
-  return(sm_val);
-}
-
-
-int Simulator::get_sinteger_from_s_register(int sreg) {
-  ASSERT((sreg >= 0) && (sreg < num_s_registers));
-
-  int sm_val = 0;
-  // Read the bits from the unsigned integer vfp_register[] array
-  // into the single precision floating point value and return it.
-  char buffer[sizeof(vfp_register[0])];
-  memcpy(buffer, &vfp_register[sreg], sizeof(vfp_register[0]));
-  memcpy(&sm_val, buffer, sizeof(vfp_register[0]));
-  return(sm_val);
-}
-
-
-double Simulator::get_double_from_d_register(int dreg) {
-  ASSERT((dreg >= 0) && (dreg < num_d_registers));
-
-  double dm_val = 0.0;
-  // Read the bits from the unsigned integer vfp_register[] array
-  // into the double precision floating point value and return it.
-  char buffer[2 * sizeof(vfp_register[0])];
-  memcpy(buffer, &vfp_register[2 * dreg], 2 * sizeof(vfp_register[0]));
-  memcpy(&dm_val, buffer, 2 * sizeof(vfp_register[0]));
-  return(dm_val);
+template<class ReturnType, int register_size>
+ReturnType Simulator::GetFromVFPRegister(int reg_index) {
+  ASSERT(reg_index >= 0);
+  if (register_size == 1) ASSERT(reg_index < num_s_registers);
+  if (register_size == 2) ASSERT(reg_index < num_d_registers);
+
+  ReturnType value = 0;
+  char buffer[register_size * sizeof(vfp_register[0])];
+  memcpy(buffer, &vfp_register[register_size * reg_index],
+         register_size * sizeof(vfp_register[0]));
+  memcpy(&value, buffer, register_size * sizeof(vfp_register[0]));
+  return value;
 }


=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.h     Tue May 22 07:05:44 2012
+++ /branches/bleeding_edge/src/arm/simulator-arm.h     Mon Aug  6 07:28:27 2012
@@ -163,12 +163,30 @@
   // Support for VFP.
   void set_s_register(int reg, unsigned int value);
   unsigned int get_s_register(int reg) const;
-  void set_d_register_from_double(int dreg, const double& dbl);
-  double get_double_from_d_register(int dreg);
-  void set_s_register_from_float(int sreg, const float dbl);
-  float get_float_from_s_register(int sreg);
-  void set_s_register_from_sinteger(int reg, const int value);
-  int get_sinteger_from_s_register(int reg);
+
+  void set_d_register_from_double(int dreg, const double& dbl) {
+    SetVFPRegister<double, 2>(dreg, dbl);
+  }
+
+  double get_double_from_d_register(int dreg) {
+    return GetFromVFPRegister<double, 2>(dreg);
+  }
+
+  void set_s_register_from_float(int sreg, const float flt) {
+    SetVFPRegister<float, 1>(sreg, flt);
+  }
+
+  float get_float_from_s_register(int sreg) {
+    return GetFromVFPRegister<float, 1>(sreg);
+  }
+
+  void set_s_register_from_sinteger(int sreg, const int sint) {
+    SetVFPRegister<int, 1>(sreg, sint);
+  }
+
+  int get_sinteger_from_s_register(int sreg) {
+    return GetFromVFPRegister<int, 1>(sreg);
+  }

// Special case of set_register and get_register to access the raw PC value.
   void set_pc(int32_t value);
@@ -332,6 +350,12 @@
   void SetFpResult(const double& result);
   void TrashCallerSaveRegisters();

+  template<class ReturnType, int register_size>
+      ReturnType GetFromVFPRegister(int reg_index);
+
+  template<class InputType, int register_size>
+      void SetVFPRegister(int reg_index, const InputType& value);
+
   // Architecture state.
   // Saturating instructions require a Q flag to indicate saturation.
// There is currently no way to read the CPSR directly, and thus read the Q
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Mon Aug 6 07:25:19 2012 +++ /branches/bleeding_edge/src/hydrogen-instructions.cc Mon Aug 6 07:28:27 2012
@@ -154,6 +154,20 @@
   bool b = CanBeMinusZero() || other->CanBeMinusZero();
   set_can_be_minus_zero(b);
 }
+
+
+void Range::CombinedMax(Range* other) {
+  upper_ = Max(upper_, other->upper_);
+  lower_ = Max(lower_, other->lower_);
+  set_can_be_minus_zero(CanBeMinusZero() || other->CanBeMinusZero());
+}
+
+
+void Range::CombinedMin(Range* other) {
+  upper_ = Min(upper_, other->upper_);
+  lower_ = Min(lower_, other->lower_);
+  set_can_be_minus_zero(CanBeMinusZero() || other->CanBeMinusZero());
+}


 void Range::Sar(int32_t value) {
@@ -1236,6 +1250,24 @@
     return HValue::InferRange(zone);
   }
 }
+
+
+Range* HMathMinMax::InferRange(Zone* zone) {
+  if (representation().IsInteger32()) {
+    Range* a = left()->range();
+    Range* b = right()->range();
+    Range* res = a->Copy(zone);
+    if (operation_ == kMathMax) {
+      res->CombinedMax(b);
+    } else {
+      ASSERT(operation_ == kMathMin);
+      res->CombinedMin(b);
+    }
+    return res;
+  } else {
+    return HValue::InferRange(zone);
+  }
+}


 void HPhi::PrintTo(StringStream* stream) {
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Mon Aug 6 07:13:09 2012 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Mon Aug 6 07:28:27 2012
@@ -124,7 +124,6 @@
   V(IsStringAndBranch)                         \
   V(IsSmiAndBranch)                            \
   V(IsUndetectableAndBranch)                   \
-  V(StringCompareAndBranch)                    \
   V(JSArrayLength)                             \
   V(LeaveInlined)                              \
   V(LoadContextSlot)                           \
@@ -141,6 +140,7 @@
   V(LoadNamedFieldPolymorphic)                 \
   V(LoadNamedGeneric)                          \
   V(MathFloorOfDiv)                            \
+  V(MathMinMax)                                \
   V(Mod)                                       \
   V(Mul)                                       \
   V(ObjectLiteral)                             \
@@ -170,6 +170,7 @@
   V(StringAdd)                                 \
   V(StringCharCodeAt)                          \
   V(StringCharFromCode)                        \
+  V(StringCompareAndBranch)                    \
   V(StringLength)                              \
   V(Sub)                                       \
   V(ThisFunction)                              \
@@ -286,6 +287,8 @@

   void Intersect(Range* other);
   void Union(Range* other);
+  void CombinedMax(Range* other);
+  void CombinedMin(Range* other);

   void AddConstant(int32_t value);
   void Sar(int32_t value);
@@ -3470,6 +3473,47 @@
 };


+class HMathMinMax: public HArithmeticBinaryOperation {
+ public:
+  enum Operation { kMathMin, kMathMax };
+
+  HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
+      : HArithmeticBinaryOperation(context, left, right),
+        operation_(op) { }
+
+  virtual Representation RequiredInputRepresentation(int index) {
+      return index == 0
+          ? Representation::Tagged()
+          : representation();
+    }
+
+  virtual Representation InferredRepresentation() {
+    if (left()->representation().IsInteger32() &&
+        right()->representation().IsInteger32()) {
+      return Representation::Integer32();
+    }
+    return Representation::Double();
+  }
+
+  virtual bool IsCommutative() const { return true; }
+
+  Operation operation() { return operation_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
+
+ protected:
+  virtual bool DataEquals(HValue* other) {
+    return other->IsMathMinMax() &&
+        HMathMinMax::cast(other)->operation_ == operation_;
+  }
+
+  virtual Range* InferRange(Zone* zone);
+
+ private:
+  Operation operation_;
+};
+
+
 class HBitwise: public HBitwiseBinaryOperation {
  public:
   HBitwise(Token::Value op, HValue* context, HValue* left, HValue* right)
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Mon Aug  6 07:25:19 2012
+++ /branches/bleeding_edge/src/hydrogen.cc     Mon Aug  6 07:28:27 2012
@@ -2556,8 +2556,8 @@
       break;
     }

-    // For multiplication and division, we must propagate to the left and
-    // the right side.
+    // For multiplication, division, and Math.min/max(), we must propagate
+    // to the left and the right side.
     if (current->IsMul()) {
       HMul* mul = HMul::cast(current);
       mul->EnsureAndPropagateNotMinusZero(visited);
@@ -2568,6 +2568,11 @@
       div->EnsureAndPropagateNotMinusZero(visited);
       PropagateMinusZeroChecks(div->left(), visited);
       PropagateMinusZeroChecks(div->right(), visited);
+    } else if (current->IsMathMinMax()) {
+      HMathMinMax* minmax = HMathMinMax::cast(current);
+      visited->Add(minmax->id());
+      PropagateMinusZeroChecks(minmax->left(), visited);
+      PropagateMinusZeroChecks(minmax->right(), visited);
     }

     current = current->EnsureAndPropagateNotMinusZero(visited);
@@ -7100,79 +7105,12 @@
AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true);
         HValue* right = Pop();
         HValue* left = Pop();
-        Pop();  // Pop receiver.
-
-        HValue* left_operand = left;
-        HValue* right_operand = right;
-
- // If we do not have two integers, we convert to double for comparison.
-        if (!left->representation().IsInteger32() ||
-            !right->representation().IsInteger32()) {
-          if (!left->representation().IsDouble()) {
-            HChange* left_convert = new(zone()) HChange(
-                left,
-                Representation::Double(),
-                false,  // Do not truncate when converting to double.
-                true);  // Deoptimize for undefined.
-            left_convert->SetFlag(HValue::kBailoutOnMinusZero);
-            left_operand = AddInstruction(left_convert);
-          }
-          if (!right->representation().IsDouble()) {
-            HChange* right_convert = new(zone()) HChange(
-                right,
-                Representation::Double(),
-                false,  // Do not truncate when converting to double.
-                true);  // Deoptimize for undefined.
-            right_convert->SetFlag(HValue::kBailoutOnMinusZero);
-            right_operand = AddInstruction(right_convert);
-          }
-        }
-
-        ASSERT(left_operand->representation().Equals(
-               right_operand->representation()));
-        ASSERT(!left_operand->representation().IsTagged());
-
-        Token::Value op = (id == kMathMin) ? Token::LT : Token::GT;
-
-        HCompareIDAndBranch* compare =
- new(zone()) HCompareIDAndBranch(left_operand, right_operand, op);
-        compare->SetInputRepresentation(left_operand->representation());
-
-        HBasicBlock* return_left = graph()->CreateBasicBlock();
-        HBasicBlock* return_right = graph()->CreateBasicBlock();
-
-        compare->SetSuccessorAt(0, return_left);
-        compare->SetSuccessorAt(1, return_right);
-        current_block()->Finish(compare);
-
-        set_current_block(return_left);
-        Push(left);
-        set_current_block(return_right);
-        // The branch above always returns the right operand if either of
-        // them is NaN, but the spec requires that max/min(NaN, X) = NaN.
- // We add another branch that checks if the left operand is NaN or not.
-        if (left_operand->representation().IsDouble()) {
-          // If left_operand != left_operand then it is NaN.
- HCompareIDAndBranch* compare_nan = new(zone()) HCompareIDAndBranch(
-              left_operand, left_operand, Token::EQ);
- compare_nan->SetInputRepresentation(left_operand->representation());
-          HBasicBlock* left_is_number = graph()->CreateBasicBlock();
-          HBasicBlock* left_is_nan = graph()->CreateBasicBlock();
-          compare_nan->SetSuccessorAt(0, left_is_number);
-          compare_nan->SetSuccessorAt(1, left_is_nan);
-          current_block()->Finish(compare_nan);
-          set_current_block(left_is_nan);
-          Push(left);
-          set_current_block(left_is_number);
-          Push(right);
- return_right = CreateJoin(left_is_number, left_is_nan, expr->id());
-        } else {
-          Push(right);
-        }
-
- HBasicBlock* join = CreateJoin(return_left, return_right, expr->id());
-        set_current_block(join);
-        ast_context()->ReturnValue(Pop());
+        Drop(1);  // Receiver.
+        HValue* context = environment()->LookupContext();
+ HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin + : HMathMinMax::kMathMax; + HMathMinMax* result = new(zone()) HMathMinMax(context, left, right, op);
+        ast_context()->ReturnInstruction(result, expr->id());
         return true;
       }
       break;
=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32.cc Mon Aug 6 07:13:09 2012 +++ /branches/bleeding_edge/src/ia32/assembler-ia32.cc Mon Aug 6 07:28:27 2012
@@ -2042,6 +2042,15 @@
   EMIT(0x54);
   emit_sse_operand(dst, src);
 }
+
+
+void Assembler::orpd(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x56);
+  emit_sse_operand(dst, src);
+}


 void Assembler::ucomisd(XMMRegister dst, XMMRegister src) {
=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32.h Mon Aug 6 07:13:09 2012 +++ /branches/bleeding_edge/src/ia32/assembler-ia32.h Mon Aug 6 07:28:27 2012
@@ -998,6 +998,7 @@
   void sqrtsd(XMMRegister dst, XMMRegister src);

   void andpd(XMMRegister dst, XMMRegister src);
+  void orpd(XMMRegister dst, XMMRegister src);

   void ucomisd(XMMRegister dst, XMMRegister src);
   void ucomisd(XMMRegister dst, const Operand& src);
=======================================
--- /branches/bleeding_edge/src/ia32/disasm-ia32.cc     Wed Jun 20 07:08:03 2012
+++ /branches/bleeding_edge/src/ia32/disasm-ia32.cc     Mon Aug  6 07:28:27 2012
@@ -1267,6 +1267,14 @@
                            NameOfXMMRegister(regop),
                            NameOfXMMRegister(rm));
             data++;
+          } else if (*data == 0x56) {
+            data++;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            AppendToBuffer("orpd %s,%s",
+                           NameOfXMMRegister(regop),
+                           NameOfXMMRegister(rm));
+            data++;
           } else if (*data == 0x57) {
             data++;
             int mod, regop, rm;
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Mon Aug 6 07:13:09 2012 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Mon Aug 6 07:28:27 2012
@@ -1495,6 +1495,67 @@
     DeoptimizeIf(overflow, instr->environment());
   }
 }
+
+
+void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
+  LOperand* left = instr->InputAt(0);
+  LOperand* right = instr->InputAt(1);
+  ASSERT(left->Equals(instr->result()));
+  HMathMinMax::Operation operation = instr->hydrogen()->operation();
+  if (instr->hydrogen()->representation().IsInteger32()) {
+    Label return_left;
+    Condition condition = (operation == HMathMinMax::kMathMin)
+        ? less_equal
+        : greater_equal;
+    if (right->IsConstantOperand()) {
+      Operand left_op = ToOperand(left);
+      Immediate right_imm = ToInteger32Immediate(right);
+      __ cmp(left_op, right_imm);
+      __ j(condition, &return_left, Label::kNear);
+      __ mov(left_op, right_imm);
+    } else {
+      Register left_reg = ToRegister(left);
+      Operand right_op = ToOperand(right);
+      __ cmp(left_reg, right_op);
+      __ j(condition, &return_left, Label::kNear);
+      __ mov(left_reg, right_op);
+    }
+    __ bind(&return_left);
+  } else {
+    ASSERT(instr->hydrogen()->representation().IsDouble());
+    Label check_nan_left, check_zero, return_left, return_right;
+ Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
+    XMMRegister left_reg = ToDoubleRegister(left);
+    XMMRegister right_reg = ToDoubleRegister(right);
+    __ ucomisd(left_reg, right_reg);
+    __ j(parity_even, &check_nan_left, Label::kNear);  // At least one NaN.
+    __ j(equal, &check_zero, Label::kNear);  // left == right.
+    __ j(condition, &return_left, Label::kNear);
+    __ jmp(&return_right, Label::kNear);
+
+    __ bind(&check_zero);
+    XMMRegister xmm_scratch = xmm0;
+    __ xorps(xmm_scratch, xmm_scratch);
+    __ ucomisd(left_reg, xmm_scratch);
+    __ j(not_equal, &return_left, Label::kNear);  // left == right != 0.
+    // At this point, both left and right are either 0 or -0.
+    if (operation == HMathMinMax::kMathMin) {
+      __ orpd(left_reg, right_reg);
+    } else {
+ // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
+      __ addsd(left_reg, right_reg);
+    }
+    __ jmp(&return_left, Label::kNear);
+
+    __ bind(&check_nan_left);
+    __ ucomisd(left_reg, left_reg);  // NaN check.
+    __ j(parity_even, &return_left, Label::kNear);  // left == NaN.
+    __ bind(&return_right);
+    __ movsd(left_reg, right_reg);
+
+    __ bind(&return_left);
+  }
+}


 void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Mon Aug 6 07:13:09 2012 +++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Mon Aug 6 07:28:27 2012
@@ -1393,6 +1393,26 @@
     return DoArithmeticT(Token::ADD, instr);
   }
 }
+
+
+LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
+  LOperand* left = NULL;
+  LOperand* right = NULL;
+  if (instr->representation().IsInteger32()) {
+    ASSERT(instr->left()->representation().IsInteger32());
+    ASSERT(instr->right()->representation().IsInteger32());
+    left = UseRegisterAtStart(instr->LeastConstantOperand());
+    right = UseOrConstantAtStart(instr->MostConstantOperand());
+  } else {
+    ASSERT(instr->representation().IsDouble());
+    ASSERT(instr->left()->representation().IsDouble());
+    ASSERT(instr->right()->representation().IsDouble());
+    left = UseRegisterAtStart(instr->left());
+    right = UseRegisterAtStart(instr->right());
+  }
+  LMathMinMax* minmax = new(zone()) LMathMinMax(left, right);
+  return DefineSameAsFirst(minmax);
+}


 LInstruction* LChunkBuilder::DoPower(HPower* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.h     Mon Aug  6 07:13:09 2012
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.h     Mon Aug  6 07:28:27 2012
@@ -109,7 +109,6 @@
   V(IsStringAndBranch)                          \
   V(IsSmiAndBranch)                             \
   V(IsUndetectableAndBranch)                    \
-  V(StringCompareAndBranch)                     \
   V(JSArrayLength)                              \
   V(Label)                                      \
   V(LazyBailout)                                \
@@ -127,6 +126,7 @@
   V(LoadNamedFieldPolymorphic)                  \
   V(LoadNamedGeneric)                           \
   V(MathFloorOfDiv)                             \
+  V(MathMinMax)                                 \
   V(MathPowHalf)                                \
   V(ModI)                                       \
   V(MulI)                                       \
@@ -158,6 +158,7 @@
   V(StringAdd)                                  \
   V(StringCharCodeAt)                           \
   V(StringCharFromCode)                         \
+  V(StringCompareAndBranch)                     \
   V(StringLength)                               \
   V(SubI)                                       \
   V(TaggedToI)                                  \
@@ -1088,6 +1089,18 @@
 };


+class LMathMinMax: public LTemplateInstruction<1, 2, 0> {
+ public:
+  LMathMinMax(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max")
+  DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
+};
+
+
 class LPower: public LTemplateInstruction<1, 2, 0> {
  public:
   LPower(LOperand* left, LOperand* right) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Mon Aug 6 07:13:09 2012 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Mon Aug 6 07:28:27 2012
@@ -1391,6 +1391,67 @@
     DeoptimizeIf(overflow, instr->environment());
   }
 }
+
+
+void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
+  LOperand* left = instr->InputAt(0);
+  LOperand* right = instr->InputAt(1);
+  ASSERT(left->Equals(instr->result()));
+  HMathMinMax::Operation operation = instr->hydrogen()->operation();
+  if (instr->hydrogen()->representation().IsInteger32()) {
+    Label return_left;
+    Condition condition = (operation == HMathMinMax::kMathMin)
+        ? less_equal
+        : greater_equal;
+    Register left_reg = ToRegister(left);
+    if (right->IsConstantOperand()) {
+      Immediate right_imm =
+          Immediate(ToInteger32(LConstantOperand::cast(right)));
+      __ cmpq(left_reg, right_imm);
+      __ j(condition, &return_left, Label::kNear);
+      __ movq(left_reg, right_imm);
+    } else {
+      Operand right_op = ToOperand(right);
+      __ cmpq(left_reg, right_op);
+      __ j(condition, &return_left, Label::kNear);
+      __ movq(left_reg, right_op);
+    }
+    __ bind(&return_left);
+  } else {
+    ASSERT(instr->hydrogen()->representation().IsDouble());
+    Label check_nan_left, check_zero, return_left, return_right;
+ Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
+    XMMRegister left_reg = ToDoubleRegister(left);
+    XMMRegister right_reg = ToDoubleRegister(right);
+    __ ucomisd(left_reg, right_reg);
+    __ j(parity_even, &check_nan_left, Label::kNear);  // At least one NaN.
+    __ j(equal, &check_zero, Label::kNear);  // left == right.
+    __ j(condition, &return_left, Label::kNear);
+    __ jmp(&return_right, Label::kNear);
+
+    __ bind(&check_zero);
+    XMMRegister xmm_scratch = xmm0;
+    __ xorps(xmm_scratch, xmm_scratch);
+    __ ucomisd(left_reg, xmm_scratch);
+    __ j(not_equal, &return_left, Label::kNear);  // left == right != 0.
+    // At this point, both left and right are either 0 or -0.
+    if (operation == HMathMinMax::kMathMin) {
+      __ orpd(left_reg, right_reg);
+    } else {
+ // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
+      __ addsd(left_reg, right_reg);
+    }
+    __ jmp(&return_left, Label::kNear);
+
+    __ bind(&check_nan_left);
+    __ ucomisd(left_reg, left_reg);  // NaN check.
+    __ j(parity_even, &return_left, Label::kNear);
+    __ bind(&return_right);
+    __ movsd(left_reg, right_reg);
+
+    __ bind(&return_left);
+  }
+}


 void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc      Mon Aug  6 07:13:09 2012
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc      Mon Aug  6 07:28:27 2012
@@ -1328,6 +1328,26 @@
   }
   return NULL;
 }
+
+
+LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
+  LOperand* left = NULL;
+  LOperand* right = NULL;
+  if (instr->representation().IsInteger32()) {
+    ASSERT(instr->left()->representation().IsInteger32());
+    ASSERT(instr->right()->representation().IsInteger32());
+    left = UseRegisterAtStart(instr->LeastConstantOperand());
+    right = UseOrConstantAtStart(instr->MostConstantOperand());
+  } else {
+    ASSERT(instr->representation().IsDouble());
+    ASSERT(instr->left()->representation().IsDouble());
+    ASSERT(instr->right()->representation().IsDouble());
+    left = UseRegisterAtStart(instr->left());
+    right = UseRegisterAtStart(instr->right());
+  }
+  LMathMinMax* minmax = new(zone()) LMathMinMax(left, right);
+  return DefineSameAsFirst(minmax);
+}


 LInstruction* LChunkBuilder::DoPower(HPower* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h       Mon Aug  6 07:13:09 2012
+++ /branches/bleeding_edge/src/x64/lithium-x64.h       Mon Aug  6 07:28:27 2012
@@ -115,7 +115,6 @@
   V(IsStringAndBranch)                          \
   V(IsSmiAndBranch)                             \
   V(IsUndetectableAndBranch)                    \
-  V(StringCompareAndBranch)                     \
   V(JSArrayLength)                              \
   V(Label)                                      \
   V(LazyBailout)                                \
@@ -133,6 +132,7 @@
   V(LoadNamedFieldPolymorphic)                  \
   V(LoadNamedGeneric)                           \
   V(MathFloorOfDiv)                             \
+  V(MathMinMax)                                 \
   V(ModI)                                       \
   V(MulI)                                       \
   V(NumberTagD)                                 \
@@ -163,6 +163,7 @@
   V(StringAdd)                                  \
   V(StringCharCodeAt)                           \
   V(StringCharFromCode)                         \
+  V(StringCompareAndBranch)                     \
   V(StringLength)                               \
   V(SubI)                                       \
   V(TaggedToI)                                  \
@@ -1064,6 +1065,18 @@
 };


+class LMathMinMax: public LTemplateInstruction<1, 2, 0> {
+ public:
+  LMathMinMax(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max")
+  DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
+};
+
+
 class LPower: public LTemplateInstruction<1, 2, 0> {
  public:
   LPower(LOperand* left, LOperand* right) {

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to