[turbofan] Optimize call on Math.min/Math.max with JSArray of double elements
This change inline call to Math.min/Math.max like Math.min.apply(this, arguments_list) to avoid packing and unpacking doubles during the optimized code execution. Change-Id: I674476f688213df8eb13ee8c876b280c8fa47263 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3799214 Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Commit-Queue: Fanchen Kong <fanchen.kong@intel.com> Cr-Commit-Position: refs/heads/main@{#83810}
This commit is contained in:
parent
fafd7c5d22
commit
680225d17e
@ -240,6 +240,7 @@ class EffectControlLinearizer {
|
||||
Node* LowerFoldConstant(Node* node);
|
||||
Node* LowerConvertReceiver(Node* node);
|
||||
Node* LowerDateNow(Node* node);
|
||||
Node* LowerDoubleArrayMinMax(Node* node);
|
||||
|
||||
// Lowering of optional operators.
|
||||
Maybe<Node*> LowerFloat64RoundUp(Node* node);
|
||||
@ -1417,6 +1418,10 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
|
||||
case IrOpcode::kFoldConstant:
|
||||
result = LowerFoldConstant(node);
|
||||
break;
|
||||
case IrOpcode::kDoubleArrayMax:
|
||||
case IrOpcode::kDoubleArrayMin:
|
||||
result = LowerDoubleArrayMinMax(node);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -6266,6 +6271,48 @@ Node* EffectControlLinearizer::LowerFoldConstant(Node* node) {
|
||||
return constant;
|
||||
}
|
||||
|
||||
Node* EffectControlLinearizer::LowerDoubleArrayMinMax(Node* node) {
|
||||
DCHECK(node->opcode() == IrOpcode::kDoubleArrayMin ||
|
||||
node->opcode() == IrOpcode::kDoubleArrayMax);
|
||||
|
||||
bool is_max = node->opcode() == IrOpcode::kDoubleArrayMax;
|
||||
Node* arguments_list = node->InputAt(0);
|
||||
|
||||
// Iterate the elements and find the result.
|
||||
Node* empty_value = is_max ? __ Float64Constant(-V8_INFINITY)
|
||||
: __ Float64Constant(V8_INFINITY);
|
||||
Node* array_length = __ LoadField(
|
||||
AccessBuilder::ForJSArrayLength(ElementsKind::PACKED_DOUBLE_ELEMENTS),
|
||||
arguments_list);
|
||||
array_length = ChangeSmiToIntPtr(array_length);
|
||||
Node* elements =
|
||||
__ LoadField(AccessBuilder::ForJSObjectElements(), arguments_list);
|
||||
|
||||
auto loop = __ MakeLoopLabel(MachineType::PointerRepresentation(),
|
||||
MachineRepresentation::kFloat64);
|
||||
auto done = __ MakeLabel(MachineRepresentation::kFloat64);
|
||||
|
||||
__ Goto(&loop, __ IntPtrConstant(0), empty_value);
|
||||
__ Bind(&loop);
|
||||
{
|
||||
Node* index = loop.PhiAt(0);
|
||||
Node* accumulator = loop.PhiAt(1);
|
||||
|
||||
Node* check = __ UintLessThan(index, array_length);
|
||||
__ GotoIfNot(check, &done, accumulator);
|
||||
|
||||
Node* element = __ LoadElement(AccessBuilder::ForFixedDoubleArrayElement(),
|
||||
elements, index);
|
||||
__ Goto(&loop, __ IntAdd(index, __ IntPtrConstant(1)),
|
||||
is_max ? __ Float64Max(accumulator, element)
|
||||
: __ Float64Min(accumulator, element));
|
||||
}
|
||||
|
||||
__ Bind(&done);
|
||||
return ChangeFloat64ToTagged(done.PhiAt(0),
|
||||
CheckForMinusZeroMode::kCheckForMinusZero);
|
||||
}
|
||||
|
||||
Node* EffectControlLinearizer::LowerConvertReceiver(Node* node) {
|
||||
ConvertReceiverMode const mode = ConvertReceiverModeOf(node->op());
|
||||
Node* value = node->InputAt(0);
|
||||
|
@ -330,6 +330,18 @@ TNode<Boolean> JSGraphAssembler::NumberLessThanOrEqual(TNode<Number> lhs,
|
||||
graph()->NewNode(simplified()->NumberLessThanOrEqual(), lhs, rhs));
|
||||
}
|
||||
|
||||
TNode<Number> JSGraphAssembler::NumberShiftRightLogical(TNode<Number> lhs,
|
||||
TNode<Number> rhs) {
|
||||
return AddNode<Number>(
|
||||
graph()->NewNode(simplified()->NumberShiftRightLogical(), lhs, rhs));
|
||||
}
|
||||
|
||||
TNode<Number> JSGraphAssembler::NumberBitwiseAnd(TNode<Number> lhs,
|
||||
TNode<Number> rhs) {
|
||||
return AddNode<Number>(
|
||||
graph()->NewNode(simplified()->NumberBitwiseAnd(), lhs, rhs));
|
||||
}
|
||||
|
||||
TNode<String> JSGraphAssembler::StringSubstring(TNode<String> string,
|
||||
TNode<Number> from,
|
||||
TNode<Number> to) {
|
||||
@ -342,6 +354,10 @@ TNode<Boolean> JSGraphAssembler::ObjectIsCallable(TNode<Object> value) {
|
||||
graph()->NewNode(simplified()->ObjectIsCallable(), value));
|
||||
}
|
||||
|
||||
TNode<Boolean> JSGraphAssembler::ObjectIsSmi(TNode<Object> value) {
|
||||
return AddNode<Boolean>(graph()->NewNode(simplified()->ObjectIsSmi(), value));
|
||||
}
|
||||
|
||||
TNode<Boolean> JSGraphAssembler::ObjectIsUndetectable(TNode<Object> value) {
|
||||
return AddNode<Boolean>(
|
||||
graph()->NewNode(simplified()->ObjectIsUndetectable(), value));
|
||||
@ -379,6 +395,16 @@ TNode<FixedArrayBase> JSGraphAssembler::MaybeGrowFastElements(
|
||||
index_needed, old_length, effect(), control()));
|
||||
}
|
||||
|
||||
TNode<Object> JSGraphAssembler::DoubleArrayMax(TNode<JSArray> array) {
|
||||
return AddNode<Object>(graph()->NewNode(simplified()->DoubleArrayMax(), array,
|
||||
effect(), control()));
|
||||
}
|
||||
|
||||
TNode<Object> JSGraphAssembler::DoubleArrayMin(TNode<JSArray> array) {
|
||||
return AddNode<Object>(graph()->NewNode(simplified()->DoubleArrayMax(), array,
|
||||
effect(), control()));
|
||||
}
|
||||
|
||||
Node* JSGraphAssembler::StringCharCodeAt(TNode<String> string,
|
||||
TNode<Number> position) {
|
||||
return AddNode(graph()->NewNode(simplified()->StringCharCodeAt(), string,
|
||||
|
@ -70,6 +70,8 @@ class Reducer;
|
||||
V(Float64InsertLowWord32) \
|
||||
V(Float64LessThan) \
|
||||
V(Float64LessThanOrEqual) \
|
||||
V(Float64Max) \
|
||||
V(Float64Min) \
|
||||
V(Float64Mod) \
|
||||
V(Float64Sub) \
|
||||
V(Int32Add) \
|
||||
@ -945,9 +947,12 @@ class V8_EXPORT_PRIVATE JSGraphAssembler : public GraphAssembler {
|
||||
TNode<Boolean> NumberLessThanOrEqual(TNode<Number> lhs, TNode<Number> rhs);
|
||||
TNode<Number> NumberAdd(TNode<Number> lhs, TNode<Number> rhs);
|
||||
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<String> StringSubstring(TNode<String> string, TNode<Number> from,
|
||||
TNode<Number> to);
|
||||
TNode<Boolean> ObjectIsCallable(TNode<Object> value);
|
||||
TNode<Boolean> ObjectIsSmi(TNode<Object> value);
|
||||
TNode<Boolean> ObjectIsUndetectable(TNode<Object> value);
|
||||
Node* CheckIf(Node* cond, DeoptimizeReason reason);
|
||||
TNode<Boolean> NumberIsFloat64Hole(TNode<Number> value);
|
||||
@ -960,6 +965,8 @@ class V8_EXPORT_PRIVATE JSGraphAssembler : public GraphAssembler {
|
||||
TNode<Number> new_length,
|
||||
TNode<Number> old_length);
|
||||
Node* StringCharCodeAt(TNode<String> string, TNode<Number> position);
|
||||
TNode<Object> DoubleArrayMax(TNode<JSArray> array);
|
||||
TNode<Object> DoubleArrayMin(TNode<JSArray> array);
|
||||
|
||||
JSGraph* jsgraph() const { return jsgraph_; }
|
||||
Isolate* isolate() const { return jsgraph()->isolate(); }
|
||||
|
@ -83,6 +83,7 @@ class JSCallReducerAssembler : public JSGraphAssembler {
|
||||
TNode<Boolean> ReduceStringPrototypeStartsWith(
|
||||
const StringRef& search_element_string);
|
||||
TNode<String> ReduceStringPrototypeSlice();
|
||||
TNode<Object> ReduceJSCallMathMinMaxWithArrayLike(Builtin builtin);
|
||||
|
||||
TNode<Object> TargetInput() const { return JSCallNode{node_ptr()}.target(); }
|
||||
|
||||
@ -294,6 +295,8 @@ class JSCallReducerAssembler : public JSGraphAssembler {
|
||||
return NumberAdd(value, OneConstant());
|
||||
}
|
||||
|
||||
TNode<Number> LoadMapElementsKind(TNode<Map> map);
|
||||
|
||||
void MaybeInsertMapChecks(MapInference* inference,
|
||||
bool has_stability_dependency) {
|
||||
// TODO(jgruber): Implement MapInference::InsertMapChecks in graph
|
||||
@ -1157,6 +1160,15 @@ TNode<JSArray> JSCallReducerAssembler::AllocateEmptyJSArray(
|
||||
return TNode<JSArray>::UncheckedCast(result);
|
||||
}
|
||||
|
||||
TNode<Number> JSCallReducerAssembler::LoadMapElementsKind(TNode<Map> map) {
|
||||
TNode<Number> bit_field2 =
|
||||
LoadField<Number>(AccessBuilder::ForMapBitField2(), map);
|
||||
return NumberShiftRightLogical(
|
||||
NumberBitwiseAnd(bit_field2,
|
||||
NumberConstant(Map::Bits2::ElementsKindBits::kMask)),
|
||||
NumberConstant(Map::Bits2::ElementsKindBits::kShift));
|
||||
}
|
||||
|
||||
TNode<Object> JSCallReducerAssembler::ReduceMathUnary(const Operator* op) {
|
||||
TNode<Object> input = Argument(0);
|
||||
TNode<Number> input_as_number = SpeculativeToNumber(input);
|
||||
@ -1327,6 +1339,57 @@ TNode<String> JSCallReducerAssembler::ReduceStringPrototypeSlice() {
|
||||
.Value();
|
||||
}
|
||||
|
||||
TNode<Object> JSCallReducerAssembler::ReduceJSCallMathMinMaxWithArrayLike(
|
||||
Builtin builtin) {
|
||||
JSCallWithArrayLikeNode n(node_ptr());
|
||||
TNode<Object> arguments_list = n.Argument(0);
|
||||
|
||||
auto call_builtin = MakeLabel();
|
||||
auto done = MakeLabel(MachineRepresentation::kTagged);
|
||||
|
||||
// Check if {arguments_list} is a JSArray.
|
||||
GotoIf(ObjectIsSmi(arguments_list), &call_builtin);
|
||||
TNode<Map> arguments_list_map =
|
||||
LoadField<Map>(AccessBuilder::ForMap(),
|
||||
TNode<HeapObject>::UncheckedCast(arguments_list));
|
||||
TNode<Number> arguments_list_instance_type = LoadField<Number>(
|
||||
AccessBuilder::ForMapInstanceType(), arguments_list_map);
|
||||
auto check_instance_type =
|
||||
NumberEqual(arguments_list_instance_type, NumberConstant(JS_ARRAY_TYPE));
|
||||
GotoIfNot(check_instance_type, &call_builtin);
|
||||
|
||||
// Check if {arguments_list} has PACKED_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);
|
||||
|
||||
// If {arguments_list} is a JSArray with PACKED_DOUBLE_ELEMENTS, calculate the
|
||||
// result with inlined loop.
|
||||
TNode<JSArray> array_arguments_list =
|
||||
TNode<JSArray>::UncheckedCast(arguments_list);
|
||||
Goto(&done, builtin == Builtin::kMathMax
|
||||
? DoubleArrayMax(array_arguments_list)
|
||||
: DoubleArrayMin(array_arguments_list));
|
||||
|
||||
// Otherwise, call BuiltinMathMin/Max as usual.
|
||||
Bind(&call_builtin);
|
||||
TNode<Object> call = CopyNode();
|
||||
CallParameters const& p = n.Parameters();
|
||||
|
||||
// Set SpeculationMode to kDisallowSpeculation to avoid infinite
|
||||
// recursion.
|
||||
NodeProperties::ChangeOp(
|
||||
call, javascript()->CallWithArrayLike(
|
||||
p.frequency(), p.feedback(),
|
||||
SpeculationMode::kDisallowSpeculation, p.feedback_relation()));
|
||||
Goto(&done, call);
|
||||
|
||||
Bind(&done);
|
||||
return done.PhiAt<Object>(0);
|
||||
}
|
||||
|
||||
TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeAt(
|
||||
ZoneVector<ElementsKind> kinds, bool needs_fallback_builtin_call,
|
||||
Node* receiver_kind) {
|
||||
@ -5192,6 +5255,13 @@ Reduction JSCallReducer::ReduceJSCallWithArrayLike(Node* node) {
|
||||
if (TargetIsClassConstructor(node, broker())) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
base::Optional<Reduction> maybe_result =
|
||||
TryReduceJSCallMathMinMaxWithArrayLike(node);
|
||||
if (maybe_result.has_value()) {
|
||||
return maybe_result.value();
|
||||
}
|
||||
|
||||
return ReduceCallOrConstructWithArrayLikeOrSpread(
|
||||
node, n.ArgumentCount(), n.LastArgumentIndex(), p.frequency(),
|
||||
p.feedback(), p.speculation_mode(), p.feedback_relation(), n.target(),
|
||||
@ -8410,6 +8480,108 @@ Reduction JSCallReducer::ReduceBigIntAsN(Node* node, Builtin builtin) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
base::Optional<Reduction> JSCallReducer::TryReduceJSCallMathMinMaxWithArrayLike(
|
||||
Node* node) {
|
||||
if (!v8_flags.turbo_optimize_math_minmax) return base::nullopt;
|
||||
|
||||
JSCallWithArrayLikeNode n(node);
|
||||
CallParameters const& p = n.Parameters();
|
||||
Node* target = n.target();
|
||||
Effect effect = n.effect();
|
||||
Control control = n.control();
|
||||
|
||||
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
|
||||
return base::nullopt;
|
||||
}
|
||||
|
||||
if (n.ArgumentCount() != 1) {
|
||||
return base::nullopt;
|
||||
}
|
||||
|
||||
// These ops are handled by ReduceCallOrConstructWithArrayLikeOrSpread.
|
||||
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;
|
||||
}
|
||||
|
||||
HeapObjectMatcher m(target);
|
||||
if (m.HasResolvedValue()) {
|
||||
ObjectRef target_ref = m.Ref(broker());
|
||||
if (target_ref.IsJSFunction()) {
|
||||
JSFunctionRef function = target_ref.AsJSFunction();
|
||||
|
||||
// Don't inline cross native context.
|
||||
if (!function.native_context().equals(native_context())) {
|
||||
return base::nullopt;
|
||||
}
|
||||
|
||||
SharedFunctionInfoRef shared = function.shared();
|
||||
Builtin builtin =
|
||||
shared.HasBuiltinId() ? shared.builtin_id() : Builtin::kNoBuiltinId;
|
||||
if (builtin == Builtin::kMathMax || builtin == Builtin::kMathMin) {
|
||||
return ReduceJSCallMathMinMaxWithArrayLike(node, builtin);
|
||||
} else {
|
||||
return base::nullopt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try specialize the JSCallWithArrayLike node with feedback target.
|
||||
if (ShouldUseCallICFeedback(target) &&
|
||||
p.feedback_relation() == CallFeedbackRelation::kTarget &&
|
||||
p.feedback().IsValid()) {
|
||||
ProcessedFeedback const& feedback =
|
||||
broker()->GetFeedbackForCall(p.feedback());
|
||||
if (feedback.IsInsufficient()) {
|
||||
return base::nullopt;
|
||||
}
|
||||
base::Optional<HeapObjectRef> feedback_target = feedback.AsCall().target();
|
||||
if (feedback_target.has_value() && feedback_target->map().is_callable()) {
|
||||
Node* target_function = jsgraph()->Constant(*feedback_target);
|
||||
ObjectRef target_ref = feedback_target.value();
|
||||
if (!target_ref.IsJSFunction()) {
|
||||
return base::nullopt;
|
||||
}
|
||||
JSFunctionRef function = target_ref.AsJSFunction();
|
||||
SharedFunctionInfoRef shared = function.shared();
|
||||
Builtin builtin =
|
||||
shared.HasBuiltinId() ? shared.builtin_id() : Builtin::kNoBuiltinId;
|
||||
if (builtin == Builtin::kMathMax || builtin == Builtin::kMathMin) {
|
||||
// Check that the {target} is still the {target_function}.
|
||||
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
|
||||
target_function);
|
||||
effect = graph()->NewNode(
|
||||
simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check,
|
||||
effect, control);
|
||||
|
||||
// Specialize the JSCallWithArrayLike node to the {target_function}.
|
||||
NodeProperties::ReplaceValueInput(node, target_function,
|
||||
n.TargetIndex());
|
||||
NodeProperties::ReplaceEffectInput(node, effect);
|
||||
// Try to further reduce the Call MathMin/Max with double array.
|
||||
return Changed(node).FollowedBy(
|
||||
ReduceJSCallMathMinMaxWithArrayLike(node, builtin));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return base::nullopt;
|
||||
}
|
||||
|
||||
Reduction JSCallReducer::ReduceJSCallMathMinMaxWithArrayLike(Node* node,
|
||||
Builtin builtin) {
|
||||
JSCallWithArrayLikeNode n(node);
|
||||
DCHECK_NE(n.Parameters().speculation_mode(),
|
||||
SpeculationMode::kDisallowSpeculation);
|
||||
DCHECK_EQ(n.ArgumentCount(), 1);
|
||||
|
||||
JSCallReducerAssembler a(this, node);
|
||||
Node* subgraph = a.ReduceJSCallMathMinMaxWithArrayLike(builtin);
|
||||
return ReplaceWithSubgraph(&a, subgraph);
|
||||
}
|
||||
|
||||
CompilationDependencies* JSCallReducer::dependencies() const {
|
||||
return broker()->dependencies();
|
||||
}
|
||||
|
@ -229,6 +229,9 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
|
||||
Reduction ReduceNumberConstructor(Node* node);
|
||||
Reduction ReduceBigIntAsN(Node* node, Builtin builtin);
|
||||
|
||||
base::Optional<Reduction> TryReduceJSCallMathMinMaxWithArrayLike(Node* node);
|
||||
Reduction ReduceJSCallMathMinMaxWithArrayLike(Node* node, Builtin builtin);
|
||||
|
||||
// The pendant to ReplaceWithValue when using GraphAssembler-based reductions.
|
||||
Reduction ReplaceWithSubgraph(JSCallReducerAssembler* gasm, Node* subgraph);
|
||||
|
||||
|
@ -430,6 +430,8 @@
|
||||
V(ConvertReceiver) \
|
||||
V(ConvertTaggedHoleToUndefined) \
|
||||
V(DateNow) \
|
||||
V(DoubleArrayMax) \
|
||||
V(DoubleArrayMin) \
|
||||
V(EnsureWritableFastElements) \
|
||||
V(FastApiCall) \
|
||||
V(FindOrderedHashMapEntry) \
|
||||
|
@ -4117,6 +4117,14 @@ class RepresentationSelector {
|
||||
case IrOpcode::kDateNow:
|
||||
VisitInputs<T>(node);
|
||||
return SetOutput<T>(node, MachineRepresentation::kTagged);
|
||||
case IrOpcode::kDoubleArrayMax: {
|
||||
return VisitUnop<T>(node, UseInfo::AnyTagged(),
|
||||
MachineRepresentation::kTagged);
|
||||
}
|
||||
case IrOpcode::kDoubleArrayMin: {
|
||||
return VisitUnop<T>(node, UseInfo::AnyTagged(),
|
||||
MachineRepresentation::kTagged);
|
||||
}
|
||||
case IrOpcode::kFrameState:
|
||||
return VisitFrameState<T>(FrameState{node});
|
||||
case IrOpcode::kStateValues:
|
||||
|
@ -812,7 +812,9 @@ bool operator==(CheckMinusZeroParameters const& lhs,
|
||||
V(StringCodePointAt, Operator::kNoProperties, 2, 1) \
|
||||
V(StringFromCodePointAt, Operator::kNoProperties, 2, 1) \
|
||||
V(StringSubstring, Operator::kNoProperties, 3, 1) \
|
||||
V(DateNow, Operator::kNoProperties, 0, 1)
|
||||
V(DateNow, Operator::kNoProperties, 0, 1) \
|
||||
V(DoubleArrayMax, Operator::kNoProperties, 1, 1) \
|
||||
V(DoubleArrayMin, Operator::kNoProperties, 1, 1)
|
||||
|
||||
#define SPECULATIVE_NUMBER_BINOP_LIST(V) \
|
||||
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \
|
||||
|
@ -1087,6 +1087,11 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
|
||||
#endif
|
||||
|
||||
const Operator* DateNow();
|
||||
|
||||
// Math.min/max for JSArray with PACKED_DOUBLE_ELEMENTS.
|
||||
const Operator* DoubleArrayMin();
|
||||
const Operator* DoubleArrayMax();
|
||||
|
||||
// Unsigned32Divide is a special operator to express the division of two
|
||||
// Unsigned32 inputs and truncating the result to Unsigned32. It's semantics
|
||||
// is equivalent to NumberFloor(NumberDivide(x:Unsigned32, y:Unsigned32)) but
|
||||
|
@ -1528,6 +1528,10 @@ Type Typer::Visitor::TypeJSObjectIsArray(Node* node) { return Type::Boolean(); }
|
||||
|
||||
Type Typer::Visitor::TypeDateNow(Node* node) { return Type::Number(); }
|
||||
|
||||
Type Typer::Visitor::TypeDoubleArrayMin(Node* node) { return Type::Number(); }
|
||||
|
||||
Type Typer::Visitor::TypeDoubleArrayMax(Node* node) { return Type::Number(); }
|
||||
|
||||
Type Typer::Visitor::TypeUnsigned32Divide(Node* node) {
|
||||
Type lhs = Operand(node, 0);
|
||||
return Type::Range(0, lhs.Max(), zone());
|
||||
|
@ -1535,7 +1535,11 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
|
||||
case IrOpcode::kAssertType:
|
||||
case IrOpcode::kVerifyType:
|
||||
break;
|
||||
|
||||
case IrOpcode::kDoubleArrayMin:
|
||||
case IrOpcode::kDoubleArrayMax:
|
||||
CheckValueInputIs(node, 0, Type::Any());
|
||||
CheckTypeIs(node, Type::Number());
|
||||
break;
|
||||
case IrOpcode::kCheckFloat64Hole:
|
||||
CheckValueInputIs(node, 0, Type::NumberOrHole());
|
||||
CheckTypeIs(node, Type::NumberOrUndefined());
|
||||
|
@ -943,6 +943,8 @@ DEFINE_BOOL(turbo_force_mid_tier_regalloc, false,
|
||||
"always use the mid-tier register allocator (for testing)")
|
||||
|
||||
DEFINE_BOOL(turbo_optimize_apply, true, "optimize Function.prototype.apply")
|
||||
DEFINE_BOOL(turbo_optimize_math_minmax, true,
|
||||
"optimize call math.min/max with double array")
|
||||
|
||||
DEFINE_BOOL(turbo_collect_feedback_in_generic_lowering, true,
|
||||
"enable experimental feedback collection in generic lowering.")
|
||||
|
Loading…
Reference in New Issue
Block a user