Refactor Math.min/max to be a single HInstruction.
authorjkummerow@chromium.org <jkummerow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 6 Aug 2012 14:28:27 +0000 (14:28 +0000)
committerjkummerow@chromium.org <jkummerow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 6 Aug 2012 14:28:27 +0000 (14:28 +0000)
That allows us to dynamically compute representations and insert appropriate HChange instructions.

Review URL: https://chromiumcodereview.appspot.com/10829169

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12265 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

17 files changed:
src/arm/lithium-arm.cc
src/arm/lithium-arm.h
src/arm/lithium-codegen-arm.cc
src/arm/simulator-arm.cc
src/arm/simulator-arm.h
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/ia32/assembler-ia32.cc
src/ia32/assembler-ia32.h
src/ia32/disasm-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc
src/x64/lithium-x64.h

index d37bfec008a8aba22655fa2a194b52821310d2af..5b5bd6b17c397b77b0df551af3752a87cdba5e52 100644 (file)
@@ -1359,6 +1359,25 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* 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) {
   ASSERT(instr->representation().IsDouble());
   // We call a C function for double power. It can't trigger a GC.
index c3d6f8a484c2c04678d9e0a642b08b658d865994..9425e9695b3fb640a8b52b7304d2e956ef8a559f 100644 (file)
@@ -115,7 +115,6 @@ class LCodeGen;
   V(IsStringAndBranch)                          \
   V(IsSmiAndBranch)                             \
   V(IsUndetectableAndBranch)                    \
-  V(StringCompareAndBranch)                     \
   V(JSArrayLength)                              \
   V(Label)                                      \
   V(LazyBailout)                                \
@@ -133,6 +132,7 @@ class LCodeGen;
   V(LoadNamedFieldPolymorphic)                  \
   V(LoadNamedGeneric)                           \
   V(MathFloorOfDiv)                             \
+  V(MathMinMax)                                 \
   V(ModI)                                       \
   V(MulI)                                       \
   V(NumberTagD)                                 \
@@ -163,6 +163,7 @@ class LCodeGen;
   V(StringAdd)                                  \
   V(StringCharCodeAt)                           \
   V(StringCharFromCode)                         \
+  V(StringCompareAndBranch)                     \
   V(StringLength)                               \
   V(SubI)                                       \
   V(TaggedToI)                                  \
@@ -1084,6 +1085,18 @@ class LAddI: public LTemplateInstruction<1, 2, 0> {
 };
 
 
+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) {
index 0c2aaff446280b8db77d12a4a6b8304043968294..d827f8c82fd9b6ceced8b333ee058d326e09a631 100644 (file)
@@ -1649,6 +1649,68 @@ void LCodeGen::DoAddI(LAddI* instr) {
 }
 
 
+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) {
   DoubleRegister left = ToDoubleRegister(instr->InputAt(0));
   DoubleRegister right = ToDoubleRegister(instr->InputAt(1));
index 394ef27eb5cfee3c09b7fb1e422a81a13ca58218..f94c3948e40ae3df99498def6f2578e0e56bcbb4 100644 (file)
@@ -945,73 +945,31 @@ unsigned int Simulator::get_s_register(int sreg) const {
 }
 
 
-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]));
-}
-
-
-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 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]));
+}
+
+
+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;
 }
 
 
