[Turbofan] Specialize TransitionAndStoreElement
We can improve performance of inlined Array.prototype.map if we statically know the type of the callback return result is a SignedSmall. Indeed, we no longer need bother with transitioning the output array, because we can store a SignedSmall (aka "Smi") anywhere. Bug: v8:6896 Change-Id: I140ce9a7c15ff77d05afeda6cda58f0560d922c8 Reviewed-on: https://chromium-review.googlesource.com/707139 Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> Commit-Queue: Michael Stanton <mvstanton@chromium.org> Cr-Commit-Position: refs/heads/master@{#48387}
This commit is contained in:
parent
3baf964aeb
commit
b4f249e48c
@ -891,6 +891,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
|
||||
case IrOpcode::kStoreTypedElement:
|
||||
LowerStoreTypedElement(node);
|
||||
break;
|
||||
case IrOpcode::kStoreSignedSmallElement:
|
||||
LowerStoreSignedSmallElement(node);
|
||||
break;
|
||||
case IrOpcode::kLookupHashStorageIndex:
|
||||
result = LowerLookupHashStorageIndex(node);
|
||||
break;
|
||||
@ -3300,6 +3303,63 @@ void EffectControlLinearizer::LowerTransitionAndStoreElement(Node* node) {
|
||||
__ Bind(&done);
|
||||
}
|
||||
|
||||
void EffectControlLinearizer::LowerStoreSignedSmallElement(Node* node) {
|
||||
Node* array = node->InputAt(0);
|
||||
Node* index = node->InputAt(1);
|
||||
Node* value = node->InputAt(2);
|
||||
|
||||
// Store a signed small in an output array.
|
||||
//
|
||||
// kind = ElementsKind(array)
|
||||
//
|
||||
// -- STORE PHASE ----------------------
|
||||
// if kind == HOLEY_DOUBLE_ELEMENTS {
|
||||
// float_value = convert smi to float
|
||||
// Store array[index] = float_value
|
||||
// } else {
|
||||
// // kind is HOLEY_SMI_ELEMENTS or HOLEY_ELEMENTS
|
||||
// Store array[index] = value
|
||||
// }
|
||||
//
|
||||
Node* map = __ LoadField(AccessBuilder::ForMap(), array);
|
||||
Node* kind;
|
||||
{
|
||||
Node* bit_field2 = __ LoadField(AccessBuilder::ForMapBitField2(), map);
|
||||
Node* mask = __ Int32Constant(Map::ElementsKindBits::kMask);
|
||||
Node* andit = __ Word32And(bit_field2, mask);
|
||||
Node* shift = __ Int32Constant(Map::ElementsKindBits::kShift);
|
||||
kind = __ Word32Shr(andit, shift);
|
||||
}
|
||||
|
||||
Node* elements = __ LoadField(AccessBuilder::ForJSObjectElements(), array);
|
||||
auto if_kind_is_double = __ MakeLabel();
|
||||
auto done = __ MakeLabel();
|
||||
__ GotoIf(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS),
|
||||
&if_kind_is_double);
|
||||
{
|
||||
// Our ElementsKind is HOLEY_SMI_ELEMENTS or HOLEY_ELEMENTS.
|
||||
// In this case, we know our value is a signed small, and we can optimize
|
||||
// the ElementAccess information.
|
||||
ElementAccess access = AccessBuilder::ForFixedArrayElement();
|
||||
access.type = Type::SignedSmall();
|
||||
access.machine_type = MachineType::TaggedSigned();
|
||||
access.write_barrier_kind = kNoWriteBarrier;
|
||||
__ StoreElement(access, elements, index, value);
|
||||
__ Goto(&done);
|
||||
}
|
||||
__ Bind(&if_kind_is_double);
|
||||
{
|
||||
// Our ElementsKind is HOLEY_DOUBLE_ELEMENTS.
|
||||
Node* int_value = ChangeSmiToInt32(value);
|
||||
Node* float_value = __ ChangeInt32ToFloat64(int_value);
|
||||
__ StoreElement(AccessBuilder::ForFixedDoubleArrayElement(), elements,
|
||||
index, float_value);
|
||||
__ Goto(&done);
|
||||
}
|
||||
|
||||
__ Bind(&done);
|
||||
}
|
||||
|
||||
void EffectControlLinearizer::LowerRuntimeAbort(Node* node) {
|
||||
BailoutReason reason = BailoutReasonOf(node->op());
|
||||
Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
|
||||
|
@ -125,6 +125,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
|
||||
Node* LowerLoadFieldByIndex(Node* node);
|
||||
Node* LowerLoadTypedElement(Node* node);
|
||||
void LowerStoreTypedElement(Node* node);
|
||||
void LowerStoreSignedSmallElement(Node* node);
|
||||
Node* LowerLookupHashStorageIndex(Node* node);
|
||||
Node* LowerLookupSigned32HashStorageIndex(Node* node);
|
||||
void LowerTransitionAndStoreElement(Node* node);
|
||||
|
@ -353,6 +353,7 @@
|
||||
V(StoreField) \
|
||||
V(StoreElement) \
|
||||
V(StoreTypedElement) \
|
||||
V(StoreSignedSmallElement) \
|
||||
V(TransitionAndStoreElement) \
|
||||
V(ObjectIsArrayBufferView) \
|
||||
V(ObjectIsCallable) \
|
||||
|
@ -2577,9 +2577,19 @@ class RepresentationSelector {
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kTransitionAndStoreElement: {
|
||||
Type* value_type = TypeOf(node->InputAt(2));
|
||||
|
||||
ProcessInput(node, 0, UseInfo::AnyTagged()); // array
|
||||
ProcessInput(node, 1, UseInfo::TruncatingWord32()); // index
|
||||
ProcessInput(node, 2, UseInfo::AnyTagged()); // value
|
||||
|
||||
if (value_type->Is(Type::SignedSmall())) {
|
||||
if (lower()) {
|
||||
NodeProperties::ChangeOp(node,
|
||||
simplified()->StoreSignedSmallElement());
|
||||
}
|
||||
}
|
||||
|
||||
ProcessRemainingInputs(node, 3);
|
||||
SetOutput(node, MachineRepresentation::kNone);
|
||||
return;
|
||||
|
@ -1076,6 +1076,12 @@ const Operator* SimplifiedOperatorBuilder::TransitionAndStoreElement(
|
||||
1, 1, 0, 1, 0, parameters);
|
||||
}
|
||||
|
||||
const Operator* SimplifiedOperatorBuilder::StoreSignedSmallElement() {
|
||||
return new (zone()) Operator(IrOpcode::kStoreSignedSmallElement,
|
||||
Operator::kNoDeopt | Operator::kNoThrow,
|
||||
"StoreSignedSmallElement", 3, 1, 1, 0, 1, 0);
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -485,6 +485,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
|
||||
// store-element [base + index], value, only with fast arrays.
|
||||
const Operator* TransitionAndStoreElement(Handle<Map> double_map,
|
||||
Handle<Map> fast_map);
|
||||
// store-element [base + index], smi value, only with fast arrays.
|
||||
const Operator* StoreSignedSmallElement();
|
||||
|
||||
// load-typed-element buffer, [base + external + index]
|
||||
const Operator* LoadTypedElement(ExternalArrayType const&);
|
||||
|
@ -1976,6 +1976,8 @@ Type* Typer::Visitor::TypeTransitionAndStoreElement(Node* node) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::TypeStoreSignedSmallElement(Node* node) { UNREACHABLE(); }
|
||||
|
||||
Type* Typer::Visitor::TypeStoreTypedElement(Node* node) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -1306,6 +1306,10 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
case IrOpcode::kTransitionAndStoreElement:
|
||||
CheckNotTyped(node);
|
||||
break;
|
||||
case IrOpcode::kStoreSignedSmallElement:
|
||||
CheckValueInputIs(node, 1, Type::SignedSmall());
|
||||
CheckNotTyped(node);
|
||||
break;
|
||||
case IrOpcode::kStoreTypedElement:
|
||||
CheckNotTyped(node);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user