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:
jkummerow@chromium.org 2012-08-06 14:28:27 +00:00
parent 92f30d1df5
commit 23a270c6e7
17 changed files with 444 additions and 148 deletions

View 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.

View 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) {

View 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));

View 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]));
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;
}

View 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

View 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) {

View 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)

View 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;

View 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);

View 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);

View 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;

View 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));

View 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.

View 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) {

View 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));

View 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.

View 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) {