index d1cad15bd04213036d8013ac140cfbb500d4bf85..abc91bbc42a1dec072be83178a4fc860f3d9e439 100644 (file)
@@ -163,12 +163,30 @@ class Simulator {
   // 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 @@ class Simulator {
   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
index f2bf64138a486de190196a74cc77a95d721c7203..353d94bff5ac055aab74e483198c2178090e7256 100644 (file)
@@ -156,6 +156,20 @@ void Range::Union(Range* other) {
 }
 
 
+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) {
   int32_t bits = value & 0x1F;
   lower_ = lower_ >> bits;
@@ -1238,6 +1252,24 @@ Range* HMod::InferRange(Zone* 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) {
   stream->Add("[");
   for (int i = 0; i < OperandCount(); ++i) {
index 960dc791dc3d8b36270ce014365ea109f95d9217..1e92cc4a3fe53e61fa0dde85b4b5b0caf5308f84 100644 (file)
@@ -124,7 +124,6 @@ class LChunkBuilder;
   V(IsStringAndBranch)                         \
   V(IsSmiAndBranch)                            \
   V(IsUndetectableAndBranch)                   \
-  V(StringCompareAndBranch)                    \
   V(JSArrayLength)                             \
   V(LeaveInlined)                              \
   V(LoadContextSlot)                           \
@@ -141,6 +140,7 @@ class LChunkBuilder;
   V(LoadNamedFieldPolymorphic)                 \
   V(LoadNamedGeneric)                          \
   V(MathFloorOfDiv)                            \
+  V(MathMinMax)                                \
   V(Mod)                                       \
   V(Mul)                                       \
   V(ObjectLiteral)                             \
@@ -170,6 +170,7 @@ class LChunkBuilder;
   V(StringAdd)                                 \
   V(StringCharCodeAt)                          \
   V(StringCharFromCode)                        \
+  V(StringCompareAndBranch)                    \
   V(StringLength)                              \
   V(Sub)                                       \
   V(ThisFunction)                              \
@@ -286,6 +287,8 @@ class Range: public ZoneObject {
 
   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 HDiv: public HArithmeticBinaryOperation {
 };
 
 
+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)
index bfbe15994b9a16cc7d1bd495745805e0d231c361..30861283c3e9fc4139fa6cc2b852ffa1a0123c77 100644 (file)
@@ -2556,8 +2556,8 @@ void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) {
       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 @@ void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) {
       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 @@ bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr,
         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;
index 87c01d1b91495b653d0acc903fefaefe69736a59..4005123df7ec5445ede4aa1d955442de9af32c7e 100644 (file)
@@ -2044,6 +2044,15 @@ void Assembler::andpd(XMMRegister dst, XMMRegister 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) {
   ASSERT(CpuFeatures::IsEnabled(SSE2));
   EnsureSpace ensure_space(this);
index b9193f36af04099bd30a15993aa9e34dd6483d22..60b680f4787b6697728eb4e3876b058019afaae2 100644 (file)
@@ -998,6 +998,7 @@ class Assembler : public AssemblerBase {
   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);
index 412bdaf00be5078abd9c9964f3d360dfb0f785d6..10dcb23f548a99b63ddcef6b42999881bd058b2d 100644 (file)
@@ -1267,6 +1267,14 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
                            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;
index e93c59754491d341bebde9fbaa445339768768d6..b2a7f83f743aba831588e3912b40829e3de26cba 100644 (file)
@@ -1497,6 +1497,67 @@ void LCodeGen::DoAddI(LAddI* instr) {
 }
 
 
+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) {
   XMMRegister left = ToDoubleRegister(instr->InputAt(0));
   XMMRegister right = ToDoubleRegister(instr->InputAt(1));
index fe0100a00e1299bd8826022f8d7228acab68c2ce..7c558036265a7b8e64c6017b3b102f1916143fb3 100644 (file)
@@ -1395,6 +1395,26 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* 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) {
   ASSERT(instr->representation().IsDouble());
   // We call a C function for double power. It can't trigger a GC.
index afee68410ce064a54c80fcd286b5449389e36984..ee41ef7496c4e896847c5377a34721505ff92148 100644 (file)
@@ -109,7 +109,6 @@ class LCodeGen;
   V(IsStringAndBranch)                          \
   V(IsSmiAndBranch)                             \
   V(IsUndetectableAndBranch)                    \
-  V(StringCompareAndBranch)                     \
   V(JSArrayLength)                              \
   V(Label)                                      \
   V(LazyBailout)                                \
@@ -127,6 +126,7 @@ class LCodeGen;
   V(LoadNamedFieldPolymorphic)                  \
   V(LoadNamedGeneric)                           \
   V(MathFloorOfDiv)                             \
+  V(MathMinMax)                                 \
   V(MathPowHalf)                                \
   V(ModI)                                       \
   V(MulI)                                       \
@@ -158,6 +158,7 @@ class LCodeGen;
   V(StringAdd)                                  \
   V(StringCharCodeAt)                           \
   V(StringCharFromCode)                         \
+  V(StringCompareAndBranch)                     \
   V(StringLength)                               \
   V(SubI)                                       \
   V(TaggedToI)                                  \
@@ -1088,6 +1089,18 @@ class LAddI: public LTemplateInstruction<1, 2, 0> {
 };
 
 
+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) {
index 97d3a441f11b04c9e70ac58493d672081f4942b6..6bf803c54bf8086bff44a4a384a82b0acd54145f 100644 (file)
@@ -1393,6 +1393,67 @@ void LCodeGen::DoAddI(LAddI* instr) {
 }
 
 
+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) {
   XMMRegister left = ToDoubleRegister(instr->InputAt(0));
   XMMRegister right = ToDoubleRegister(instr->InputAt(1));
index 6b5785257d480f2c9c586df22f891961118b9506..bd40a78828322c6038ea4cdd2c6058b5e260893d 100644 (file)
@@ -1330,6 +1330,26 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* 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) {
   ASSERT(instr->representation().IsDouble());
   // We call a C function for double power. It can't trigger a GC.
index e3ee8e9d70035b8d32247f1bdb8d81651655205c..7d9cb6ccab9b3803a3b8466cc3e3978a3d8b7ea7 100644 (file)
@@ -115,7 +115,6 @@ class LCodeGen;
   V(IsStringAndBranch)                          \
   V(IsSmiAndBranch)                             \
   V(IsUndetectableAndBranch)                    \
-  V(StringCompareAndBranch)                     \
   V(JSArrayLength)                              \
   V(Label)                                      \
   V(LazyBailout)                                \
@@ -133,6 +132,7 @@ class LCodeGen;
   V(LoadNamedFieldPolymorphic)                  \
   V(LoadNamedGeneric)                           \
   V(MathFloorOfDiv)                             \
+  V(MathMinMax)                                 \
   V(ModI)                                       \
   V(MulI)                                       \
   V(NumberTagD)                                 \
@@ -163,6 +163,7 @@ class LCodeGen;
   V(StringAdd)                                  \
   V(StringCharCodeAt)                           \
   V(StringCharFromCode)                         \
+  V(StringCompareAndBranch)                     \
   V(StringLength)                               \
   V(SubI)                                       \
   V(TaggedToI)                                  \
@@ -1064,6 +1065,18 @@ class LAddI: public LTemplateInstruction<1, 2, 0> {
 };
 
 
+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) {