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:
mbrandy 2016-01-29 11:32:39 -08:00 committed by Commit bot
parent 0dc1e186e0
commit 3641a44883
3 changed files with 118 additions and 0 deletions

View File

@ -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 -------------

View File

@ -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); }

View File

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