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
This commit is contained in:
parent
a42da8e38d
commit
339c9c12e7
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user