PPC: [builtins] Make Math.max and Math.min fast by default.
Port cb9b801069
Original commit message:
The previous versions of Math.max and Math.min made it difficult to
optimize those (that's why we already have custom code in Crankshaft),
and due to lack of ideas what to do about the variable number of
arguments, we will probably need to stick in special code in TurboFan
as well; so inlining those builtins is off the table, hence there's no
real advantage in having them around as "not quite JS" with extra work
necessary in the optimizing compilers to still make those builtins
somewhat fast in cases where we cannot inline them (also there's a
tricky deopt loop in Crankshaft related to Math.min and Math.max, but
that will be dealt with later).
So to sum up: Instead of trying to make Math.max and Math.min semi-fast
in the optimizing compilers with weird work-arounds support %_Arguments
%_ArgumentsLength, we do provide the optimal code as native builtins
instead and call it a day (which gives a nice performance boost on some
benchmarks).
R=bmeurer@chromium.org, joransiu@ca.ibm.com, jyan@ca.ibm.com, michael_dawson@ca.ibm.com
BUG=
Review URL: https://codereview.chromium.org/1648353002
Cr-Commit-Position: refs/heads/master@{#33618}
This commit is contained in:
parent
0dc1e186e0
commit
3641a44883
@ -135,6 +135,119 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r3 : number of arguments
|
||||
// -- lr : return address
|
||||
// -- sp[(argc - n) * 8] : arg[n] (zero-based)
|
||||
// -- sp[(argc + 1) * 8] : receiver
|
||||
// -----------------------------------
|
||||
Condition const cond_done = (kind == MathMaxMinKind::kMin) ? lt : gt;
|
||||
Heap::RootListIndex const root_index =
|
||||
(kind == MathMaxMinKind::kMin) ? Heap::kInfinityValueRootIndex
|
||||
: Heap::kMinusInfinityValueRootIndex;
|
||||
DoubleRegister const reg = (kind == MathMaxMinKind::kMin) ? d2 : d1;
|
||||
|
||||
// Load the accumulator with the default return value (either -Infinity or
|
||||
// +Infinity), with the tagged value in r4 and the double value in d1.
|
||||
__ LoadRoot(r4, root_index);
|
||||
__ lfd(d1, FieldMemOperand(r4, HeapNumber::kValueOffset));
|
||||
|
||||
// Setup state for loop
|
||||
// r5: address of arg[0] + kPointerSize
|
||||
// r6: number of arguments
|
||||
__ ShiftLeftImm(r5, r3, Operand(kPointerSizeLog2));
|
||||
__ add(r5, sp, r5);
|
||||
__ mr(r6, r3);
|
||||
|
||||
Label done_loop, loop;
|
||||
__ bind(&loop);
|
||||
{
|
||||
// Check if all parameters done.
|
||||
__ cmpl(r5, sp);
|
||||
__ ble(&done_loop);
|
||||
|
||||
// Load the next parameter tagged value into r3.
|
||||
__ LoadPU(r3, MemOperand(r5, -kPointerSize));
|
||||
|
||||
// Load the double value of the parameter into d2, maybe converting the
|
||||
// parameter to a number first using the ToNumberStub if necessary.
|
||||
Label convert, convert_smi, convert_number, done_convert;
|
||||
__ bind(&convert);
|
||||
__ JumpIfSmi(r3, &convert_smi);
|
||||
__ LoadP(r7, FieldMemOperand(r3, HeapObject::kMapOffset));
|
||||
__ JumpIfRoot(r7, Heap::kHeapNumberMapRootIndex, &convert_number);
|
||||
{
|
||||
// Parameter is not a Number, use the ToNumberStub to convert it.
|
||||
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
||||
__ SmiTag(r6);
|
||||
__ Push(r4, r5, r6);
|
||||
ToNumberStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ Pop(r4, r5, r6);
|
||||
__ SmiUntag(r6);
|
||||
{
|
||||
// Restore the double accumulator value (d1).
|
||||
Label restore_smi, done_restore;
|
||||
__ JumpIfSmi(r4, &restore_smi);
|
||||
__ lfd(d1, FieldMemOperand(r4, HeapNumber::kValueOffset));
|
||||
__ b(&done_restore);
|
||||
__ bind(&restore_smi);
|
||||
__ SmiToDouble(d1, r4);
|
||||
__ bind(&done_restore);
|
||||
}
|
||||
}
|
||||
__ b(&convert);
|
||||
__ bind(&convert_number);
|
||||
__ lfd(d2, FieldMemOperand(r3, HeapNumber::kValueOffset));
|
||||
__ b(&done_convert);
|
||||
__ bind(&convert_smi);
|
||||
__ SmiToDouble(d2, r3);
|
||||
__ bind(&done_convert);
|
||||
|
||||
// Perform the actual comparison with the accumulator value on the left hand
|
||||
// side (d1) and the next parameter value on the right hand side (d2).
|
||||
Label compare_nan, compare_swap;
|
||||
__ fcmpu(d1, d2);
|
||||
__ bunordered(&compare_nan);
|
||||
__ b(cond_done, &loop);
|
||||
__ b(CommuteCondition(cond_done), &compare_swap);
|
||||
|
||||
// Left and right hand side are equal, check for -0 vs. +0.
|
||||
#if V8_TARGET_ARCH_PPC64
|
||||
__ MovDoubleToInt64(r7, reg);
|
||||
__ rotldi(r7, r7, 1);
|
||||
__ cmpi(r7, Operand(1));
|
||||
#else
|
||||
__ MovDoubleToInt64(r7, r8, reg);
|
||||
__ cmpi(r8, Operand::Zero());
|
||||
__ bne(&loop);
|
||||
__ lis(r8, Operand(SIGN_EXT_IMM16(0x8000)));
|
||||
__ cmp(r7, r8);
|
||||
#endif
|
||||
__ bne(&loop);
|
||||
|
||||
// Update accumulator. Result is on the right hand side.
|
||||
__ bind(&compare_swap);
|
||||
__ fmr(d1, d2);
|
||||
__ mr(r4, r3);
|
||||
__ b(&loop);
|
||||
|
||||
// At least one side is NaN, which means that the result will be NaN too.
|
||||
// We still need to visit the rest of the arguments.
|
||||
__ bind(&compare_nan);
|
||||
__ LoadRoot(r4, Heap::kNanValueRootIndex);
|
||||
__ lfd(d1, FieldMemOperand(r4, HeapNumber::kValueOffset));
|
||||
__ b(&loop);
|
||||
}
|
||||
|
||||
__ bind(&done_loop);
|
||||
__ mr(r3, r4);
|
||||
__ Drop(r6);
|
||||
__ Ret(1);
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
|
@ -183,6 +183,10 @@ void MacroAssembler::Drop(int count) {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::Drop(Register count, Register scratch) {
|
||||
ShiftLeftImm(scratch, count, Operand(kPointerSizeLog2));
|
||||
add(sp, sp, scratch);
|
||||
}
|
||||
|
||||
void MacroAssembler::Call(Label* target) { b(target, SetLK); }
|
||||
|
||||
|
@ -147,6 +147,7 @@ class MacroAssembler : public Assembler {
|
||||
// Emit code to discard a non-negative number of pointer-sized elements
|
||||
// from the stack, clobbering only the sp register.
|
||||
void Drop(int count);
|
||||
void Drop(Register count, Register scratch = r0);
|
||||
|
||||
void Ret(int drop) {
|
||||
Drop(drop);
|
||||
|
Loading…
Reference in New Issue
Block a user