Commit 339c9c12 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Inlining Math.min and Math.max in crankshaft.

BUG=v8:1325
TEST=

Review URL: http://codereview.chromium.org/9147034

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10391 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent a42da8e3
...@@ -3903,6 +3903,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { ...@@ -3903,6 +3903,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
void LCodeGen::EmitNumberUntagD(Register input_reg, void LCodeGen::EmitNumberUntagD(Register input_reg,
DoubleRegister result_reg, DoubleRegister result_reg,
bool deoptimize_on_undefined, bool deoptimize_on_undefined,
bool deoptimize_on_minus_zero,
LEnvironment* env) { LEnvironment* env) {
Register scratch = scratch0(); Register scratch = scratch0();
SwVfpRegister flt_scratch = double_scratch0().low(); SwVfpRegister flt_scratch = double_scratch0().low();
...@@ -3938,6 +3939,14 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, ...@@ -3938,6 +3939,14 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
// Heap number to double register conversion. // Heap number to double register conversion.
__ sub(ip, input_reg, Operand(kHeapObjectTag)); __ sub(ip, input_reg, Operand(kHeapObjectTag));
__ vldr(result_reg, ip, HeapNumber::kValueOffset); __ vldr(result_reg, ip, HeapNumber::kValueOffset);
if (deoptimize_on_minus_zero) {
__ vmov(ip, result_reg.low());
__ cmp(ip, Operand(0));
__ b(ne, &done);
__ vmov(ip, result_reg.high());
__ cmp(ip, Operand(HeapNumber::kSignMask));
DeoptimizeIf(eq, env);
}
__ jmp(&done); __ jmp(&done);
// Smi to double register conversion // Smi to double register conversion
...@@ -4071,6 +4080,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { ...@@ -4071,6 +4080,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
EmitNumberUntagD(input_reg, result_reg, EmitNumberUntagD(input_reg, result_reg,
instr->hydrogen()->deoptimize_on_undefined(), instr->hydrogen()->deoptimize_on_undefined(),
instr->hydrogen()->deoptimize_on_minus_zero(),
instr->environment()); instr->environment());
} }
......
...@@ -273,6 +273,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -273,6 +273,7 @@ class LCodeGen BASE_EMBEDDED {
void EmitNumberUntagD(Register input, void EmitNumberUntagD(Register input,
DoubleRegister result, DoubleRegister result,
bool deoptimize_on_undefined, bool deoptimize_on_undefined,
bool deoptimize_on_minus_zero,
LEnvironment* env); LEnvironment* env);
// Emits optimized code for typeof x == "y". Modifies input register. // Emits optimized code for typeof x == "y". Modifies input register.
......
...@@ -1137,6 +1137,9 @@ class HChange: public HUnaryOperation { ...@@ -1137,6 +1137,9 @@ class HChange: public HUnaryOperation {
bool deoptimize_on_undefined() const { bool deoptimize_on_undefined() const {
return CheckFlag(kDeoptimizeOnUndefined); return CheckFlag(kDeoptimizeOnUndefined);
} }
bool deoptimize_on_minus_zero() const {
return CheckFlag(kBailoutOnMinusZero);
}
virtual Representation RequiredInputRepresentation(int index) { virtual Representation RequiredInputRepresentation(int index) {
return from(); return from();
} }
......
...@@ -5140,6 +5140,57 @@ bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, ...@@ -5140,6 +5140,57 @@ bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
return true; return true;
} }
break; break;
case kMathMax:
case kMathMin:
if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
AddCheckConstantFunction(expr, receiver, receiver_map, true);
HValue* right = Pop();
HValue* left = Pop();
// Do not inline if the return representation is not certain.
if (!left->representation().Equals(right->representation())) {
Push(left);
Push(right);
return false;
}
Pop(); // Pop receiver.
Token::Value op = (id == kMathMin) ? Token::LT : Token::GT;
HCompareIDAndBranch* compare = NULL;
if (left->representation().IsTagged()) {
HChange* left_cvt =
new(zone()) HChange(left, Representation::Double(), false, true);
left_cvt->SetFlag(HValue::kBailoutOnMinusZero);
AddInstruction(left_cvt);
HChange* right_cvt =
new(zone()) HChange(right, Representation::Double(), false, true);
right_cvt->SetFlag(HValue::kBailoutOnMinusZero);
AddInstruction(right_cvt);
compare = new(zone()) HCompareIDAndBranch(left_cvt, right_cvt, op);
compare->SetInputRepresentation(Representation::Double());
} else {
compare = new(zone()) HCompareIDAndBranch(left, right, op);
compare->SetInputRepresentation(left->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);
Push(right);
HBasicBlock* join = CreateJoin(return_left, return_right, expr->id());
set_current_block(join);
ast_context()->ReturnValue(Pop());
return true;
}
break;
default: default:
// Not yet supported for inlining. // Not yet supported for inlining.
break; break;
......
...@@ -3699,8 +3699,10 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { ...@@ -3699,8 +3699,10 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
void LCodeGen::EmitNumberUntagD(Register input_reg, void LCodeGen::EmitNumberUntagD(Register input_reg,
Register temp_reg,
XMMRegister result_reg, XMMRegister result_reg,
bool deoptimize_on_undefined, bool deoptimize_on_undefined,
bool deoptimize_on_minus_zero,
LEnvironment* env) { LEnvironment* env) {
Label load_smi, done; Label load_smi, done;
...@@ -3729,6 +3731,15 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, ...@@ -3729,6 +3731,15 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
} }
// Heap number to XMM conversion. // Heap number to XMM conversion.
__ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset)); __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
if (deoptimize_on_minus_zero) {
XMMRegister xmm_scratch = xmm0;
__ xorps(xmm_scratch, xmm_scratch);
__ ucomisd(result_reg, xmm_scratch);
__ j(not_zero, &done, Label::kNear);
__ movmskpd(temp_reg, result_reg);
__ test_b(temp_reg, 1);
DeoptimizeIf(not_zero, env);
}
__ jmp(&done, Label::kNear); __ jmp(&done, Label::kNear);
// Smi to XMM conversion // Smi to XMM conversion
...@@ -3851,14 +3862,23 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { ...@@ -3851,14 +3862,23 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
LOperand* input = instr->InputAt(0); LOperand* input = instr->InputAt(0);
ASSERT(input->IsRegister()); ASSERT(input->IsRegister());
LOperand* temp = instr->TempAt(0);
ASSERT(temp == NULL || temp->IsRegister());
LOperand* result = instr->result(); LOperand* result = instr->result();
ASSERT(result->IsDoubleRegister()); ASSERT(result->IsDoubleRegister());
Register input_reg = ToRegister(input); Register input_reg = ToRegister(input);
XMMRegister result_reg = ToDoubleRegister(result); XMMRegister result_reg = ToDoubleRegister(result);
EmitNumberUntagD(input_reg, result_reg, bool deoptimize_on_minus_zero =
instr->hydrogen()->deoptimize_on_minus_zero();
Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
EmitNumberUntagD(input_reg,
temp_reg,
result_reg,
instr->hydrogen()->deoptimize_on_undefined(), instr->hydrogen()->deoptimize_on_undefined(),
deoptimize_on_minus_zero,
instr->environment()); instr->environment());
} }
......
...@@ -268,8 +268,10 @@ class LCodeGen BASE_EMBEDDED { ...@@ -268,8 +268,10 @@ class LCodeGen BASE_EMBEDDED {
void EmitGoto(int block); void EmitGoto(int block);
void EmitBranch(int left_block, int right_block, Condition cc); void EmitBranch(int left_block, int right_block, Condition cc);
void EmitNumberUntagD(Register input, void EmitNumberUntagD(Register input,
Register temp,
XMMRegister result, XMMRegister result,
bool deoptimize_on_undefined, bool deoptimize_on_undefined,
bool deoptimize_on_minus_zero,
LEnvironment* env); LEnvironment* env);
// Emits optimized code for typeof x == "y". Modifies input register. // Emits optimized code for typeof x == "y". Modifies input register.
......
...@@ -1682,7 +1682,11 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { ...@@ -1682,7 +1682,11 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
if (from.IsTagged()) { if (from.IsTagged()) {
if (to.IsDouble()) { if (to.IsDouble()) {
LOperand* value = UseRegister(instr->value()); LOperand* value = UseRegister(instr->value());
LNumberUntagD* res = new(zone()) LNumberUntagD(value); // Temp register only necessary for minus zero check.
LOperand* temp = instr->deoptimize_on_minus_zero()
? TempRegister()
: NULL;
LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp);
return AssignEnvironment(DefineAsRegister(res)); return AssignEnvironment(DefineAsRegister(res));
} else { } else {
ASSERT(to.IsInteger32()); ASSERT(to.IsInteger32());
......
...@@ -1624,10 +1624,11 @@ class LSmiTag: public LTemplateInstruction<1, 1, 0> { ...@@ -1624,10 +1624,11 @@ class LSmiTag: public LTemplateInstruction<1, 1, 0> {
}; };
class LNumberUntagD: public LTemplateInstruction<1, 1, 0> { class LNumberUntagD: public LTemplateInstruction<1, 1, 1> {
public: public:
explicit LNumberUntagD(LOperand* value) { explicit LNumberUntagD(LOperand* value, LOperand* temp) {
inputs_[0] = value; inputs_[0] = value;
temps_[0] = temp;
} }
DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag") DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
......
...@@ -4894,7 +4894,9 @@ class Script: public Struct { ...@@ -4894,7 +4894,9 @@ class Script: public Struct {
V(Math, exp, MathExp) \ V(Math, exp, MathExp) \
V(Math, sqrt, MathSqrt) \ V(Math, sqrt, MathSqrt) \
V(Math, pow, MathPow) \ V(Math, pow, MathPow) \
V(Math, random, MathRandom) V(Math, random, MathRandom) \
V(Math, max, MathMax) \
V(Math, min, MathMin)
enum BuiltinFunctionId { enum BuiltinFunctionId {
......
...@@ -3547,6 +3547,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { ...@@ -3547,6 +3547,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
void LCodeGen::EmitNumberUntagD(Register input_reg, void LCodeGen::EmitNumberUntagD(Register input_reg,
XMMRegister result_reg, XMMRegister result_reg,
bool deoptimize_on_undefined, bool deoptimize_on_undefined,
bool deoptimize_on_minus_zero,
LEnvironment* env) { LEnvironment* env) {
Label load_smi, done; Label load_smi, done;
...@@ -3574,6 +3575,15 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, ...@@ -3574,6 +3575,15 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
} }
// Heap number to XMM conversion. // Heap number to XMM conversion.
__ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset)); __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
if (deoptimize_on_minus_zero) {
XMMRegister xmm_scratch = xmm0;
__ xorps(xmm_scratch, xmm_scratch);
__ ucomisd(xmm_scratch, result_reg);
__ j(not_equal, &done, Label::kNear);
__ movmskpd(kScratchRegister, result_reg);
__ testq(kScratchRegister, Immediate(1));
DeoptimizeIf(not_zero, env);
}
__ jmp(&done, Label::kNear); __ jmp(&done, Label::kNear);
// Smi to XMM conversion // Smi to XMM conversion
...@@ -3665,6 +3675,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { ...@@ -3665,6 +3675,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
EmitNumberUntagD(input_reg, result_reg, EmitNumberUntagD(input_reg, result_reg,
instr->hydrogen()->deoptimize_on_undefined(), instr->hydrogen()->deoptimize_on_undefined(),
instr->hydrogen()->deoptimize_on_minus_zero(),
instr->environment()); instr->environment());
} }
......
...@@ -255,6 +255,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -255,6 +255,7 @@ class LCodeGen BASE_EMBEDDED {
void EmitNumberUntagD(Register input, void EmitNumberUntagD(Register input,
XMMRegister result, XMMRegister result,
bool deoptimize_on_undefined, bool deoptimize_on_undefined,
bool deoptimize_on_minus_zero,
LEnvironment* env); LEnvironment* env);
// Emits optimized code for typeof x == "y". Modifies input register. // Emits optimized code for typeof x == "y". Modifies input register.
......
...@@ -115,3 +115,67 @@ assertEquals(NaN, Math.max(1, 'oxen')); ...@@ -115,3 +115,67 @@ assertEquals(NaN, Math.max(1, 'oxen'));
assertEquals(Infinity, 1/Math.max(ZERO, -0)); assertEquals(Infinity, 1/Math.max(ZERO, -0));
assertEquals(Infinity, 1/Math.max(-0, ZERO)); assertEquals(Infinity, 1/Math.max(-0, ZERO));
function run(crankshaft_test) {
crankshaft_test(1);
crankshaft_test(1);
%OptimizeFunctionOnNextCall(crankshaft_test);
crankshaft_test(-0);
}
function crankshaft_test_1(arg) {
var v1 = 1;
var v2 = 5;
var v3 = 1.5;
var v4 = 5.5;
var v5 = 2;
var v6 = 6;
var v7 = 0;
var v8 = -0;
var v9 = 9.9;
var v0 = 10.1;
// Integer32 representation.
assertEquals(v2, Math.max(v1++, v2++));
assertEquals(v1, Math.min(v1++, v2++));
// Tagged representation.
assertEquals(v4, Math.max(v3, v4));
assertEquals(v3, Math.min(v3, v4));
assertEquals(v6, Math.max(v5, v6));
assertEquals(v5, Math.min(v5, v6));
// Double representation.
assertEquals(v0, Math.max(v0++, v9++));
assertEquals(v9, Math.min(v0++, v9++));
// Minus zero.
assertEquals(Infinity, 1/Math.max(v7, v8));
assertEquals(-Infinity, 1/Math.min(v7, v8));
// NaN.
assertEquals(NaN, Math.max(NaN, v8));
assertEquals(NaN, Math.min(NaN, v9));
assertEquals(NaN, Math.max(v8, NaN));
assertEquals(NaN, Math.min(v9, NaN));
// Minus zero as Integer32.
assertEquals((arg === -0) ? -Infinity : 1, 1/Math.min(arg, v2));
}
run(crankshaft_test_1);
function crankshaft_test_2() {
var v9 = {};
v9.valueOf = function() { return 6; }
// Deopt expected due to non-heapnumber objects.
assertEquals(6, Math.min(v9, 12));
}
run(crankshaft_test_2);
// Test overriding Math.min and Math.max
Math.min = function(a, b) { return a + b; }
Math.max = function(a, b) { return a - b; }
function crankshaft_test_3() {
assertEquals(8, Math.min(3, 5));
assertEquals(3, Math.max(5, 2));
}
run(crankshaft_test_3);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment