Commit 66f2d3bd authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Introduce initial support for TypedArrays.

This adds support for lowering keyed access to JSTypedArray objects to
element loads and stores instead of IC calls. There's still a lot of
room for improvement, but the improvements can be done incrementally
later.

We add a dedicated UnsafePointerAdd operator, which sits in the effect
chain, and does the (GC invisible) computation of addresses that are
potentially inside HeapObjects. Also there's now a dedicated Retain
operator, which ensures that we retain a certain tagged value, which is
necessary to ensure that we keep a JSArrayBuffer alive as long as we
might still potentially access elements in its backing store.

R=epertoso@chromium.org

Review-Url: https://codereview.chromium.org/2203693002
Cr-Commit-Position: refs/heads/master@{#38235}
parent 8135caef
...@@ -327,6 +327,27 @@ FieldAccess AccessBuilder::ForFixedArrayLength() { ...@@ -327,6 +327,27 @@ FieldAccess AccessBuilder::ForFixedArrayLength() {
return access; return access;
} }
// static
FieldAccess AccessBuilder::ForFixedTypedArrayBaseBasePointer() {
FieldAccess access = {kTaggedBase,
FixedTypedArrayBase::kBasePointerOffset,
MaybeHandle<Name>(),
Type::Tagged(),
MachineType::AnyTagged(),
kPointerWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForFixedTypedArrayBaseExternalPointer() {
FieldAccess access = {kTaggedBase,
FixedTypedArrayBase::kExternalPointerOffset,
MaybeHandle<Name>(),
Type::UntaggedPointer(),
MachineType::Pointer(),
kNoWriteBarrier};
return access;
}
// static // static
FieldAccess AccessBuilder::ForDescriptorArrayEnumCache() { FieldAccess AccessBuilder::ForDescriptorArrayEnumCache() {
......
...@@ -106,6 +106,12 @@ class AccessBuilder final : public AllStatic { ...@@ -106,6 +106,12 @@ class AccessBuilder final : public AllStatic {
// Provides access to FixedArray::length() field. // Provides access to FixedArray::length() field.
static FieldAccess ForFixedArrayLength(); static FieldAccess ForFixedArrayLength();
// Provides access to FixedTypedArrayBase::base_pointer() field.
static FieldAccess ForFixedTypedArrayBaseBasePointer();
// Provides access to FixedTypedArrayBase::external_pointer() field.
static FieldAccess ForFixedTypedArrayBaseExternalPointer();
// Provides access to DescriptorArray::enum_cache() field. // Provides access to DescriptorArray::enum_cache() field.
static FieldAccess ForDescriptorArrayEnumCache(); static FieldAccess ForDescriptorArrayEnumCache();
......
...@@ -25,6 +25,8 @@ bool CanInlineElementAccess(Handle<Map> map) { ...@@ -25,6 +25,8 @@ bool CanInlineElementAccess(Handle<Map> map) {
ElementsKind const elements_kind = map->elements_kind(); ElementsKind const elements_kind = map->elements_kind();
if (IsFastElementsKind(elements_kind)) return true; if (IsFastElementsKind(elements_kind)) return true;
// TODO(bmeurer): Add support for other elements kind. // TODO(bmeurer): Add support for other elements kind.
if (elements_kind == UINT8_CLAMPED_ELEMENTS) return false;
if (IsFixedTypedArrayElementsKind(elements_kind)) return true;
return false; return false;
} }
......
...@@ -235,21 +235,22 @@ std::ostream& operator<<(std::ostream& os, ...@@ -235,21 +235,22 @@ std::ostream& operator<<(std::ostream& os,
return os; return os;
} }
#define CACHED_OP_LIST(V) \ #define CACHED_OP_LIST(V) \
V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \ V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \
V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(IfDefault, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfDefault, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(Throw, Operator::kKontrol, 1, 1, 1, 0, 0, 1) \ V(Throw, Operator::kKontrol, 1, 1, 1, 0, 0, 1) \
V(Terminate, Operator::kKontrol, 0, 1, 1, 0, 0, 1) \ V(Terminate, Operator::kKontrol, 0, 1, 1, 0, 0, 1) \
V(OsrNormalEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \ V(OsrNormalEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \
V(OsrLoopEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \ V(OsrLoopEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \
V(LoopExit, Operator::kKontrol, 0, 0, 2, 0, 0, 1) \ V(LoopExit, Operator::kKontrol, 0, 0, 2, 0, 0, 1) \
V(LoopExitValue, Operator::kPure, 1, 0, 1, 1, 0, 0) \ V(LoopExitValue, Operator::kPure, 1, 0, 1, 1, 0, 0) \
V(LoopExitEffect, Operator::kNoThrow, 0, 1, 1, 0, 1, 0) \ V(LoopExitEffect, Operator::kNoThrow, 0, 1, 1, 0, 1, 0) \
V(Checkpoint, Operator::kKontrol, 0, 1, 1, 0, 1, 0) \ V(Checkpoint, Operator::kKontrol, 0, 1, 1, 0, 1, 0) \
V(FinishRegion, Operator::kKontrol, 1, 1, 0, 1, 1, 0) V(FinishRegion, Operator::kKontrol, 1, 1, 0, 1, 1, 0) \
V(Retain, Operator::kKontrol, 1, 1, 0, 0, 1, 0)
#define CACHED_RETURN_LIST(V) \ #define CACHED_RETURN_LIST(V) \
V(1) \ V(1) \
......
...@@ -248,6 +248,7 @@ class CommonOperatorBuilder final : public ZoneObject { ...@@ -248,6 +248,7 @@ class CommonOperatorBuilder final : public ZoneObject {
const Operator* Call(const CallDescriptor* descriptor); const Operator* Call(const CallDescriptor* descriptor);
const Operator* TailCall(const CallDescriptor* descriptor); const Operator* TailCall(const CallDescriptor* descriptor);
const Operator* Projection(size_t index); const Operator* Projection(size_t index);
const Operator* Retain();
// Constructs a new merge or phi operator with the same opcode as {op}, but // Constructs a new merge or phi operator with the same opcode as {op}, but
// with {size} inputs. // with {size} inputs.
......
...@@ -722,6 +722,12 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, ...@@ -722,6 +722,12 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kTransitionElementsKind: case IrOpcode::kTransitionElementsKind:
state = LowerTransitionElementsKind(node, *effect, *control); state = LowerTransitionElementsKind(node, *effect, *control);
break; break;
case IrOpcode::kLoadTypedElement:
state = LowerLoadTypedElement(node, *effect, *control);
break;
case IrOpcode::kStoreTypedElement:
state = LowerStoreTypedElement(node, *effect, *control);
break;
default: default:
return false; return false;
} }
...@@ -2619,6 +2625,59 @@ EffectControlLinearizer::LowerTransitionElementsKind(Node* node, Node* effect, ...@@ -2619,6 +2625,59 @@ EffectControlLinearizer::LowerTransitionElementsKind(Node* node, Node* effect,
return ValueEffectControl(nullptr, effect, control); return ValueEffectControl(nullptr, effect, control);
} }
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerLoadTypedElement(Node* node, Node* effect,
Node* control) {
ExternalArrayType array_type = ExternalArrayTypeOf(node->op());
Node* buffer = node->InputAt(0);
Node* base = node->InputAt(1);
Node* external = node->InputAt(2);
Node* index = node->InputAt(3);
// We need to keep the {buffer} alive so that the GC will not release the
// ArrayBuffer (if there's any) as long as we are still operating on it.
effect = graph()->NewNode(common()->Retain(), buffer, effect);
// Compute the effective storage pointer.
Node* storage = effect = graph()->NewNode(machine()->UnsafePointerAdd(), base,
external, effect, control);
// Perform the actual typed element access.
Node* value = effect = graph()->NewNode(
simplified()->LoadElement(
AccessBuilder::ForTypedArrayElement(array_type, true)),
storage, index, effect, control);
return ValueEffectControl(value, effect, control);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerStoreTypedElement(Node* node, Node* effect,
Node* control) {
ExternalArrayType array_type = ExternalArrayTypeOf(node->op());
Node* buffer = node->InputAt(0);
Node* base = node->InputAt(1);
Node* external = node->InputAt(2);
Node* index = node->InputAt(3);
Node* value = node->InputAt(4);
// We need to keep the {buffer} alive so that the GC will not release the
// ArrayBuffer (if there's any) as long as we are still operating on it.
effect = graph()->NewNode(common()->Retain(), buffer, effect);
// Compute the effective storage pointer.
Node* storage = effect = graph()->NewNode(machine()->UnsafePointerAdd(), base,
external, effect, control);
// Perform the actual typed element access.
effect = graph()->NewNode(
simplified()->StoreElement(
AccessBuilder::ForTypedArrayElement(array_type, true)),
storage, index, value, effect, control);
return ValueEffectControl(nullptr, effect, control);
}
Factory* EffectControlLinearizer::factory() const { Factory* EffectControlLinearizer::factory() const {
return isolate()->factory(); return isolate()->factory();
} }
......
...@@ -134,6 +134,10 @@ class EffectControlLinearizer { ...@@ -134,6 +134,10 @@ class EffectControlLinearizer {
Node* control); Node* control);
ValueEffectControl LowerTransitionElementsKind(Node* node, Node* effect, ValueEffectControl LowerTransitionElementsKind(Node* node, Node* effect,
Node* control); Node* control);
ValueEffectControl LowerLoadTypedElement(Node* node, Node* effect,
Node* control);
ValueEffectControl LowerStoreTypedElement(Node* node, Node* effect,
Node* control);
ValueEffectControl AllocateHeapNumberWithValue(Node* node, Node* effect, ValueEffectControl AllocateHeapNumberWithValue(Node* node, Node* effect,
Node* control); Node* control);
......
...@@ -299,6 +299,9 @@ void InstructionSelector::MarkAsDefined(Node* node) { ...@@ -299,6 +299,9 @@ void InstructionSelector::MarkAsDefined(Node* node) {
bool InstructionSelector::IsUsed(Node* node) const { bool InstructionSelector::IsUsed(Node* node) const {
DCHECK_NOT_NULL(node); DCHECK_NOT_NULL(node);
// TODO(bmeurer): This is a terrible monster hack, but we have to make sure
// that the Retain is actually emitted, otherwise the GC will mess up.
if (node->opcode() == IrOpcode::kRetain) return true;
if (!node->op()->HasProperty(Operator::kEliminatable)) return true; if (!node->op()->HasProperty(Operator::kEliminatable)) return true;
size_t const id = node->id(); size_t const id = node->id();
DCHECK_LT(id, used_.size()); DCHECK_LT(id, used_.size());
...@@ -929,6 +932,9 @@ void InstructionSelector::VisitNode(Node* node) { ...@@ -929,6 +932,9 @@ void InstructionSelector::VisitNode(Node* node) {
case IrOpcode::kComment: case IrOpcode::kComment:
VisitComment(node); VisitComment(node);
return; return;
case IrOpcode::kRetain:
VisitRetain(node);
return;
case IrOpcode::kLoad: { case IrOpcode::kLoad: {
LoadRepresentation type = LoadRepresentationOf(node->op()); LoadRepresentation type = LoadRepresentationOf(node->op());
MarkAsRepresentation(type.representation(), node); MarkAsRepresentation(type.representation(), node);
...@@ -1297,6 +1303,9 @@ void InstructionSelector::VisitNode(Node* node) { ...@@ -1297,6 +1303,9 @@ void InstructionSelector::VisitNode(Node* node) {
} }
case IrOpcode::kAtomicStore: case IrOpcode::kAtomicStore:
return VisitAtomicStore(node); return VisitAtomicStore(node);
case IrOpcode::kUnsafePointerAdd:
MarkAsRepresentation(MachineType::PointerRepresentation(), node);
return VisitUnsafePointerAdd(node);
default: default:
V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d", V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d",
node->opcode(), node->op()->mnemonic(), node->id()); node->opcode(), node->op()->mnemonic(), node->id());
...@@ -2016,6 +2025,19 @@ void InstructionSelector::VisitComment(Node* node) { ...@@ -2016,6 +2025,19 @@ void InstructionSelector::VisitComment(Node* node) {
Emit(kArchComment, 0, nullptr, 1, &operand); Emit(kArchComment, 0, nullptr, 1, &operand);
} }
void InstructionSelector::VisitUnsafePointerAdd(Node* node) {
#if V8_TARGET_ARCH_64_BIT
VisitInt64Add(node);
#else // V8_TARGET_ARCH_64_BIT
VisitInt32Add(node);
#endif // V8_TARGET_ARCH_64_BIT
}
void InstructionSelector::VisitRetain(Node* node) {
OperandGenerator g(this);
Emit(kArchNop, g.NoOutput(), g.UseAny(node->InputAt(0)));
}
bool InstructionSelector::CanProduceSignalingNaN(Node* node) { bool InstructionSelector::CanProduceSignalingNaN(Node* node) {
// TODO(jarin) Improve the heuristic here. // TODO(jarin) Improve the heuristic here.
if (node->opcode() == IrOpcode::kFloat64Add || if (node->opcode() == IrOpcode::kFloat64Add ||
......
...@@ -296,6 +296,7 @@ class InstructionSelector final { ...@@ -296,6 +296,7 @@ class InstructionSelector final {
Node* value); Node* value);
void VisitReturn(Node* ret); void VisitReturn(Node* ret);
void VisitThrow(Node* value); void VisitThrow(Node* value);
void VisitRetain(Node* node);
void EmitPrepareArguments(ZoneVector<compiler::PushParameter>* arguments, void EmitPrepareArguments(ZoneVector<compiler::PushParameter>* arguments,
const CallDescriptor* descriptor, Node* node); const CallDescriptor* descriptor, Node* node);
......
...@@ -732,9 +732,9 @@ Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor( ...@@ -732,9 +732,9 @@ Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor(
jsgraph()->ZeroConstant()); jsgraph()->ZeroConstant());
// Default to zero if the {receiver}s buffer was neutered. // Default to zero if the {receiver}s buffer was neutered.
Node* value = Node* value = graph()->NewNode(
graph()->NewNode(common()->Select(MachineRepresentation::kTagged), common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
check, receiver_length, jsgraph()->ZeroConstant()); check, receiver_length, jsgraph()->ZeroConstant());
ReplaceWithValue(node, value, effect, control); ReplaceWithValue(node, value, effect, control);
return Replace(value); return Replace(value);
......
...@@ -63,6 +63,8 @@ Reduction LoadElimination::Reduce(Node* node) { ...@@ -63,6 +63,8 @@ Reduction LoadElimination::Reduce(Node* node) {
return ReduceLoadElement(node); return ReduceLoadElement(node);
case IrOpcode::kStoreElement: case IrOpcode::kStoreElement:
return ReduceStoreElement(node); return ReduceStoreElement(node);
case IrOpcode::kStoreTypedElement:
return ReduceStoreTypedElement(node);
case IrOpcode::kEffectPhi: case IrOpcode::kEffectPhi:
return ReduceEffectPhi(node); return ReduceEffectPhi(node);
case IrOpcode::kDead: case IrOpcode::kDead:
...@@ -455,6 +457,13 @@ Reduction LoadElimination::ReduceStoreElement(Node* node) { ...@@ -455,6 +457,13 @@ Reduction LoadElimination::ReduceStoreElement(Node* node) {
return UpdateState(node, state); return UpdateState(node, state);
} }
Reduction LoadElimination::ReduceStoreTypedElement(Node* node) {
Node* const effect = NodeProperties::GetEffectInput(node);
AbstractState const* state = node_states_.Get(effect);
if (state == nullptr) return NoChange();
return UpdateState(node, state);
}
Reduction LoadElimination::ReduceEffectPhi(Node* node) { Reduction LoadElimination::ReduceEffectPhi(Node* node) {
Node* const effect0 = NodeProperties::GetEffectInput(node, 0); Node* const effect0 = NodeProperties::GetEffectInput(node, 0);
Node* const control = NodeProperties::GetControlInput(node); Node* const control = NodeProperties::GetControlInput(node);
...@@ -571,15 +580,20 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState( ...@@ -571,15 +580,20 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
// static // static
int LoadElimination::FieldIndexOf(FieldAccess const& access) { int LoadElimination::FieldIndexOf(FieldAccess const& access) {
switch (access.machine_type.representation()) { MachineRepresentation rep = access.machine_type.representation();
switch (rep) {
case MachineRepresentation::kNone: case MachineRepresentation::kNone:
case MachineRepresentation::kBit: case MachineRepresentation::kBit:
UNREACHABLE(); UNREACHABLE();
break; break;
case MachineRepresentation::kWord8:
case MachineRepresentation::kWord16:
case MachineRepresentation::kWord32: case MachineRepresentation::kWord32:
case MachineRepresentation::kWord64: case MachineRepresentation::kWord64:
if (rep != MachineType::PointerRepresentation()) {
return -1; // We currently only track pointer size fields.
}
break;
case MachineRepresentation::kWord8:
case MachineRepresentation::kWord16:
case MachineRepresentation::kFloat32: case MachineRepresentation::kFloat32:
return -1; // Currently untracked. return -1; // Currently untracked.
case MachineRepresentation::kFloat64: case MachineRepresentation::kFloat64:
......
...@@ -155,6 +155,7 @@ class LoadElimination final : public AdvancedReducer { ...@@ -155,6 +155,7 @@ class LoadElimination final : public AdvancedReducer {
Reduction ReduceStoreField(Node* node); Reduction ReduceStoreField(Node* node);
Reduction ReduceLoadElement(Node* node); Reduction ReduceLoadElement(Node* node);
Reduction ReduceStoreElement(Node* node); Reduction ReduceStoreElement(Node* node);
Reduction ReduceStoreTypedElement(Node* node);
Reduction ReduceEffectPhi(Node* node); Reduction ReduceEffectPhi(Node* node);
Reduction ReduceStart(Node* node); Reduction ReduceStart(Node* node);
Reduction ReduceOtherNode(Node* node); Reduction ReduceOtherNode(Node* node);
......
...@@ -611,6 +611,13 @@ struct MachineOperatorGlobalCache { ...@@ -611,6 +611,13 @@ struct MachineOperatorGlobalCache {
0, 0, 0, 0, 0) {} 0, 0, 0, 0, 0) {}
}; };
DebugBreakOperator kDebugBreak; DebugBreakOperator kDebugBreak;
struct UnsafePointerAddOperator final : public Operator {
UnsafePointerAddOperator()
: Operator(IrOpcode::kUnsafePointerAdd, Operator::kKontrol,
"UnsafePointerAdd", 2, 1, 1, 1, 1, 0) {}
};
UnsafePointerAddOperator kUnsafePointerAdd;
}; };
struct CommentOperator : public Operator1<const char*> { struct CommentOperator : public Operator1<const char*> {
...@@ -728,6 +735,10 @@ const Operator* MachineOperatorBuilder::Store(StoreRepresentation store_rep) { ...@@ -728,6 +735,10 @@ const Operator* MachineOperatorBuilder::Store(StoreRepresentation store_rep) {
return nullptr; return nullptr;
} }
const Operator* MachineOperatorBuilder::UnsafePointerAdd() {
return &cache_.kUnsafePointerAdd;
}
const Operator* MachineOperatorBuilder::DebugBreak() { const Operator* MachineOperatorBuilder::DebugBreak() {
return &cache_.kDebugBreak; return &cache_.kDebugBreak;
} }
......
...@@ -214,6 +214,7 @@ class MachineOperatorBuilder final : public ZoneObject { ...@@ -214,6 +214,7 @@ class MachineOperatorBuilder final : public ZoneObject {
const Operator* Comment(const char* msg); const Operator* Comment(const char* msg);
const Operator* DebugBreak(); const Operator* DebugBreak();
const Operator* UnsafePointerAdd();
const Operator* Word32And(); const Operator* Word32And();
const Operator* Word32Or(); const Operator* Word32Or();
......
...@@ -92,6 +92,8 @@ void MemoryOptimizer::VisitNode(Node* node, AllocationState const* state) { ...@@ -92,6 +92,8 @@ void MemoryOptimizer::VisitNode(Node* node, AllocationState const* state) {
case IrOpcode::kIfException: case IrOpcode::kIfException:
case IrOpcode::kLoad: case IrOpcode::kLoad:
case IrOpcode::kStore: case IrOpcode::kStore:
case IrOpcode::kRetain:
case IrOpcode::kUnsafePointerAdd:
return VisitOtherEffect(node, state); return VisitOtherEffect(node, state);
default: default:
break; break;
......
...@@ -61,7 +61,8 @@ ...@@ -61,7 +61,8 @@
V(LoopExit) \ V(LoopExit) \
V(LoopExitValue) \ V(LoopExitValue) \
V(LoopExitEffect) \ V(LoopExitEffect) \
V(Projection) V(Projection) \
V(Retain)
#define COMMON_OP_LIST(V) \ #define COMMON_OP_LIST(V) \
CONSTANT_OP_LIST(V) \ CONSTANT_OP_LIST(V) \
...@@ -282,9 +283,11 @@ ...@@ -282,9 +283,11 @@
V(LoadField) \ V(LoadField) \
V(LoadBuffer) \ V(LoadBuffer) \
V(LoadElement) \ V(LoadElement) \
V(LoadTypedElement) \
V(StoreField) \ V(StoreField) \
V(StoreBuffer) \ V(StoreBuffer) \
V(StoreElement) \ V(StoreElement) \
V(StoreTypedElement) \
V(ObjectIsCallable) \ V(ObjectIsCallable) \
V(ObjectIsNumber) \ V(ObjectIsNumber) \
V(ObjectIsReceiver) \ V(ObjectIsReceiver) \
...@@ -473,7 +476,8 @@ ...@@ -473,7 +476,8 @@
V(Word32PairShr) \ V(Word32PairShr) \
V(Word32PairSar) \ V(Word32PairSar) \
V(AtomicLoad) \ V(AtomicLoad) \
V(AtomicStore) V(AtomicStore) \
V(UnsafePointerAdd)
#define MACHINE_SIMD_RETURN_SIMD_OP_LIST(V) \ #define MACHINE_SIMD_RETURN_SIMD_OP_LIST(V) \
V(CreateFloat32x4) \ V(CreateFloat32x4) \
......
...@@ -65,6 +65,27 @@ enum Phase { ...@@ -65,6 +65,27 @@ enum Phase {
namespace { namespace {
MachineRepresentation MachineRepresentationFromArrayType(
ExternalArrayType array_type) {
switch (array_type) {
case kExternalUint8Array:
case kExternalUint8ClampedArray:
case kExternalInt8Array:
return MachineRepresentation::kWord8;
case kExternalUint16Array:
case kExternalInt16Array:
return MachineRepresentation::kWord16;
case kExternalUint32Array:
case kExternalInt32Array:
return MachineRepresentation::kWord32;
case kExternalFloat32Array:
return MachineRepresentation::kFloat32;
case kExternalFloat64Array:
return MachineRepresentation::kFloat64;
}
UNREACHABLE();
return MachineRepresentation::kNone;
}
UseInfo TruncatingUseInfoFromRepresentation(MachineRepresentation rep) { UseInfo TruncatingUseInfoFromRepresentation(MachineRepresentation rep) {
switch (rep) { switch (rep) {
...@@ -2209,6 +2230,30 @@ class RepresentationSelector { ...@@ -2209,6 +2230,30 @@ class RepresentationSelector {
} }
return; return;
} }
case IrOpcode::kLoadTypedElement: {
MachineRepresentation const rep =
MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
ProcessInput(node, 1, UseInfo::AnyTagged()); // base pointer
ProcessInput(node, 2, UseInfo::PointerInt()); // external pointer
ProcessInput(node, 3, UseInfo::TruncatingWord32()); // index
ProcessRemainingInputs(node, 4);
SetOutput(node, rep);
return;
}
case IrOpcode::kStoreTypedElement: {
MachineRepresentation const rep =
MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
ProcessInput(node, 1, UseInfo::AnyTagged()); // base pointer
ProcessInput(node, 2, UseInfo::PointerInt()); // external pointer
ProcessInput(node, 3, UseInfo::TruncatingWord32()); // index
ProcessInput(node, 4,
TruncatingUseInfoFromRepresentation(rep)); // value
ProcessRemainingInputs(node, 5);
SetOutput(node, MachineRepresentation::kNone);
return;
}
case IrOpcode::kPlainPrimitiveToNumber: { case IrOpcode::kPlainPrimitiveToNumber: {
if (InputIs(node, Type::Boolean())) { if (InputIs(node, Type::Boolean())) {
VisitUnop(node, UseInfo::Bool(), MachineRepresentation::kWord32); VisitUnop(node, UseInfo::Bool(), MachineRepresentation::kWord32);
......
...@@ -181,6 +181,12 @@ const ElementAccess& ElementAccessOf(const Operator* op) { ...@@ -181,6 +181,12 @@ const ElementAccess& ElementAccessOf(const Operator* op) {
return OpParameter<ElementAccess>(op); return OpParameter<ElementAccess>(op);
} }
ExternalArrayType ExternalArrayTypeOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kLoadTypedElement ||
op->opcode() == IrOpcode::kStoreTypedElement);
return OpParameter<ExternalArrayType>(op);
}
size_t hash_value(CheckFloat64HoleMode mode) { size_t hash_value(CheckFloat64HoleMode mode) {
return static_cast<size_t>(mode); return static_cast<size_t>(mode);
} }
...@@ -634,11 +640,13 @@ const Operator* SimplifiedOperatorBuilder::SpeculativeNumberLessThanOrEqual( ...@@ -634,11 +640,13 @@ const Operator* SimplifiedOperatorBuilder::SpeculativeNumberLessThanOrEqual(
"SpeculativeNumberLessThanOrEqual", 2, 1, 1, 1, 1, 0, hint); "SpeculativeNumberLessThanOrEqual", 2, 1, 1, 1, 1, 0, hint);
} }
#define ACCESS_OP_LIST(V) \ #define ACCESS_OP_LIST(V) \
V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1) \ V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1) \
V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0) \ V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0) \
V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \ V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \
V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0) V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0) \
V(LoadTypedElement, ExternalArrayType, Operator::kNoWrite, 4, 1, 1) \
V(StoreTypedElement, ExternalArrayType, Operator::kNoRead, 5, 1, 0)
#define ACCESS(Name, Type, properties, value_input_count, control_input_count, \ #define ACCESS(Name, Type, properties, value_input_count, control_input_count, \
output_count) \ output_count) \
......
...@@ -107,6 +107,8 @@ std::ostream& operator<<(std::ostream&, ElementAccess const&); ...@@ -107,6 +107,8 @@ std::ostream& operator<<(std::ostream&, ElementAccess const&);
ElementAccess const& ElementAccessOf(const Operator* op) WARN_UNUSED_RESULT; ElementAccess const& ElementAccessOf(const Operator* op) WARN_UNUSED_RESULT;
ExternalArrayType ExternalArrayTypeOf(const Operator* op) WARN_UNUSED_RESULT;
enum class CheckFloat64HoleMode : uint8_t { enum class CheckFloat64HoleMode : uint8_t {
kNeverReturnHole, // Never return the hole (deoptimize instead). kNeverReturnHole, // Never return the hole (deoptimize instead).
kAllowReturnHole // Allow to return the hole (signaling NaN). kAllowReturnHole // Allow to return the hole (signaling NaN).
...@@ -319,12 +321,18 @@ class SimplifiedOperatorBuilder final : public ZoneObject { ...@@ -319,12 +321,18 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
// store-buffer buffer, offset, length, value // store-buffer buffer, offset, length, value
const Operator* StoreBuffer(BufferAccess); const Operator* StoreBuffer(BufferAccess);
// load-element [base + index], length // load-element [base + index]
const Operator* LoadElement(ElementAccess const&); const Operator* LoadElement(ElementAccess const&);
// store-element [base + index], length, value // store-element [base + index], value
const Operator* StoreElement(ElementAccess const&); const Operator* StoreElement(ElementAccess const&);
// load-typed-element buffer, [base + external + index]
const Operator* LoadTypedElement(ExternalArrayType const&);
// store-typed-element buffer, [base + external + index], value
const Operator* StoreTypedElement(ExternalArrayType const&);
private: private:
Zone* zone() const { return zone_; } Zone* zone() const { return zone_; }
......
...@@ -1975,6 +1975,17 @@ Type* Typer::Visitor::TypeLoadElement(Node* node) { ...@@ -1975,6 +1975,17 @@ Type* Typer::Visitor::TypeLoadElement(Node* node) {
return ElementAccessOf(node->op()).type; return ElementAccessOf(node->op()).type;
} }
Type* Typer::Visitor::TypeLoadTypedElement(Node* node) {
switch (ExternalArrayTypeOf(node->op())) {
#define TYPED_ARRAY_CASE(ElemType, type, TYPE, ctype, size) \
case kExternal##ElemType##Array: \
return typer_->cache_.k##ElemType;
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
}
UNREACHABLE();
return nullptr;
}
Type* Typer::Visitor::TypeStoreField(Node* node) { Type* Typer::Visitor::TypeStoreField(Node* node) {
UNREACHABLE(); UNREACHABLE();
...@@ -1993,6 +2004,11 @@ Type* Typer::Visitor::TypeStoreElement(Node* node) { ...@@ -1993,6 +2004,11 @@ Type* Typer::Visitor::TypeStoreElement(Node* node) {
return nullptr; return nullptr;
} }
Type* Typer::Visitor::TypeStoreTypedElement(Node* node) {
UNREACHABLE();
return nullptr;
}
Type* Typer::Visitor::TypeObjectIsCallable(Node* node) { Type* Typer::Visitor::TypeObjectIsCallable(Node* node) {
return TypeUnaryOp(node, ObjectIsCallable); return TypeUnaryOp(node, ObjectIsCallable);
} }
...@@ -2026,6 +2042,13 @@ Type* Typer::Visitor::TypeDebugBreak(Node* node) { return Type::None(); } ...@@ -2026,6 +2042,13 @@ Type* Typer::Visitor::TypeDebugBreak(Node* node) { return Type::None(); }
Type* Typer::Visitor::TypeComment(Node* node) { return Type::None(); } Type* Typer::Visitor::TypeComment(Node* node) { return Type::None(); }
Type* Typer::Visitor::TypeRetain(Node* node) {
UNREACHABLE();
return nullptr;
}
Type* Typer::Visitor::TypeUnsafePointerAdd(Node* node) { return Type::None(); }
Type* Typer::Visitor::TypeLoad(Node* node) { return Type::Any(); } Type* Typer::Visitor::TypeLoad(Node* node) { return Type::Any(); }
Type* Typer::Visitor::TypeStackSlot(Node* node) { return Type::Any(); } Type* Typer::Visitor::TypeStackSlot(Node* node) { return Type::Any(); }
......
...@@ -650,11 +650,10 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -650,11 +650,10 @@ void Verifier::Visitor::Check(Node* node) {
CheckNotTyped(node); CheckNotTyped(node);
break; break;
case IrOpcode::kDebugBreak:
CheckNotTyped(node);
break;
case IrOpcode::kComment: case IrOpcode::kComment:
case IrOpcode::kDebugBreak:
case IrOpcode::kRetain:
case IrOpcode::kUnsafePointerAdd:
CheckNotTyped(node); CheckNotTyped(node);
break; break;
...@@ -1042,6 +1041,8 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -1042,6 +1041,8 @@ void Verifier::Visitor::Check(Node* node) {
// CheckValueInputIs(node, 0, Type::Object()); // CheckValueInputIs(node, 0, Type::Object());
// CheckUpperIs(node, ElementAccessOf(node->op()).type)); // CheckUpperIs(node, ElementAccessOf(node->op()).type));
break; break;
case IrOpcode::kLoadTypedElement:
break;
case IrOpcode::kStoreField: case IrOpcode::kStoreField:
// (Object, fieldtype) -> _|_ // (Object, fieldtype) -> _|_
// TODO(rossberg): activate once machine ops are typed. // TODO(rossberg): activate once machine ops are typed.
...@@ -1058,6 +1059,9 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -1058,6 +1059,9 @@ void Verifier::Visitor::Check(Node* node) {
// CheckValueInputIs(node, 1, ElementAccessOf(node->op()).type)); // CheckValueInputIs(node, 1, ElementAccessOf(node->op()).type));
CheckNotTyped(node); CheckNotTyped(node);
break; break;
case IrOpcode::kStoreTypedElement:
CheckNotTyped(node);
break;
case IrOpcode::kNumberSilenceNaN: case IrOpcode::kNumberSilenceNaN:
CheckValueInputIs(node, 0, Type::Number()); CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Number()); CheckUpperIs(node, Type::Number());
......
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