Commit 1aa09302 authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[turbofan] Introduce LookupSigned32HashStorageIndex specialization of Map#get.

This adds a new operator LookupSigned32HashStorageIndex, which is a
specialization of the general LookupHashStorageIndex for Map#get that
is used when TurboFan knows that the key is in Signed32 range.

This improves the execution time of the ARES6 Basic test locally by
around 5% and seems to make sense in general.

Bug: v8:6410, v8:6354, v8:6278, v8:6344
Change-Id: I78dcbc9cc855a4109e1690d8cd14fbc88fd89861
Reviewed-on: https://chromium-review.googlesource.com/706787Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48361}
parent 0e3b6bea
......@@ -838,6 +838,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kLookupHashStorageIndex:
result = LowerLookupHashStorageIndex(node);
break;
case IrOpcode::kLookupSigned32HashStorageIndex:
result = LowerLookupSigned32HashStorageIndex(node);
break;
case IrOpcode::kLoadHashMapValue:
result = LowerLoadHashMapValue(node);
case IrOpcode::kTransitionAndStoreElement:
......@@ -2701,15 +2704,31 @@ Node* EffectControlLinearizer::ChangeInt32ToSmi(Node* value) {
return __ WordShl(value, SmiShiftBitsConstant());
}
Node* EffectControlLinearizer::ChangeUint32ToSmi(Node* value) {
Node* EffectControlLinearizer::ChangeIntPtrToInt32(Node* value) {
if (machine()->Is64()) {
value = __ TruncateInt64ToInt32(value);
}
return value;
}
Node* EffectControlLinearizer::ChangeUint32ToUintPtr(Node* value) {
if (machine()->Is64()) {
value = __ ChangeUint32ToUint64(value);
}
return value;
}
Node* EffectControlLinearizer::ChangeUint32ToSmi(Node* value) {
value = ChangeUint32ToUintPtr(value);
return __ WordShl(value, SmiShiftBitsConstant());
}
Node* EffectControlLinearizer::ChangeSmiToIntPtr(Node* value) {
return __ WordSar(value, SmiShiftBitsConstant());
}
Node* EffectControlLinearizer::ChangeSmiToInt32(Node* value) {
value = __ WordSar(value, SmiShiftBitsConstant());
value = ChangeSmiToIntPtr(value);
if (machine()->Is64()) {
value = __ TruncateInt64ToInt32(value);
}
......@@ -3570,6 +3589,97 @@ Node* EffectControlLinearizer::LowerLookupHashStorageIndex(Node* node) {
}
}
Node* EffectControlLinearizer::ComputeIntegerHash(Node* value) {
// See v8::internal::ComputeIntegerHash()
value = __ Int32Add(__ Word32Xor(value, __ Int32Constant(0xffffffff)),
__ Word32Shl(value, __ Int32Constant(15)));
value = __ Word32Xor(value, __ Word32Shr(value, __ Int32Constant(12)));
value = __ Int32Add(value, __ Word32Shl(value, __ Int32Constant(2)));
value = __ Word32Xor(value, __ Word32Shr(value, __ Int32Constant(4)));
value = __ Int32Mul(value, __ Int32Constant(2057));
value = __ Word32Xor(value, __ Word32Shr(value, __ Int32Constant(16)));
value = __ Word32And(value, __ Int32Constant(0x3fffffff));
return value;
}
Node* EffectControlLinearizer::LowerLookupSigned32HashStorageIndex(Node* node) {
Node* table = NodeProperties::GetValueInput(node, 0);
Node* key = NodeProperties::GetValueInput(node, 1);
// Compute the integer hash code.
Node* hash = ChangeUint32ToUintPtr(ComputeIntegerHash(key));
Node* number_of_buckets = ChangeSmiToIntPtr(__ LoadField(
AccessBuilder::ForOrderedHashTableBaseNumberOfBuckets(), table));
hash = __ WordAnd(hash, __ IntSub(number_of_buckets, __ IntPtrConstant(1)));
Node* first_entry = ChangeSmiToIntPtr(__ Load(
MachineType::TaggedSigned(), table,
__ IntAdd(__ WordShl(hash, __ IntPtrConstant(kPointerSizeLog2)),
__ IntPtrConstant(OrderedHashMap::kHashTableStartOffset -
kHeapObjectTag))));
auto loop = __ MakeLoopLabel(MachineType::PointerRepresentation());
auto done = __ MakeLabel(MachineRepresentation::kWord32);
__ Goto(&loop, first_entry);
__ Bind(&loop);
{
Node* entry = loop.PhiAt(0);
Node* check =
__ WordEqual(entry, __ IntPtrConstant(OrderedHashTableBase::kNotFound));
__ GotoIf(check, &done, __ Int32Constant(-1));
Node* entry_start = __ IntAdd(
__ IntMul(entry, __ IntPtrConstant(OrderedHashMap::kEntrySize)),
number_of_buckets);
Node* candidate_key = __ Load(
MachineType::AnyTagged(), table,
__ IntAdd(__ WordShl(entry_start, __ IntPtrConstant(kPointerSizeLog2)),
__ IntPtrConstant(OrderedHashMap::kHashTableStartOffset -
kHeapObjectTag)));
auto if_match = __ MakeLabel();
auto if_notmatch = __ MakeLabel();
auto if_notsmi = __ MakeDeferredLabel();
__ GotoIfNot(ObjectIsSmi(candidate_key), &if_notsmi);
__ Branch(__ Word32Equal(ChangeSmiToInt32(candidate_key), key), &if_match,
&if_notmatch);
__ Bind(&if_notsmi);
__ GotoIfNot(
__ WordEqual(__ LoadField(AccessBuilder::ForMap(), candidate_key),
__ HeapNumberMapConstant()),
&if_notmatch);
__ Branch(__ Float64Equal(__ LoadField(AccessBuilder::ForHeapNumberValue(),
candidate_key),
__ ChangeInt32ToFloat64(key)),
&if_match, &if_notmatch);
__ Bind(&if_match);
{
Node* index = ChangeIntPtrToInt32(__ IntAdd(
entry_start, __ IntPtrConstant(OrderedHashMap::kHashTableStartIndex +
OrderedHashMap::kValueOffset)));
__ Goto(&done, index);
}
__ Bind(&if_notmatch);
{
Node* next_entry = ChangeSmiToIntPtr(__ Load(
MachineType::TaggedSigned(), table,
__ IntAdd(
__ WordShl(entry_start, __ IntPtrConstant(kPointerSizeLog2)),
__ IntPtrConstant(OrderedHashMap::kHashTableStartOffset +
OrderedHashMap::kChainOffset * kPointerSize -
kHeapObjectTag))));
__ Goto(&loop, next_entry);
}
}
__ Bind(&done);
return done.PhiAt(0);
}
Node* EffectControlLinearizer::LowerLoadHashMapValue(Node* node) {
Node* table = NodeProperties::GetValueInput(node, 0);
Node* index = NodeProperties::GetValueInput(node, 1);
......
......@@ -126,6 +126,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerLoadTypedElement(Node* node);
void LowerStoreTypedElement(Node* node);
Node* LowerLookupHashStorageIndex(Node* node);
Node* LowerLookupSigned32HashStorageIndex(Node* node);
Node* LowerLoadHashMapValue(Node* node);
void LowerTransitionAndStoreElement(Node* node);
void LowerRuntimeAbort(Node* node);
......@@ -143,11 +144,15 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* value,
Node* frame_state);
Node* BuildFloat64RoundDown(Node* value);
Node* ComputeIntegerHash(Node* value);
Node* LowerStringComparison(Callable const& callable, Node* node);
Node* IsElementsKindGreaterThan(Node* kind, ElementsKind reference_kind);
Node* ChangeInt32ToSmi(Node* value);
Node* ChangeIntPtrToInt32(Node* value);
Node* ChangeUint32ToUintPtr(Node* value);
Node* ChangeUint32ToSmi(Node* value);
Node* ChangeSmiToIntPtr(Node* value);
Node* ChangeSmiToInt32(Node* value);
Node* ObjectIsSmi(Node* value);
......
......@@ -37,10 +37,12 @@ namespace compiler {
V(WordAnd) \
V(Word32Or) \
V(Word32And) \
V(Word32Xor) \
V(Word32Shr) \
V(Word32Shl) \
V(IntAdd) \
V(IntSub) \
V(IntMul) \
V(IntLessThan) \
V(UintLessThan) \
V(Int32Add) \
......
......@@ -374,6 +374,7 @@
V(MaybeGrowFastElements) \
V(TransitionElementsKind) \
V(LookupHashStorageIndex) \
V(LookupSigned32HashStorageIndex) \
V(LoadHashMapValue) \
V(RuntimeAbort)
......
......@@ -2917,9 +2917,21 @@ class RepresentationSelector {
// Assume the output is tagged.
return SetOutput(node, MachineRepresentation::kTagged);
case IrOpcode::kLookupHashStorageIndex:
VisitInputs(node);
return SetOutput(node, MachineRepresentation::kTaggedSigned);
case IrOpcode::kLookupHashStorageIndex: {
Type* const key_type = TypeOf(node->InputAt(1));
if (key_type->Is(Type::Signed32())) {
VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32);
if (lower()) {
NodeProperties::ChangeOp(
node, lowering->simplified()->LookupSigned32HashStorageIndex());
}
} else {
VisitBinop(node, UseInfo::AnyTagged(),
MachineRepresentation::kTaggedSigned);
}
return;
}
case IrOpcode::kLoadHashMapValue:
ProcessInput(node, 0, UseInfo::AnyTagged()); // table
......
......@@ -596,6 +596,14 @@ struct SimplifiedOperatorGlobalCache final {
};
LookupHashStorageIndexOperator kLookupHashStorageIndex;
struct LookupSigned32HashStorageIndexOperator final : public Operator {
LookupSigned32HashStorageIndexOperator()
: Operator(IrOpcode::kLookupSigned32HashStorageIndex,
Operator::kEliminatable, "LookupSigned32HashStorageIndex", 2,
1, 1, 1, 1, 0) {}
};
LookupSigned32HashStorageIndexOperator kLookupSigned32HashStorageIndex;
struct LoadHashMapValueOperator final : public Operator {
LoadHashMapValueOperator()
: Operator(IrOpcode::kLoadHashMapValue, Operator::kEliminatable,
......@@ -780,6 +788,7 @@ CHECKED_OP_LIST(GET_FROM_CACHE)
GET_FROM_CACHE(ArrayBufferWasNeutered)
GET_FROM_CACHE(ArgumentsFrame)
GET_FROM_CACHE(LookupHashStorageIndex)
GET_FROM_CACHE(LookupSigned32HashStorageIndex)
GET_FROM_CACHE(LoadHashMapValue)
GET_FROM_CACHE(LoadFieldByIndex)
#undef GET_FROM_CACHE
......
......@@ -374,6 +374,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* StringToUpperCaseIntl();
const Operator* LookupHashStorageIndex();
const Operator* LookupSigned32HashStorageIndex();
const Operator* LoadHashMapValue();
const Operator* SpeculativeToNumber(NumberOperationHint hint);
......
......@@ -2054,6 +2054,10 @@ Type* Typer::Visitor::TypeLookupHashStorageIndex(Node* node) {
return Type::SignedSmall();
}
Type* Typer::Visitor::TypeLookupSigned32HashStorageIndex(Node* node) {
return Type::SignedSmall();
}
Type* Typer::Visitor::TypeLoadHashMapValue(Node* node) {
return Type::NonInternal();
}
......
......@@ -1022,6 +1022,12 @@ void Verifier::Visitor::Check(Node* node) {
CheckTypeIs(node, Type::Boolean());
break;
case IrOpcode::kLookupHashStorageIndex:
CheckValueInputIs(node, 0, Type::Any());
CheckTypeIs(node, Type::SignedSmall());
break;
case IrOpcode::kLookupSigned32HashStorageIndex:
CheckValueInputIs(node, 0, Type::Any());
CheckValueInputIs(node, 1, Type::Signed32());
CheckTypeIs(node, Type::SignedSmall());
break;
case IrOpcode::kLoadHashMapValue:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment