diff --git a/src/compiler/effect-control-linearizer.cc b/src/compiler/effect-control-linearizer.cc index 192029669e..088fdb34cc 100644 --- a/src/compiler/effect-control-linearizer.cc +++ b/src/compiler/effect-control-linearizer.cc @@ -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; diff --git a/src/compiler/effect-control-linearizer.h b/src/compiler/effect-control-linearizer.h index bae85e8e6f..19439c61d4 100644 --- a/src/compiler/effect-control-linearizer.h +++ b/src/compiler/effect-control-linearizer.h @@ -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); diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index 69fc01808d..efc5fffd57 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -353,6 +353,7 @@ V(StoreField) \ V(StoreElement) \ V(StoreTypedElement) \ + V(StoreSignedSmallElement) \ V(TransitionAndStoreElement) \ V(ObjectIsArrayBufferView) \ V(ObjectIsCallable) \ diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc index 20f9e0677f..98f69d5027 100644 --- a/src/compiler/simplified-lowering.cc +++ b/src/compiler/simplified-lowering.cc @@ -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; diff --git a/src/compiler/simplified-operator.cc b/src/compiler/simplified-operator.cc index 02357a02e6..8aff74c564 100644 --- a/src/compiler/simplified-operator.cc +++ b/src/compiler/simplified-operator.cc @@ -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 diff --git a/src/compiler/simplified-operator.h b/src/compiler/simplified-operator.h index 3d46bb52c6..d527739b39 100644 --- a/src/compiler/simplified-operator.h +++ b/src/compiler/simplified-operator.h @@ -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&); diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 2b401f7993..81eadd80dd 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -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(); } diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index 05c803fd42..9dd2a2facb 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -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;