[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:
|
case IrOpcode::kStoreTypedElement:
|
||||||
LowerStoreTypedElement(node);
|
LowerStoreTypedElement(node);
|
||||||
break;
|
break;
|
||||||
|
case IrOpcode::kStoreSignedSmallElement:
|
||||||
|
LowerStoreSignedSmallElement(node);
|
||||||
|
break;
|
||||||
case IrOpcode::kLookupHashStorageIndex:
|
case IrOpcode::kLookupHashStorageIndex:
|
||||||
result = LowerLookupHashStorageIndex(node);
|
result = LowerLookupHashStorageIndex(node);
|
||||||
break;
|
break;
|
||||||
@ -3300,6 +3303,63 @@ void EffectControlLinearizer::LowerTransitionAndStoreElement(Node* node) {
|
|||||||
__ Bind(&done);
|
__ 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) {
|
void EffectControlLinearizer::LowerRuntimeAbort(Node* node) {
|
||||||
BailoutReason reason = BailoutReasonOf(node->op());
|
BailoutReason reason = BailoutReasonOf(node->op());
|
||||||
Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
|
Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
|
||||||
|
@ -125,6 +125,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
|
|||||||
Node* LowerLoadFieldByIndex(Node* node);
|
Node* LowerLoadFieldByIndex(Node* node);
|
||||||
Node* LowerLoadTypedElement(Node* node);
|
Node* LowerLoadTypedElement(Node* node);
|
||||||
void LowerStoreTypedElement(Node* node);
|
void LowerStoreTypedElement(Node* node);
|
||||||
|
void LowerStoreSignedSmallElement(Node* node);
|
||||||
Node* LowerLookupHashStorageIndex(Node* node);
|
Node* LowerLookupHashStorageIndex(Node* node);
|
||||||
Node* LowerLookupSigned32HashStorageIndex(Node* node);
|
Node* LowerLookupSigned32HashStorageIndex(Node* node);
|
||||||
void LowerTransitionAndStoreElement(Node* node);
|
void LowerTransitionAndStoreElement(Node* node);
|
||||||
|
@ -353,6 +353,7 @@
|
|||||||
V(StoreField) \
|
V(StoreField) \
|
||||||
V(StoreElement) \
|
V(StoreElement) \
|
||||||
V(StoreTypedElement) \
|
V(StoreTypedElement) \
|
||||||
|
V(StoreSignedSmallElement) \
|
||||||
V(TransitionAndStoreElement) \
|
V(TransitionAndStoreElement) \
|
||||||
V(ObjectIsArrayBufferView) \
|
V(ObjectIsArrayBufferView) \
|
||||||
V(ObjectIsCallable) \
|
V(ObjectIsCallable) \
|
||||||
|
@ -2577,9 +2577,19 @@ class RepresentationSelector {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case IrOpcode::kTransitionAndStoreElement: {
|
case IrOpcode::kTransitionAndStoreElement: {
|
||||||
|
Type* value_type = TypeOf(node->InputAt(2));
|
||||||
|
|
||||||
ProcessInput(node, 0, UseInfo::AnyTagged()); // array
|
ProcessInput(node, 0, UseInfo::AnyTagged()); // array
|
||||||
ProcessInput(node, 1, UseInfo::TruncatingWord32()); // index
|
ProcessInput(node, 1, UseInfo::TruncatingWord32()); // index
|
||||||
ProcessInput(node, 2, UseInfo::AnyTagged()); // value
|
ProcessInput(node, 2, UseInfo::AnyTagged()); // value
|
||||||
|
|
||||||
|
if (value_type->Is(Type::SignedSmall())) {
|
||||||
|
if (lower()) {
|
||||||
|
NodeProperties::ChangeOp(node,
|
||||||
|
simplified()->StoreSignedSmallElement());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ProcessRemainingInputs(node, 3);
|
ProcessRemainingInputs(node, 3);
|
||||||
SetOutput(node, MachineRepresentation::kNone);
|
SetOutput(node, MachineRepresentation::kNone);
|
||||||
return;
|
return;
|
||||||
|
@ -1076,6 +1076,12 @@ const Operator* SimplifiedOperatorBuilder::TransitionAndStoreElement(
|
|||||||
1, 1, 0, 1, 0, parameters);
|
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 compiler
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -485,6 +485,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
|
|||||||
// store-element [base + index], value, only with fast arrays.
|
// store-element [base + index], value, only with fast arrays.
|
||||||
const Operator* TransitionAndStoreElement(Handle<Map> double_map,
|
const Operator* TransitionAndStoreElement(Handle<Map> double_map,
|
||||||
Handle<Map> fast_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]
|
// load-typed-element buffer, [base + external + index]
|
||||||
const Operator* LoadTypedElement(ExternalArrayType const&);
|
const Operator* LoadTypedElement(ExternalArrayType const&);
|
||||||
|
@ -1976,6 +1976,8 @@ Type* Typer::Visitor::TypeTransitionAndStoreElement(Node* node) {
|
|||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type* Typer::Visitor::TypeStoreSignedSmallElement(Node* node) { UNREACHABLE(); }
|
||||||
|
|
||||||
Type* Typer::Visitor::TypeStoreTypedElement(Node* node) {
|
Type* Typer::Visitor::TypeStoreTypedElement(Node* node) {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -1306,6 +1306,10 @@ void Verifier::Visitor::Check(Node* node) {
|
|||||||
case IrOpcode::kTransitionAndStoreElement:
|
case IrOpcode::kTransitionAndStoreElement:
|
||||||
CheckNotTyped(node);
|
CheckNotTyped(node);
|
||||||
break;
|
break;
|
||||||
|
case IrOpcode::kStoreSignedSmallElement:
|
||||||
|
CheckValueInputIs(node, 1, Type::SignedSmall());
|
||||||
|
CheckNotTyped(node);
|
||||||
|
break;
|
||||||
case IrOpcode::kStoreTypedElement:
|
case IrOpcode::kStoreTypedElement:
|
||||||
CheckNotTyped(node);
|
CheckNotTyped(node);
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user