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 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12265 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
92f30d1df5
commit
23a270c6e7
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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]));
|
||||
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_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 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);
|
||||
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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, ®op, &rm);
|
||||
AppendToBuffer("orpd %s,%s",
|
||||
NameOfXMMRegister(regop),
|
||||
NameOfXMMRegister(rm));
|
||||
data++;
|
||||
} else if (*data == 0x57) {
|
||||
data++;
|
||||
int mod, regop, rm;
|
||||
|
@ -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));
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user