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) {
void LCodeGen::EmitNumberUntagD(Register input_reg,
DoubleRegister result_reg,
bool deoptimize_on_undefined,
bool deoptimize_on_minus_zero,
LEnvironment* env) {
Register scratch = scratch0();
SwVfpRegister flt_scratch = double_scratch0().low();
......@@ -3938,6 +3939,14 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
// Heap number to double register conversion.
__ sub(ip, input_reg, Operand(kHeapObjectTag));
__ 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);
// Smi to double register conversion
......@@ -4071,6 +4080,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
EmitNumberUntagD(input_reg, result_reg,
instr->hydrogen()->deoptimize_on_undefined(),
instr->hydrogen()->deoptimize_on_minus_zero(),
instr->environment());
}
......
......@@ -273,6 +273,7 @@ class LCodeGen BASE_EMBEDDED {
void EmitNumberUntagD(Register input,
DoubleRegister result,
bool deoptimize_on_undefined,
bool deoptimize_on_minus_zero,
LEnvironment* env);
// Emits optimized code for typeof x == "y". Modifies input register.
......
......@@ -1137,6 +1137,9 @@ class HChange: public HUnaryOperation {
bool deoptimize_on_undefined() const {
return CheckFlag(kDeoptimizeOnUndefined);
}
bool deoptimize_on_minus_zero() const {
return CheckFlag(kBailoutOnMinusZero);
}
virtual Representation RequiredInputRepresentation(int index) {
return from();
}
......
......@@ -5140,6 +5140,57 @@ bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
return true;
}
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:
// Not yet supported for inlining.
break;
......
......@@ -3699,8 +3699,10 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
void LCodeGen::EmitNumberUntagD(Register input_reg,
Register temp_reg,
XMMRegister result_reg,
bool deoptimize_on_undefined,
bool deoptimize_on_minus_zero,
LEnvironment* env) {
Label load_smi, done;
......@@ -3729,6 +3731,15 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
}
// Heap number to XMM conversion.
__ 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);
// Smi to XMM conversion
......@@ -3851,14 +3862,23 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
LOperand* input = instr->InputAt(0);
ASSERT(input->IsRegister());
LOperand* temp = instr->TempAt(0);
ASSERT(temp == NULL || temp->IsRegister());
LOperand* result = instr->result();
ASSERT(result->IsDoubleRegister());
Register input_reg = ToRegister(input);
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(),
deoptimize_on_minus_zero,
instr->environment());
}
......
......@@ -268,8 +268,10 @@ class LCodeGen BASE_EMBEDDED {
void EmitGoto(int block);
void EmitBranch(int left_block, int right_block, Condition cc);
void EmitNumberUntagD(Register input,
Register temp,
XMMRegister result,
bool deoptimize_on_undefined,
bool deoptimize_on_minus_zero,
LEnvironment* env);
// Emits optimized code for typeof x == "y". Modifies input register.
......
......@@ -1682,7 +1682,11 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
if (from.IsTagged()) {
if (to.IsDouble()) {
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));
} else {
ASSERT(to.IsInteger32());
......
......@@ -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:
explicit LNumberUntagD(LOperand* value) {
explicit LNumberUntagD(LOperand* value, LOperand* temp) {
inputs_[0] = value;
temps_[0] = temp;
}
DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
......
......@@ -4894,7 +4894,9 @@ class Script: public Struct {
V(Math, exp, MathExp) \
V(Math, sqrt, MathSqrt) \
V(Math, pow, MathPow) \
V(Math, random, MathRandom)
V(Math, random, MathRandom) \
V(Math, max, MathMax) \
V(Math, min, MathMin)
enum BuiltinFunctionId {
......
......@@ -3547,6 +3547,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
void LCodeGen::EmitNumberUntagD(Register input_reg,
XMMRegister result_reg,
bool deoptimize_on_undefined,
bool deoptimize_on_minus_zero,
LEnvironment* env) {
Label load_smi, done;
......@@ -3574,6 +3575,15 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
}
// Heap number to XMM conversion.
__ 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);
// Smi to XMM conversion
......@@ -3665,6 +3675,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
EmitNumberUntagD(input_reg, result_reg,
instr->hydrogen()->deoptimize_on_undefined(),
instr->hydrogen()->deoptimize_on_minus_zero(),
instr->environment());
}
......
......@@ -255,6 +255,7 @@ class LCodeGen BASE_EMBEDDED {
void EmitNumberUntagD(Register input,
XMMRegister result,
bool deoptimize_on_undefined,
bool deoptimize_on_minus_zero,
LEnvironment* env);
// Emits optimized code for typeof x == "y". Modifies input register.
......
......@@ -115,3 +115,67 @@ assertEquals(NaN, Math.max(1, 'oxen'));
assertEquals(Infinity, 1/Math.max(ZERO, -0));
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