[turbofan] Generalize optimization on CallWithArrayLike when target is Math.min/max

With this change, ReduceJSCallMathMinMaxWithArrayLike will work on both PACKED_DOUBLE_ELEMENTS and HOLEY_DOUBLE_ELEMETNS kind.

It will also work when the opcode of arguments_list is JSCreateEmptyLiteralArray to deal with following use cases.

    var array = [];
    array.push(num1); // add elements
    array.push(num2);
    console.log(Math.min.apply(Math, array));

Change-Id: I39840a17607c31baea2c6b1d33218700f723d760
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4007927
Commit-Queue: Fanchen Kong <fanchen.kong@intel.com>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#84079}
This commit is contained in:
Fanchen Kong 2022-11-08 03:23:40 +08:00 committed by V8 LUCI CQ
parent 1d28608ec0
commit f8e7c7ad7a
4 changed files with 50 additions and 5 deletions

View File

@ -398,6 +398,12 @@ TNode<Number> JSGraphAssembler::NumberBitwiseAnd(TNode<Number> lhs,
graph()->NewNode(simplified()->NumberBitwiseAnd(), lhs, rhs));
}
TNode<Number> JSGraphAssembler::NumberBitwiseOr(TNode<Number> lhs,
TNode<Number> rhs) {
return AddNode<Number>(
graph()->NewNode(simplified()->NumberBitwiseOr(), lhs, rhs));
}
TNode<String> JSGraphAssembler::StringSubstring(TNode<String> string,
TNode<Number> from,
TNode<Number> to) {

View File

@ -1008,6 +1008,7 @@ class V8_EXPORT_PRIVATE JSGraphAssembler : public GraphAssembler {
TNode<Number> NumberSubtract(TNode<Number> lhs, TNode<Number> rhs);
TNode<Number> NumberShiftRightLogical(TNode<Number> lhs, TNode<Number> rhs);
TNode<Number> NumberBitwiseAnd(TNode<Number> lhs, TNode<Number> rhs);
TNode<Number> NumberBitwiseOr(TNode<Number> lhs, TNode<Number> rhs);
TNode<Number> NumberDivide(TNode<Number> lhs, TNode<Number> rhs);
TNode<Number> NumberFloor(TNode<Number> value);
TNode<String> StringSubstring(TNode<String> string, TNode<Number> from,

View File

@ -1077,12 +1077,17 @@ TNode<Object> JSCallReducerAssembler::ReduceJSCallMathMinMaxWithArrayLike(
NumberEqual(arguments_list_instance_type, NumberConstant(JS_ARRAY_TYPE));
GotoIfNot(check_instance_type, &call_builtin);
// Check if {arguments_list} has PACKED_DOUBLE_ELEMENTS.
// Check if {arguments_list} has PACKED_DOUBLE_ELEMENTS or
// HOLEY_DOUBLE_ELEMENTS.
TNode<Number> arguments_list_elements_kind =
LoadMapElementsKind(arguments_list_map);
auto check_element_kind = NumberEqual(arguments_list_elements_kind,
NumberConstant(PACKED_DOUBLE_ELEMENTS));
GotoIfNot(check_element_kind, &call_builtin);
static_assert(PACKED_DOUBLE_ELEMENTS == 4);
static_assert(HOLEY_DOUBLE_ELEMENTS == 5);
auto check_elements_kind = NumberEqual(
NumberBitwiseOr(arguments_list_elements_kind, NumberConstant(1)),
NumberConstant(HOLEY_DOUBLE_ELEMENTS));
GotoIfNot(check_elements_kind, &call_builtin);
// If {arguments_list} is a JSArray with PACKED_DOUBLE_ELEMENTS, calculate the
// result with inlined loop.
@ -8345,10 +8350,15 @@ base::Optional<Reduction> JSCallReducer::TryReduceJSCallMathMinMaxWithArrayLike(
return base::nullopt;
}
if (!dependencies()->DependOnNoElementsProtector()) {
return base::nullopt;
}
// These ops are handled by ReduceCallOrConstructWithArrayLikeOrSpread.
// IrOpcode::kJSCreateEmptyLiteralArray is not included, since arguments_list
// for Math.min/min is not likely to keep empty.
Node* arguments_list = n.Argument(0);
if (arguments_list->opcode() == IrOpcode::kJSCreateLiteralArray ||
arguments_list->opcode() == IrOpcode::kJSCreateEmptyLiteralArray ||
arguments_list->opcode() == IrOpcode::kJSCreateArguments) {
return base::nullopt;
}

View File

@ -248,6 +248,34 @@
})();
// Test with holey double array and Math.min/max.
(function () {
"use strict";
function arrayMin(val) {
return Math.min.apply(Math, val);
}
function arrayMax(val) {
return Math.max.apply(Math, val);
}
%PrepareFunctionForOptimization(arrayMin);
%PrepareFunctionForOptimization(arrayMin);
assertEquals(NaN, arrayMin([11.03, 16.11, , 26.06]));
%PrepareFunctionForOptimization(arrayMax);
%PrepareFunctionForOptimization(arrayMax);
assertEquals(NaN, arrayMax([11.03, 16.11, , 26.06]));
%OptimizeFunctionOnNextCall(arrayMin);
%OptimizeFunctionOnNextCall(arrayMax);
assertEquals(NaN, arrayMin([11.03, 16.11, , 26.06]));
assertEquals(NaN, arrayMax([11.03, 16.11, , 26.06]));
assertOptimized(arrayMin);
assertOptimized(arrayMax);
})();
// Test Reflect.apply().
(function () {
"use strict";