diff --git a/src/code-factory.cc b/src/code-factory.cc index e9398300e61..10d38c7eabc 100644 --- a/src/code-factory.cc +++ b/src/code-factory.cc @@ -102,6 +102,13 @@ Callable CodeFactory::ToFloat32x4Obj(Isolate* isolate) { } +// static +Callable CodeFactory::ToInt32x4Obj(Isolate* isolate) { + ToInt32x4Stub stub(isolate); + return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor()); +} + + // static Callable CodeFactory::ToFloat64x2Obj(Isolate* isolate) { ToFloat64x2Stub stub(isolate); @@ -131,6 +138,13 @@ Callable CodeFactory::AllocateFloat32x4(Isolate* isolate) { } +// static +Callable CodeFactory::AllocateInt32x4(Isolate* isolate) { + AllocateInt32x4Stub stub(isolate); + return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor()); +} + + // static Callable CodeFactory::AllocateFloat64x2(Isolate* isolate) { AllocateFloat64x2Stub stub(isolate); diff --git a/src/code-factory.h b/src/code-factory.h index 375e623e820..65e0813ae09 100644 --- a/src/code-factory.h +++ b/src/code-factory.h @@ -54,6 +54,8 @@ class CodeFactory FINAL { static Callable ToFloat32x4Obj(Isolate* isolate); + static Callable ToInt32x4Obj(Isolate* isolate); + static Callable ToFloat64x2Obj(Isolate* isolate); static Callable StringAdd(Isolate* isolate, StringAddFlags flags, @@ -63,6 +65,8 @@ class CodeFactory FINAL { static Callable AllocateFloat32x4(Isolate* isolate); + static Callable AllocateInt32x4(Isolate* isolate); + static Callable AllocateFloat64x2(Isolate* isolate); static Callable CallFunction(Isolate* isolate, int argc, diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index be0e59788db..80061005019 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -938,6 +938,40 @@ Handle AllocateFloat32x4Stub::GenerateCode() { } +template <> +HValue* CodeStubGraphBuilder::BuildCodeStub() { + HValue* result = + Add(Add(Int32x4::kSize), HType::Int32x4(), + NOT_TENURED, INT32x4_TYPE); + HInstruction* int32x4_fun = + Add(handle(isolate()->native_context()->int32x4_function())); + HObjectAccess map_access = HObjectAccess::ForPrototypeOrInitialMap(); + HInstruction* int32x4_map = Add( + int32x4_fun, static_cast(NULL), map_access); + Add(result, HObjectAccess::ForMap(), int32x4_map); + HInstruction* empty_fixed_array = + Add(isolate()->factory()->empty_fixed_array()); + Add(result, HObjectAccess::ForPropertiesPointer(), + empty_fixed_array); + Add(result, HObjectAccess::ForElementsPointer(), + empty_fixed_array); + + HValue* value = Add( + Add(FixedTypedArrayBase::kDataOffset + kInt32x4Size), + HType::HeapObject(), NOT_TENURED, FIXED_INT32x4_ARRAY_TYPE); + Add(result, HObjectAccess::ForSIMD128Value(), value); + AddStoreMapConstant(value, isolate()->factory()->fixed_int32x4_array_map()); + Add(value, HObjectAccess::ForFixedArrayLength(), + Add(1)); + return result; +} + + +Handle AllocateInt32x4Stub::GenerateCode() { + return DoGenerateCode(this); +} + + template <> HValue* CodeStubGraphBuilder::BuildCodeStub() { HValue* result = diff --git a/src/code-stubs.cc b/src/code-stubs.cc index a571c20472e..214645db2ee 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -707,6 +707,12 @@ void AllocateFloat32x4Stub::InitializeDescriptor( } +void AllocateInt32x4Stub::InitializeDescriptor( + CodeStubDescriptor* descriptor) { + descriptor->Initialize( + Runtime::FunctionForId(Runtime::kAllocateInt32x4)->entry); +} + void AllocateFloat64x2Stub::InitializeDescriptor( CodeStubDescriptor* descriptor) { descriptor->Initialize( diff --git a/src/code-stubs.h b/src/code-stubs.h index 2fbc7ba32cb..ff0ed10aa72 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -52,10 +52,12 @@ namespace internal { V(SubString) \ V(ToNumber) \ V(ToFloat32x4) \ + V(ToInt32x4) \ V(ToFloat64x2) \ /* HydrogenCodeStubs */ \ V(AllocateHeapNumber) \ V(AllocateFloat32x4) \ + V(AllocateInt32x4) \ V(AllocateFloat64x2) \ V(ArrayNArgumentsConstructor) \ V(ArrayNoArgumentConstructor) \ @@ -2164,6 +2166,17 @@ class AllocateFloat32x4Stub FINAL : public HydrogenCodeStub { }; +class AllocateInt32x4Stub FINAL : public HydrogenCodeStub { + public: + explicit AllocateInt32x4Stub(Isolate* isolate) + : HydrogenCodeStub(isolate) {} + + private: + DEFINE_CALL_INTERFACE_DESCRIPTOR(AllocateInt32x4); + DEFINE_HYDROGEN_CODE_STUB(AllocateInt32x4, HydrogenCodeStub); +}; + + class AllocateFloat64x2Stub FINAL : public HydrogenCodeStub { public: explicit AllocateFloat64x2Stub(Isolate* isolate) @@ -2601,6 +2614,15 @@ class ToFloat32x4Stub FINAL : public PlatformCodeStub { }; +class ToInt32x4Stub FINAL : public PlatformCodeStub { + public: + explicit ToInt32x4Stub(Isolate* isolate) : PlatformCodeStub(isolate) {} + + DEFINE_CALL_INTERFACE_DESCRIPTOR(ToInt32x4); + DEFINE_PLATFORM_CODE_STUB(ToInt32x4, PlatformCodeStub); +}; + + class ToFloat64x2Stub FINAL : public PlatformCodeStub { public: explicit ToFloat64x2Stub(Isolate* isolate) : PlatformCodeStub(isolate) {} diff --git a/src/compiler/change-lowering.cc b/src/compiler/change-lowering.cc index 2bf6d7ce040..7af4bb2946b 100644 --- a/src/compiler/change-lowering.cc +++ b/src/compiler/change-lowering.cc @@ -31,6 +31,10 @@ Reduction ChangeLowering::Reduce(Node* node) { return ChangeFloat32x4ToTagged(node->InputAt(0), control); case IrOpcode::kChangeTaggedToFloat32x4: return ChangeTaggedToFloat32x4(node->InputAt(0), control); + case IrOpcode::kChangeInt32x4ToTagged: + return ChangeInt32x4ToTagged(node->InputAt(0), control); + case IrOpcode::kChangeTaggedToInt32x4: + return ChangeTaggedToInt32x4(node->InputAt(0), control); case IrOpcode::kChangeFloat64x2ToTagged: return ChangeFloat64x2ToTagged(node->InputAt(0), control); case IrOpcode::kChangeTaggedToFloat64x2: @@ -69,6 +73,14 @@ Node* ChangeLowering::Float32x4ValueIndexConstant() { } +Node* ChangeLowering::Int32x4ValueIndexConstant() { + STATIC_ASSERT(Int32x4::kValueOffset % kPointerSize == 0); + const int value_offset = + ((Int32x4::kValueOffset / kPointerSize) * (machine()->Is64() ? 8 : 4)); + return jsgraph()->IntPtrConstant(value_offset - kHeapObjectTag); +} + + Node* ChangeLowering::Float64x2ValueIndexConstant() { STATIC_ASSERT(Float64x2::kValueOffset % kPointerSize == 0); const int value_offset = @@ -131,6 +143,27 @@ Node* ChangeLowering::AllocateFloat32x4WithValue(Node* value, Node* control) { } +Node* ChangeLowering::AllocateInt32x4WithValue(Node* value, Node* control) { + Callable callable = CodeFactory::AllocateInt32x4(isolate()); + CallDescriptor* descriptor = linkage()->GetStubCallDescriptor( + callable.descriptor(), 0, CallDescriptor::kNoFlags); + Node* target = jsgraph()->HeapConstant(callable.code()); + Node* context = jsgraph()->NoContextConstant(); + Node* effect = graph()->NewNode(common()->ValueEffect(1), value); + Node* int32x4_obj = graph()->NewNode(common()->Call(descriptor), target, + context, effect, control); + Node* val_obj = + graph()->NewNode(machine()->Load(kRepTagged), int32x4_obj, + Int32x4ValueIndexConstant(), int32x4_obj, control); + Node* stored_bytes = jsgraph()->Int32Constant(16); + Node* store = graph()->NewNode( + machine()->Store(StoreRepresentation(kRepInt32x4, kNoWriteBarrier)), + val_obj, jsgraph()->IntPtrConstant(FixedTypedArrayBase::kDataOffset - 1), + value, stored_bytes, val_obj, control); + return graph()->NewNode(common()->Finish(1), int32x4_obj, store); +} + + Node* ChangeLowering::AllocateFloat64x2WithValue(Node* value, Node* control) { Callable callable = CodeFactory::AllocateFloat64x2(isolate()); CallDescriptor* descriptor = linkage()->GetStubCallDescriptor( @@ -228,6 +261,11 @@ Reduction ChangeLowering::ChangeFloat32x4ToTagged(Node* val, Node* control) { } +Reduction ChangeLowering::ChangeInt32x4ToTagged(Node* val, Node* control) { + return Replace(AllocateInt32x4WithValue(val, control)); +} + + Reduction ChangeLowering::ChangeFloat64x2ToTagged(Node* val, Node* control) { return Replace(AllocateFloat64x2WithValue(val, control)); } @@ -361,6 +399,39 @@ Reduction ChangeLowering::ChangeTaggedToFloat32x4(Node* value, Node* control) { } +Reduction ChangeLowering::ChangeTaggedToInt32x4(Node* value, Node* control) { + if (CanCover(value, IrOpcode::kJSToInt32x4Obj)) { + Node* const object = NodeProperties::GetValueInput(value, 0); + Node* const effect = NodeProperties::GetEffectInput(value); + Node* const control = NodeProperties::GetControlInput(value); + + Node* val_obj = + graph()->NewNode(machine()->Load(kRepTagged), object, + Int32x4ValueIndexConstant(), effect, control); + + Node* loaded_bytes = jsgraph()->Int32Constant(16); + Node* load = graph()->NewNode( + machine()->Load(kRepInt32x4), val_obj, + jsgraph()->IntPtrConstant(FixedTypedArrayBase::kDataOffset - 1), + loaded_bytes, effect, control); + + return Replace(load); + } else { + Node* val_obj = graph()->NewNode(machine()->Load(kRepTagged), value, + Int32x4ValueIndexConstant(), + graph()->start(), control); + + Node* loaded_bytes = jsgraph()->Int32Constant(16); + Node* load = graph()->NewNode( + machine()->Load(kRepInt32x4), val_obj, + jsgraph()->IntPtrConstant(FixedTypedArrayBase::kDataOffset - 1), + loaded_bytes, graph()->start(), control); + + return Replace(load); + } +} + + Reduction ChangeLowering::ChangeTaggedToFloat64x2(Node* value, Node* control) { if (CanCover(value, IrOpcode::kJSToFloat64x2Obj)) { Node* const object = NodeProperties::GetValueInput(value, 0); diff --git a/src/compiler/change-lowering.h b/src/compiler/change-lowering.h index da04741a9a5..39037d37d34 100644 --- a/src/compiler/change-lowering.h +++ b/src/compiler/change-lowering.h @@ -28,12 +28,14 @@ class ChangeLowering FINAL : public Reducer { private: Node* HeapNumberValueIndexConstant(); Node* Float32x4ValueIndexConstant(); + Node* Int32x4ValueIndexConstant(); Node* Float64x2ValueIndexConstant(); Node* SmiMaxValueConstant(); Node* SmiShiftBitsConstant(); Node* AllocateHeapNumberWithValue(Node* value, Node* control); Node* AllocateFloat32x4WithValue(Node* value, Node* control); + Node* AllocateInt32x4WithValue(Node* value, Node* control); Node* AllocateFloat64x2WithValue(Node* value, Node* control); Node* ChangeInt32ToFloat64(Node* value); Node* ChangeSmiToFloat64(Node* value); @@ -48,10 +50,12 @@ class ChangeLowering FINAL : public Reducer { Reduction ChangeBoolToBit(Node* value); Reduction ChangeFloat64ToTagged(Node* value, Node* control); Reduction ChangeFloat32x4ToTagged(Node* value, Node* control); + Reduction ChangeInt32x4ToTagged(Node* value, Node* control); Reduction ChangeFloat64x2ToTagged(Node* value, Node* control); Reduction ChangeInt32ToTagged(Node* value, Node* control); Reduction ChangeTaggedToFloat64(Node* value, Node* control); Reduction ChangeTaggedToFloat32x4(Node* value, Node* control); + Reduction ChangeTaggedToInt32x4(Node* value, Node* control); Reduction ChangeTaggedToFloat64x2(Node* value, Node* control); Reduction ChangeTaggedToUI32(Node* value, Node* control, Signedness signedness); diff --git a/src/compiler/instruction-codes.h b/src/compiler/instruction-codes.h index df1d9575dd8..0255615353d 100644 --- a/src/compiler/instruction-codes.h +++ b/src/compiler/instruction-codes.h @@ -76,6 +76,17 @@ namespace compiler { V(Float32x4WithW) \ V(Float32x4Clamp) \ V(Float32x4Swizzle) \ + V(Int32x4Add) \ + V(Int32x4And) \ + V(Int32x4Mul) \ + V(Int32x4Sub) \ + V(Int32x4Or) \ + V(Int32x4Xor) \ + V(Int32x4Constructor) \ + V(Int32x4GetX) \ + V(Int32x4GetY) \ + V(Int32x4GetZ) \ + V(Int32x4GetW) \ V(LoadSIMD128) \ V(CheckedLoadSIMD128) \ V(StoreSIMD128) \ diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc index e7bf2aad28a..f04ccda41a0 100644 --- a/src/compiler/instruction-selector.cc +++ b/src/compiler/instruction-selector.cc @@ -956,6 +956,28 @@ void InstructionSelector::VisitNode(Node* node) { return MarkAsFloat32x4(node), VisitFloat32x4Clamp(node); case IrOpcode::kFloat32x4Swizzle: return MarkAsFloat32x4(node), VisitFloat32x4Swizzle(node); + case IrOpcode::kInt32x4Add: + return MarkAsInt32x4(node), VisitInt32x4Add(node); + case IrOpcode::kInt32x4And: + return MarkAsInt32x4(node), VisitInt32x4And(node); + case IrOpcode::kInt32x4Sub: + return MarkAsInt32x4(node), VisitInt32x4Sub(node); + case IrOpcode::kInt32x4Mul: + return MarkAsInt32x4(node), VisitInt32x4Mul(node); + case IrOpcode::kInt32x4Or: + return MarkAsInt32x4(node), VisitInt32x4Or(node); + case IrOpcode::kInt32x4Xor: + return MarkAsInt32x4(node), VisitInt32x4Xor(node); + case IrOpcode::kInt32x4Constructor: + return MarkAsInt32x4(node), VisitInt32x4Constructor(node); + case IrOpcode::kInt32x4GetX: + return VisitInt32x4GetX(node); + case IrOpcode::kInt32x4GetY: + return VisitInt32x4GetY(node); + case IrOpcode::kInt32x4GetZ: + return VisitInt32x4GetZ(node); + case IrOpcode::kInt32x4GetW: + return VisitInt32x4GetW(node); case IrOpcode::kFloat64x2Add: return MarkAsFloat64x2(node), VisitFloat64x2Add(node); case IrOpcode::kFloat64x2Sub: diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc index 366c7fd9009..4a38feb0980 100644 --- a/src/compiler/js-builtin-reducer.cc +++ b/src/compiler/js-builtin-reducer.cc @@ -105,6 +105,10 @@ JSBuiltinReducer::JSBuiltinReducer(JSGraph* jsgraph) isolate->native_context()->float32x4_function()->initial_map(), isolate); float32x4_ = Type::Class(float32x4_map, jsgraph_->zone()); + Handle int32x4_map = handle( + isolate->native_context()->int32x4_function()->initial_map(), isolate); + int32x4_ = Type::Class(int32x4_map, jsgraph_->zone()); + Handle float64x2_map = handle( isolate->native_context()->float64x2_function()->initial_map(), isolate); float64x2_ = Type::Class(float64x2_map, jsgraph_->zone()); @@ -233,6 +237,12 @@ Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) { V(float32x4_, Type::Number(), Float32x4WithY) \ V(float32x4_, Type::Number(), Float32x4WithZ) \ V(float32x4_, Type::Number(), Float32x4WithW) \ + V(int32x4_, int32x4_, Int32x4Add) \ + V(int32x4_, int32x4_, Int32x4And) \ + V(int32x4_, int32x4_, Int32x4Sub) \ + V(int32x4_, int32x4_, Int32x4Mul) \ + V(int32x4_, int32x4_, Int32x4Or) \ + V(int32x4_, int32x4_, Int32x4Xor) \ V(float64x2_, float64x2_, Float64x2Add) \ V(float64x2_, float64x2_, Float64x2Sub) \ V(float64x2_, float64x2_, Float64x2Mul) \ @@ -296,6 +306,41 @@ Reduction JSBuiltinReducer::ReduceFloat32x4Constructor(Node* node) { } +Reduction JSBuiltinReducer::ReduceInt32x4Constructor(Node* node) { + // SIMD.int32x4(x, y, z, w) -> + // Int32x4(x:int32, y:int32, z:int32, w:int32) + JSCallReduction r(node); + if (r.InputsMatchZero()) { + // SIMD.Int32x4() -> SIMD.Int32x4(0, 0, 0, 0); + Node* value = + graph()->NewNode(machine()->Int32x4Constructor(), + jsgraph()->ZeroConstant(), jsgraph()->ZeroConstant(), + jsgraph()->ZeroConstant(), jsgraph()->ZeroConstant()); + return Replace(value); + } else if (r.GetJSCallArity() == 4 && r.InputsMatchAll(Type::Number())) { + Node* value = graph()->NewNode(machine()->Int32x4Constructor(), + r.GetJSCallInput(0), r.GetJSCallInput(1), + r.GetJSCallInput(2), r.GetJSCallInput(3)); + return Replace(value); + } else if (r.GetJSCallArity() == 1) { + // SIMD.int32x4(...) -> type annotation + if (r.InputsMatchOne(int32x4_)) { + return Replace(r.GetJSCallInput(0)); + } else { + Node* const object = r.GetJSCallInput(0); + Node* const effect = NodeProperties::GetEffectInput(node); + Node* const control = NodeProperties::GetControlInput(node); + Node* value = + graph()->NewNode(jsgraph()->javascript()->ToInt32x4Obj(), object, + jsgraph()->NoContextConstant(), effect, control); + return Replace(value); + } + } + + return NoChange(); +} + + Reduction JSBuiltinReducer::ReduceFloat64x2Constructor(Node* node) { // SIMD.float64x2(x, y) -> // Float64x2(x:float64, y:float64) @@ -613,6 +658,20 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { return ReplaceWithPureReduction(node, ReduceSetFloat32x4XYZ(node)); case kSetFloat32x4XYZW: return ReplaceWithPureReduction(node, ReduceSetFloat32x4XYZW(node)); + case kInt32x4Add: + return ReplaceWithPureReduction(node, ReduceInt32x4Add(node)); + case kInt32x4And: + return ReplaceWithPureReduction(node, ReduceInt32x4And(node)); + case kInt32x4Sub: + return ReplaceWithPureReduction(node, ReduceInt32x4Sub(node)); + case kInt32x4Mul: + return ReplaceWithPureReduction(node, ReduceInt32x4Mul(node)); + case kInt32x4Or: + return ReplaceWithPureReduction(node, ReduceInt32x4Or(node)); + case kInt32x4Xor: + return ReplaceWithPureReduction(node, ReduceInt32x4Xor(node)); + case kInt32x4Constructor: + return ReplaceWithPureReduction(node, ReduceInt32x4Constructor(node)); case kFloat64x2Add: return ReplaceWithPureReduction(node, ReduceFloat64x2Add(node)); case kFloat64x2Sub: diff --git a/src/compiler/js-builtin-reducer.h b/src/compiler/js-builtin-reducer.h index b6889c8c369..5904813dd57 100644 --- a/src/compiler/js-builtin-reducer.h +++ b/src/compiler/js-builtin-reducer.h @@ -61,7 +61,13 @@ class JSBuiltinReducer FINAL : public Reducer { Reduction ReduceSetFloat32x4XY(Node* node); Reduction ReduceSetFloat32x4XYZ(Node* node); Reduction ReduceSetFloat32x4XYZW(Node* node); - + Reduction ReduceInt32x4Add(Node* node); + Reduction ReduceInt32x4And(Node* node); + Reduction ReduceInt32x4Sub(Node* node); + Reduction ReduceInt32x4Mul(Node* node); + Reduction ReduceInt32x4Or(Node* node); + Reduction ReduceInt32x4Xor(Node* node); + Reduction ReduceInt32x4Constructor(Node* node); Reduction ReduceFloat64x2Add(Node* node); Reduction ReduceFloat64x2Sub(Node* node); Reduction ReduceFloat64x2Mul(Node* node); @@ -90,6 +96,7 @@ class JSBuiltinReducer FINAL : public Reducer { JSGraph* jsgraph_; SimplifiedOperatorBuilder simplified_; Type* float32x4_; + Type* int32x4_; Type* float64x2_; }; diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index 5c76d06901e..b7bc10dd384 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -252,6 +252,12 @@ void JSGenericLowering::LowerJSToFloat32x4Obj(Node* node) { } +void JSGenericLowering::LowerJSToInt32x4Obj(Node* node) { + Callable callable = CodeFactory::ToInt32x4Obj(isolate()); + ReplaceWithStubCall(node, callable, FlagsForNode(node)); +} + + void JSGenericLowering::LowerJSToFloat64x2Obj(Node* node) { Callable callable = CodeFactory::ToFloat64x2Obj(isolate()); ReplaceWithStubCall(node, callable, FlagsForNode(node)); diff --git a/src/compiler/js-operator.cc b/src/compiler/js-operator.cc index 5e43b0633be..e63aeb0381d 100644 --- a/src/compiler/js-operator.cc +++ b/src/compiler/js-operator.cc @@ -235,6 +235,7 @@ const StoreNamedParameters& StoreNamedParametersOf(const Operator* op) { V(ToName, Operator::kNoProperties, 1, 1) \ V(ToObject, Operator::kNoProperties, 1, 1) \ V(ToFloat32x4Obj, Operator::kNoProperties, 1, 1) \ + V(ToInt32x4Obj, Operator::kNoProperties, 1, 1) \ V(ToFloat64x2Obj, Operator::kNoProperties, 1, 1) \ V(Yield, Operator::kNoProperties, 1, 1) \ V(Create, Operator::kEliminatable, 0, 1) \ diff --git a/src/compiler/js-operator.h b/src/compiler/js-operator.h index cd34e41bcf4..ca30ac0868a 100644 --- a/src/compiler/js-operator.h +++ b/src/compiler/js-operator.h @@ -226,6 +226,7 @@ class JSOperatorBuilder FINAL : public ZoneObject { const Operator* ToName(); const Operator* ToObject(); const Operator* ToFloat32x4Obj(); + const Operator* ToInt32x4Obj(); const Operator* ToFloat64x2Obj(); const Operator* Yield(); diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc index 699ce2a38b3..326c6ceac57 100644 --- a/src/compiler/js-typed-lowering.cc +++ b/src/compiler/js-typed-lowering.cc @@ -42,6 +42,11 @@ JSTypedLowering::JSTypedLowering(JSGraph* jsgraph, Zone* zone) Handle float32x4_map = handle( isolate->native_context()->float32x4_function()->initial_map(), isolate); float32x4_ = Type::Class(float32x4_map, jsgraph_->zone()); + + Handle int32x4_map = handle( + isolate->native_context()->int32x4_function()->initial_map(), isolate); + int32x4_ = Type::Class(int32x4_map, jsgraph_->zone()); + Handle float64x2_map = handle( isolate->native_context()->float64x2_function()->initial_map(), isolate); float64x2_ = Type::Class(float64x2_map, jsgraph_->zone()); @@ -662,6 +667,19 @@ Reduction JSTypedLowering::ReduceJSToFloat32x4Obj(Node* node) { } +Reduction JSTypedLowering::ReduceJSToInt32x4Obj(Node* node) { + Node* const input = node->InputAt(0); + if (input->opcode() == IrOpcode::kJSToInt32x4Obj) { + // Recursively try to reduce the input first. + Reduction result = ReduceJSToInt32x4Obj(input); + if (!result.Changed()) result = Changed(input); + NodeProperties::ReplaceWithValue(node, result.replacement()); + return result; + } + return NoChange(); +} + + Reduction JSTypedLowering::ReduceJSToFloat64x2Obj(Node* node) { Node* const input = node->InputAt(0); if (input->opcode() == IrOpcode::kJSToFloat64x2Obj) { @@ -772,6 +790,23 @@ Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) { value = graph()->NewNode(machine()->Float32x4GetSignMask(), obj); } + if (value != NULL) { + NodeProperties::ReplaceWithValue(node, value); + return Replace(value); + } + } else if (NodeProperties::GetBounds(obj).upper->Is(int32x4_)) { + Node* value = NULL; + Handle name = p.name().handle(); + if (name->Equals(isolate->heap()->x())) { + value = graph()->NewNode(machine()->Int32x4GetX(), obj); + } else if (name->Equals(isolate->heap()->y())) { + value = graph()->NewNode(machine()->Int32x4GetY(), obj); + } else if (name->Equals(isolate->heap()->z())) { + value = graph()->NewNode(machine()->Int32x4GetZ(), obj); + } else if (name->Equals(isolate->heap()->w())) { + value = graph()->NewNode(machine()->Int32x4GetW(), obj); + } + if (value != NULL) { NodeProperties::ReplaceWithValue(node, value); return Replace(value); diff --git a/src/compiler/js-typed-lowering.h b/src/compiler/js-typed-lowering.h index d28b8cdf430..db6a06ed868 100644 --- a/src/compiler/js-typed-lowering.h +++ b/src/compiler/js-typed-lowering.h @@ -47,6 +47,7 @@ class JSTypedLowering FINAL : public Reducer { Reduction ReduceJSToNumberInput(Node* input); Reduction ReduceJSToNumber(Node* node); Reduction ReduceJSToFloat32x4Obj(Node* node); + Reduction ReduceJSToInt32x4Obj(Node* node); Reduction ReduceJSToFloat64x2Obj(Node* node); Reduction ReduceJSToStringInput(Node* input); Reduction ReduceJSToString(Node* node); @@ -77,6 +78,7 @@ class JSTypedLowering FINAL : public Reducer { Type* one_range_; Type* zero_thirtyone_range_; Type* float32x4_; + Type* int32x4_; Type* float64x2_; Type* shifted_int32_ranges_[4]; }; diff --git a/src/compiler/machine-operator.cc b/src/compiler/machine-operator.cc index 725d417f686..b721d6db6e6 100644 --- a/src/compiler/machine-operator.cc +++ b/src/compiler/machine-operator.cc @@ -158,6 +158,17 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) { V(Float32x4WithW, Operator::kNoProperties, 2, 0, 1) \ V(Float32x4Clamp, Operator::kNoProperties, 3, 0, 1) \ V(Float32x4Swizzle, Operator::kNoProperties, 5, 0, 1) \ + V(Int32x4Add, Operator::kCommutative, 2, 0, 1) \ + V(Int32x4And, Operator::kCommutative, 2, 0, 1) \ + V(Int32x4Sub, Operator::kNoProperties, 2, 0, 1) \ + V(Int32x4Mul, Operator::kCommutative, 2, 0, 1) \ + V(Int32x4Or, Operator::kCommutative, 2, 0, 1) \ + V(Int32x4Xor, Operator::kNoProperties, 2, 0, 1) \ + V(Int32x4Constructor, Operator::kNoProperties, 4, 0, 1) \ + V(Int32x4GetX, Operator::kNoProperties, 1, 0, 1) \ + V(Int32x4GetY, Operator::kNoProperties, 1, 0, 1) \ + V(Int32x4GetZ, Operator::kNoProperties, 1, 0, 1) \ + V(Int32x4GetW, Operator::kNoProperties, 1, 0, 1) \ V(Float64x2Add, Operator::kCommutative, 2, 0, 1) \ V(Float64x2Sub, Operator::kNoProperties, 2, 0, 1) \ V(Float64x2Mul, Operator::kCommutative, 2, 0, 1) \ @@ -201,6 +212,8 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) { #define MACHINE_SIMD_TYPE_LIST(V) \ V(RepFloat32x4) \ V(MachFloat32x4) \ + V(RepInt32x4) \ + V(MachInt32x4) \ V(RepFloat64x2) \ V(MachFloat64x2) diff --git a/src/compiler/machine-operator.h b/src/compiler/machine-operator.h index d9bd3596573..52db6a8967b 100644 --- a/src/compiler/machine-operator.h +++ b/src/compiler/machine-operator.h @@ -204,6 +204,17 @@ class MachineOperatorBuilder FINAL : public ZoneObject { V(Float32x4WithW) \ V(Float32x4Clamp) \ V(Float32x4Swizzle) \ + V(Int32x4Add) \ + V(Int32x4And) \ + V(Int32x4Mul) \ + V(Int32x4Sub) \ + V(Int32x4Or) \ + V(Int32x4Xor) \ + V(Int32x4Constructor) \ + V(Int32x4GetX) \ + V(Int32x4GetY) \ + V(Int32x4GetZ) \ + V(Int32x4GetW) \ V(Float64x2Add) \ V(Float64x2Mul) \ V(Float64x2Sub) \ diff --git a/src/compiler/machine-type.h b/src/compiler/machine-type.h index db97377cdfd..a183f278dfb 100644 --- a/src/compiler/machine-type.h +++ b/src/compiler/machine-type.h @@ -55,7 +55,7 @@ enum MachineType { kMachInt64 = kRepWord64 | kTypeInt64, kMachUint64 = kRepWord64 | kTypeUint64, kMachFloat32x4 = kRepFloat32x4 | kTypeVector, - kMachInt32x4 = kRepFloat32x4 | kTypeVector, + kMachInt32x4 = kRepInt32x4 | kTypeVector, kMachFloat64x2 = kRepFloat64x2 | kTypeVector, kMachIntPtr = (kPointerSize == 4) ? kMachInt32 : kMachInt64, kMachUintPtr = (kPointerSize == 4) ? kMachUint32 : kMachUint64, @@ -70,7 +70,7 @@ typedef uint32_t MachineTypeUnion; // Globally useful machine types and constants. const MachineTypeUnion kRepMask = kRepBit | kRepWord8 | kRepWord16 | kRepWord32 | kRepWord64 | kRepFloat32 | - kRepFloat64 | kRepFloat32x4 | kRepFloat64x2 | kRepTagged; + kRepFloat64 | kRepFloat32x4 | kRepInt32x4 | kRepFloat64x2 | kRepTagged; const MachineTypeUnion kTypeMask = kTypeBool | kTypeInt32 | kTypeUint32 | kTypeInt64 | kTypeUint64 | kTypeNumber | kTypeVector | kTypeAny; diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index 3feb93099b5..1a6f3303f73 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -88,6 +88,7 @@ V(JSToName) \ V(JSToObject) \ V(JSToFloat32x4Obj) \ + V(JSToInt32x4Obj) \ V(JSToFloat64x2Obj) #define JS_OTHER_UNOP_LIST(V) \ @@ -160,6 +161,8 @@ V(ChangeFloat64ToTagged) \ V(ChangeFloat32x4ToTagged) \ V(ChangeTaggedToFloat32x4) \ + V(ChangeInt32x4ToTagged) \ + V(ChangeTaggedToInt32x4) \ V(ChangeFloat64x2ToTagged) \ V(ChangeTaggedToFloat64x2) \ V(ChangeBoolToBit) \ @@ -269,6 +272,17 @@ V(Float32x4WithW) \ V(Float32x4Clamp) \ V(Float32x4Swizzle) \ + V(Int32x4Add) \ + V(Int32x4And) \ + V(Int32x4Mul) \ + V(Int32x4Sub) \ + V(Int32x4Or) \ + V(Int32x4Xor) \ + V(Int32x4Constructor) \ + V(Int32x4GetX) \ + V(Int32x4GetY) \ + V(Int32x4GetZ) \ + V(Int32x4GetW) \ V(Float64x2Add) \ V(Float64x2Mul) \ V(Float64x2Sub) \ diff --git a/src/compiler/operator-properties.cc b/src/compiler/operator-properties.cc index 3a1122d35d7..7928de2dc37 100644 --- a/src/compiler/operator-properties.cc +++ b/src/compiler/operator-properties.cc @@ -71,6 +71,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) { // Conversions case IrOpcode::kJSToObject: case IrOpcode::kJSToFloat32x4Obj: + case IrOpcode::kJSToInt32x4Obj: case IrOpcode::kJSToFloat64x2Obj: // Other diff --git a/src/compiler/representation-change.h b/src/compiler/representation-change.h index a42f1b59f2a..45273eef49b 100644 --- a/src/compiler/representation-change.h +++ b/src/compiler/representation-change.h @@ -66,6 +66,8 @@ class RepresentationChanger { return GetWord64RepresentationFor(node, output_type); } else if (use_type & kRepFloat32x4) { return GetFloat32x4RepresentationFor(node, output_type); + } else if (use_type & kRepInt32x4) { + return GetInt32x4RepresentationFor(node, output_type); } else if (use_type & kRepFloat64x2) { return GetFloat64x2RepresentationFor(node, output_type); } else { @@ -118,6 +120,8 @@ class RepresentationChanger { op = simplified()->ChangeFloat64ToTagged(); } else if (output_type & kRepFloat32x4) { op = simplified()->ChangeFloat32x4ToTagged(); + } else if (output_type & kRepInt32x4) { + op = simplified()->ChangeInt32x4ToTagged(); } else if (output_type & kRepFloat64x2) { op = simplified()->ChangeFloat64x2ToTagged(); } else { @@ -225,6 +229,19 @@ class RepresentationChanger { } } + Node* GetInt32x4RepresentationFor(Node* node, + MachineTypeUnion output_type) { + // Select the correct X -> Int32x4 operator. + if (output_type & kRepTagged) { + return jsgraph()->graph()->NewNode( + simplified()->ChangeTaggedToInt32x4(), node); + } else if (output_type & kRepInt32x4) { + return node; + } else { + return TypeError(node, output_type, kRepInt32x4); + } + } + Node* GetFloat64x2RepresentationFor(Node* node, MachineTypeUnion output_type) { // Select the correct X -> Float64x2 operator. diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc index 9626b60f409..a2bf9939c35 100644 --- a/src/compiler/simplified-lowering.cc +++ b/src/compiler/simplified-lowering.cc @@ -89,6 +89,12 @@ class RepresentationSelector { ->initial_map(), zone->isolate()), zone); + int32x4_ = Type::Class(handle(zone->isolate() + ->native_context() + ->int32x4_function() + ->initial_map(), + zone->isolate()), + zone); float64x2_ = Type::Class(handle(zone->isolate() ->native_context() ->float64x2_function() @@ -343,6 +349,8 @@ class RepresentationSelector { return kRepFloat64; } else if (upper->Is(float32x4_)) { return kRepFloat32x4; + } else if (upper->Is(int32x4_)) { + return kRepInt32x4; } else if (upper->Is(float64x2_)) { return kRepFloat64x2; } @@ -903,6 +911,7 @@ class RepresentationSelector { ProcessInput(node, 0, tBase); // pointer or object ProcessInput(node, 1, kMachInt32); // index if (RepresentationOf(rep) == kRepFloat32x4 || + RepresentationOf(rep) == kRepInt32x4 || RepresentationOf(rep) == kRepFloat64x2) { ProcessInput(node, 2, kMachInt32); // partial ProcessRemainingInputs(node, 3); @@ -919,6 +928,7 @@ class RepresentationSelector { ProcessInput(node, 1, kMachInt32); // index ProcessInput(node, 2, kMachInt32); // length if (RepresentationOf(rep) == kRepFloat32x4 || + RepresentationOf(rep) == kRepInt32x4 || RepresentationOf(rep) == kRepFloat64x2) { ProcessInput(node, 3, kMachInt32); // partial ProcessRemainingInputs(node, 4); @@ -936,6 +946,7 @@ class RepresentationSelector { ProcessInput(node, 1, kMachInt32); // index ProcessInput(node, 2, rep.machine_type()); if (rep.machine_type() == kRepFloat32x4 || + rep.machine_type() == kRepInt32x4 || rep.machine_type() == kRepFloat64x2) { ProcessInput(node, 3, kMachInt32); // partial ProcessRemainingInputs(node, 4); @@ -1149,6 +1160,35 @@ class RepresentationSelector { ProcessInput(node, 4, kMachInt32); SetOutput(node, kMachFloat32x4); break; + // Int32x4 + case IrOpcode::kInt32x4Add: + case IrOpcode::kInt32x4And: + case IrOpcode::kInt32x4Sub: + case IrOpcode::kInt32x4Mul: + case IrOpcode::kInt32x4Or: + case IrOpcode::kInt32x4Xor: + DCHECK_EQ(2, node->InputCount()); + ProcessInput(node, 0, kMachInt32x4); + ProcessInput(node, 1, kMachInt32x4); + SetOutput(node, kMachInt32x4); + break; + case IrOpcode::kInt32x4Constructor: + DCHECK_EQ(4, node->InputCount()); + ProcessInput(node, 0, kMachInt32); + ProcessInput(node, 1, kMachInt32); + ProcessInput(node, 2, kMachInt32); + ProcessInput(node, 3, kMachInt32); + SetOutput(node, kMachInt32x4); + break; + case IrOpcode::kInt32x4GetX: + case IrOpcode::kInt32x4GetY: + case IrOpcode::kInt32x4GetZ: + case IrOpcode::kInt32x4GetW: + DCHECK_EQ(1, node->InputCount()); + ProcessInput(node, 0, kMachInt32x4); + SetOutput(node, kMachInt32); + break; + // Float64x2 case IrOpcode::kFloat64x2Add: case IrOpcode::kFloat64x2Sub: case IrOpcode::kFloat64x2Mul: @@ -1250,6 +1290,7 @@ class RepresentationSelector { Type* safe_bit_range_; Type* safe_int_additive_range_; Type* float32x4_; + Type* int32x4_; Type* float64x2_; NodeInfo* GetInfo(Node* node) { diff --git a/src/compiler/simplified-operator.cc b/src/compiler/simplified-operator.cc index ed5fd98fc53..35911dbf976 100644 --- a/src/compiler/simplified-operator.cc +++ b/src/compiler/simplified-operator.cc @@ -188,6 +188,8 @@ const ElementAccess& ElementAccessOf(const Operator* op) { V(ChangeFloat64ToTagged, Operator::kNoProperties, 1) \ V(ChangeFloat32x4ToTagged, Operator::kNoProperties, 1) \ V(ChangeTaggedToFloat32x4, Operator::kNoProperties, 1) \ + V(ChangeInt32x4ToTagged, Operator::kNoProperties, 1) \ + V(ChangeTaggedToInt32x4, Operator::kNoProperties, 1) \ V(ChangeFloat64x2ToTagged, Operator::kNoProperties, 1) \ V(ChangeTaggedToFloat64x2, Operator::kNoProperties, 1) \ V(ChangeBoolToBit, Operator::kNoProperties, 1) \ diff --git a/src/compiler/simplified-operator.h b/src/compiler/simplified-operator.h index a46c31d1623..0ddee967110 100644 --- a/src/compiler/simplified-operator.h +++ b/src/compiler/simplified-operator.h @@ -159,6 +159,8 @@ class SimplifiedOperatorBuilder FINAL { const Operator* ChangeFloat64ToTagged(); const Operator* ChangeFloat32x4ToTagged(); const Operator* ChangeTaggedToFloat32x4(); + const Operator* ChangeInt32x4ToTagged(); + const Operator* ChangeTaggedToInt32x4(); const Operator* ChangeFloat64x2ToTagged(); const Operator* ChangeTaggedToFloat64x2(); const Operator* ChangeBoolToBit(); diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 2ce7c8eab12..afc16aa6213 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -42,6 +42,9 @@ enum LazyCachedType { kFloat32x4Func3, kFloat32x4Func4f, kFloat32x4Func1_4i, + kInt32x4Tagged, + kInt32x4Func2, + kInt32x4Func4i, kFloat64x2Tagged, kFloat64x2Func1, kFloat64x2Func2, @@ -143,6 +146,19 @@ class LazyTypeCache FINAL : public ZoneObject { return Type::Function(Get(kFloat32x4), Get(kFloat32x4), Type::Integral32(), Type::Integral32(), Type::Integral32(), Type::Integral32(), zone()); + // Int32x4 + case kInt32x4: + return CreateInt32x4(); + case kInt32x4Tagged: + return CreateInt32x4Tagged(); + case kInt32x4Func2: + return Type::Function(Get(kInt32x4), Get(kInt32x4), Get(kInt32x4), + zone()); + case kInt32x4Func4i: + return Type::Function(Get(kFloat32x4), Type::Integral32(), + Type::Integral32(), Type::Integral32(), + Type::Integral32(), zone()); + // Float64x2 case kFloat64x2Tagged: return CreateFloat64x2Tagged(); case kFloat64x2: @@ -163,9 +179,6 @@ class LazyTypeCache FINAL : public ZoneObject { Get(kFloat64x2), zone()); case kFloat64x2FuncA: return Type::Function(Get(kFloat64x2), zone()); - case kInt32x4: - // TODO(huningxin): fix this workaround. - return NULL; } UNREACHABLE(); return NULL; @@ -213,6 +226,22 @@ class LazyTypeCache FINAL : public ZoneObject { zone()); } + Type* CreateInt32x4() { + Handle int32x4_map = + handle(isolate()->native_context()->int32x4_function()->initial_map(), + isolate()); + return Type::Intersect(Type::Class(int32x4_map, zone()), Type::Untagged(), + zone()); + } + + Type* CreateInt32x4Tagged() { + Handle int32x4_map = + handle(isolate()->native_context()->int32x4_function()->initial_map(), + isolate()); + return Type::Intersect(Type::Class(int32x4_map, zone()), Type::Tagged(), + zone()); + } + Type* CreateFloat64x2() { Handle float64x2_map = handle(isolate()->native_context()->float64x2_function()->initial_map(), @@ -319,6 +348,11 @@ Typer::Typer(Graph* graph, MaybeHandle context) isolate()); float32x4_ = Type::Class(float32x4_map, zone); + Handle int32x4_map = + handle(isolate()->native_context()->int32x4_function()->initial_map(), + isolate()); + int32x4_ = Type::Class(int32x4_map, zone); + Handle float64x2_map = handle(isolate()->native_context()->float64x2_function()->initial_map(), isolate()); @@ -1326,6 +1360,11 @@ Bounds Typer::Visitor::TypeJSToFloat32x4Obj(Node* node) { } +Bounds Typer::Visitor::TypeJSToInt32x4Obj(Node* node) { + return Bounds(Type::Intersect(typer_->int32x4_, Type::Tagged(), zone())); +} + + Bounds Typer::Visitor::TypeJSToFloat64x2Obj(Node* node) { return Bounds(Type::Intersect(typer_->float64x2_, Type::Tagged(), zone())); } @@ -1727,6 +1766,20 @@ Bounds Typer::Visitor::TypeChangeTaggedToFloat32x4(Node* node) { } +Bounds Typer::Visitor::TypeChangeInt32x4ToTagged(Node* node) { + Bounds arg = Operand(node, 0); + return Bounds(ChangeRepresentation(arg.lower, Type::Tagged(), zone()), + ChangeRepresentation(arg.upper, Type::Tagged(), zone())); +} + + +Bounds Typer::Visitor::TypeChangeTaggedToInt32x4(Node* node) { + Bounds arg = Operand(node, 0); + return Bounds(ChangeRepresentation(arg.lower, typer_->int32x4_, zone()), + ChangeRepresentation(arg.upper, typer_->int32x4_, zone())); +} + + Bounds Typer::Visitor::TypeChangeFloat64x2ToTagged(Node* node) { Bounds arg = Operand(node, 0); return Bounds(ChangeRepresentation(arg.lower, Type::Tagged(), zone()), @@ -2209,6 +2262,17 @@ Bounds Typer::Visitor::TypeCheckedStore(Node* node) { V(typer_->float32x4_, Type::Untagged(), Float32x4WithW) \ V(typer_->float32x4_, Type::Untagged(), Float32x4Clamp) \ V(typer_->float32x4_, Type::Untagged(), Float32x4Swizzle) \ + V(typer_->int32x4_, Type::Untagged(), Int32x4Add) \ + V(typer_->int32x4_, Type::Untagged(), Int32x4Sub) \ + V(typer_->int32x4_, Type::Untagged(), Int32x4Mul) \ + V(typer_->int32x4_, Type::Untagged(), Int32x4And) \ + V(typer_->int32x4_, Type::Untagged(), Int32x4Or) \ + V(typer_->int32x4_, Type::Untagged(), Int32x4Xor) \ + V(typer_->int32x4_, Type::Untagged(), Int32x4Constructor) \ + V(typer_->int32x4_, Type::UntaggedSigned32(), Int32x4GetX) \ + V(typer_->int32x4_, Type::UntaggedSigned32(), Int32x4GetY) \ + V(typer_->int32x4_, Type::UntaggedSigned32(), Int32x4GetZ) \ + V(typer_->int32x4_, Type::UntaggedSigned32(), Int32x4GetW) \ V(Type::Number(), Type::UntaggedFloat32(), Float32x4GetX) \ V(Type::Number(), Type::UntaggedFloat32(), Float32x4GetY) \ V(Type::Number(), Type::UntaggedFloat32(), Float32x4GetZ) \ @@ -2312,6 +2376,17 @@ Type* Typer::Visitor::TypeConstant(Handle value) { case kGetFloat32x4XYZ: case kGetFloat32x4XYZW: return typer_->cache_->Get(kFloat32x4FuncA); + // Int32x4 + case kInt32x4Add: + case kInt32x4And: + case kInt32x4Sub: + case kInt32x4Mul: + case kInt32x4Or: + case kInt32x4Xor: + return typer_->cache_->Get(kInt32x4Func2); + case kInt32x4Constructor: + return typer_->cache_->Get(kInt32x4Func4i); + // Float64x2 case kFloat64x2Add: case kFloat64x2Sub: case kFloat64x2Mul: @@ -2370,6 +2445,8 @@ Type* Typer::Visitor::TypeConstant(Handle value) { } } else if (value->IsFloat32x4()) { return typer_->cache_->Get(kFloat32x4Tagged); + } else if (value->IsInt32x4()) { + return typer_->cache_->Get(kInt32x4Tagged); } else if (value->IsFloat64x2()) { return typer_->cache_->Get(kFloat64x2Tagged); } diff --git a/src/compiler/typer.h b/src/compiler/typer.h index 407be4d512c..bfa8f8b3365 100644 --- a/src/compiler/typer.h +++ b/src/compiler/typer.h @@ -63,6 +63,7 @@ class Typer { Type* weakint_fun1_; Type* random_fun_; Type* float32x4_; + Type* int32x4_; Type* float64x2_; LazyTypeCache* cache_; diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index e01c4e2d4e8..a475c5c2652 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -417,6 +417,7 @@ void Verifier::Visitor::Pre(Node* node) { break; case IrOpcode::kJSToObject: case IrOpcode::kJSToFloat32x4Obj: + case IrOpcode::kJSToInt32x4Obj: case IrOpcode::kJSToFloat64x2Obj: // Type is Receiver. CheckUpperIs(node, Type::Receiver()); @@ -762,6 +763,21 @@ void Verifier::Visitor::Pre(Node* node) { case IrOpcode::kFloat32x4WithW: case IrOpcode::kFloat32x4Clamp: case IrOpcode::kFloat32x4Swizzle: + // Int32x4 + case IrOpcode::kInt32x4Add: + case IrOpcode::kInt32x4And: + case IrOpcode::kInt32x4Sub: + case IrOpcode::kInt32x4Mul: + case IrOpcode::kInt32x4Or: + case IrOpcode::kInt32x4Xor: + case IrOpcode::kInt32x4Constructor: + case IrOpcode::kChangeInt32x4ToTagged: + case IrOpcode::kChangeTaggedToInt32x4: + case IrOpcode::kInt32x4GetX: + case IrOpcode::kInt32x4GetY: + case IrOpcode::kInt32x4GetZ: + case IrOpcode::kInt32x4GetW: + // Float64x2 case IrOpcode::kFloat64x2Add: case IrOpcode::kFloat64x2Sub: case IrOpcode::kFloat64x2Mul: diff --git a/src/compiler/x64/code-generator-x64.cc b/src/compiler/x64/code-generator-x64.cc index 505e48e4248..55547c8ba1d 100644 --- a/src/compiler/x64/code-generator-x64.cc +++ b/src/compiler/x64/code-generator-x64.cc @@ -937,6 +937,76 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { __ shufps(value_reg, value_reg, s); break; } + // For Int32x4 operation. + case kInt32x4And: + ASSEMBLE_SIMD_BINOP_NOAVX(andps, Int32x4); + break; + case kInt32x4Or: + ASSEMBLE_SIMD_BINOP_NOAVX(orps, Int32x4); + break; + case kInt32x4Xor: + ASSEMBLE_SIMD_BINOP_NOAVX(xorps, Int32x4); + break; + case kInt32x4Sub: + ASSEMBLE_SIMD_BINOP_NOAVX(psubd, Int32x4); + break; + case kInt32x4Add: + ASSEMBLE_SIMD_BINOP_NOAVX(paddd, Int32x4); + break; + case kInt32x4Mul: { + DCHECK(i.InputInt32x4Register(0).is(i.OutputInt32x4Register())); + XMMRegister left_reg = i.InputInt32x4Register(0); + XMMRegister right_reg = i.InputInt32x4Register(1); + if (CpuFeatures::IsSupported(SSE4_1)) { + CpuFeatureScope scope(masm(), SSE4_1); + __ pmulld(left_reg, right_reg); + } else { + // The algorithm is from http://stackoverflow.com/questions/10500766/sse-multiplication-of-4-32-bit-integers + XMMRegister xmm_scratch = xmm0; + __ movaps(xmm_scratch, left_reg); + __ pmuludq(left_reg, right_reg); + __ psrldq(xmm_scratch, 4); + __ psrldq(right_reg, 4); + __ pmuludq(xmm_scratch, right_reg); + __ pshufd(left_reg, left_reg, 8); + __ pshufd(xmm_scratch, xmm_scratch, 8); + __ punpackldq(left_reg, xmm_scratch); + } + break; + } + case kInt32x4Constructor: + __ leaq(rsp, Operand(rsp, -kInt32x4Size)); + __ movl(Operand(rsp, 0 * kIntSize), i.InputRegister(0)); + __ movl(Operand(rsp, 1 * kIntSize), i.InputRegister(1)); + __ movl(Operand(rsp, 2 * kIntSize), i.InputRegister(2)); + __ movl(Operand(rsp, 3 * kIntSize), i.InputRegister(3)); + __ movups(i.OutputInt32x4Register(), Operand(rsp, 0 * kIntSize)); + __ leaq(rsp, Operand(rsp, kInt32x4Size)); + break; + case kInt32x4GetW: + select++; + case kInt32x4GetZ: + select++; + case kInt32x4GetY: + select++; + case kInt32x4GetX: { + Register dst = i.OutputRegister(); + XMMRegister input = i.InputInt32x4Register(0); + if (select == 0x0) { + __ movd(dst, input); + } else { + if (CpuFeatures::IsSupported(SSE4_1)) { + CpuFeatureScope scope(masm(), SSE4_1); + __ extractps(dst, input, select); + } else { + XMMRegister xmm_scratch = xmm0; + __ pshufd(xmm_scratch, input, select); + __ movd(dst, xmm_scratch); + } + } + break; + } + // Int32x4 Operation end. case kLoadSIMD128: { int index = 0; auto result = i.OutputSIMD128Register(); diff --git a/src/compiler/x64/instruction-selector-x64.cc b/src/compiler/x64/instruction-selector-x64.cc index 134966d6f9b..5939358c910 100644 --- a/src/compiler/x64/instruction-selector-x64.cc +++ b/src/compiler/x64/instruction-selector-x64.cc @@ -133,6 +133,7 @@ void InstructionSelector::VisitLoad(Node* node) { opcode = kX64Movq; break; case kRepFloat32x4: + case kRepInt32x4: case kRepFloat64x2: opcode = kLoadSIMD128; loaded_bytes = node->InputAt(2); @@ -202,6 +203,7 @@ void InstructionSelector::VisitStore(Node* node) { opcode = kX64Movq; break; case kRepFloat32x4: + case kRepInt32x4: case kRepFloat64x2: opcode = kStoreSIMD128; stored_bytes = node->InputAt(3); @@ -1377,6 +1379,11 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { V(Float32x4Div) \ V(Float32x4Min) \ V(Float32x4Max) \ + V(Int32x4Add) \ + V(Int32x4And) \ + V(Int32x4Sub) \ + V(Int32x4Or) \ + V(Int32x4Xor) \ V(Float64x2Add) \ V(Float64x2Sub) \ V(Float64x2Mul) \ @@ -1405,6 +1412,25 @@ void InstructionSelector::VisitFloat32x4Constructor(Node* node) { } +// TODO(chunyang): current code generation for int32x4 requires register for +// both input parameters. We can optimize it later. +void InstructionSelector::VisitInt32x4Mul(Node* node) { + X64OperandGenerator g(this); + InstructionOperand* output = IsSupported(AVX) ? g.DefineAsRegister(node) + : g.DefineSameAsFirst(node); + Emit(kInt32x4Mul, output, g.UseRegister(node->InputAt(0)), + g.UseRegister(node->InputAt(1))); +} + + +void InstructionSelector::VisitInt32x4Constructor(Node* node) { + X64OperandGenerator g(this); + Emit(kInt32x4Constructor, g.DefineAsRegister(node), + g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), + g.UseRegister(node->InputAt(2)), g.UseRegister(node->InputAt(3))); +} + + void InstructionSelector::VisitFloat64x2Constructor(Node* node) { X64OperandGenerator g(this); Emit(kFloat64x2Constructor, g.DefineAsRegister(node), @@ -1419,6 +1445,10 @@ void InstructionSelector::VisitFloat64x2Constructor(Node* node) { V(Float32x4GetW) \ V(Float32x4GetSignMask) \ V(Float32x4Splat) \ + V(Int32x4GetX) \ + V(Int32x4GetY) \ + V(Int32x4GetZ) \ + V(Int32x4GetW) \ V(Float64x2GetX) \ V(Float64x2GetY) \ V(Float64x2GetSignMask) diff --git a/src/factory.cc b/src/factory.cc index 1fd1667eb21..83653f68657 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1345,7 +1345,8 @@ Handle Factory::NewFunction(Handle name, Handle code, ElementsKind elements_kind = type == JS_ARRAY_TYPE ? FAST_SMI_ELEMENTS : FAST_HOLEY_SMI_ELEMENTS; Handle initial_map = NewMap(type, instance_size, elements_kind); - if (type == FLOAT32x4_TYPE || type == FLOAT64x2_TYPE) { + if (type == FLOAT32x4_TYPE || type == FLOAT64x2_TYPE || + type == INT32x4_TYPE) { initial_map->set_is_extensible(false); } if (!function->shared()->is_generator()) { diff --git a/src/interface-descriptors.h b/src/interface-descriptors.h index 3fe88eebdbb..c60c06f4f28 100644 --- a/src/interface-descriptors.h +++ b/src/interface-descriptors.h @@ -25,6 +25,7 @@ class PlatformInterfaceDescriptor; V(FastNewContext) \ V(ToNumber) \ V(ToFloat32x4) \ + V(ToInt32x4) \ V(ToFloat64x2) \ V(NumberToString) \ V(FastCloneShallowArray) \ @@ -37,6 +38,7 @@ class PlatformInterfaceDescriptor; V(TransitionElementsKind) \ V(AllocateHeapNumber) \ V(AllocateFloat32x4) \ + V(AllocateInt32x4) \ V(AllocateFloat64x2) \ V(ArrayConstructorConstantArgCount) \ V(ArrayConstructor) \ @@ -302,6 +304,12 @@ class ToFloat32x4Descriptor : public CallInterfaceDescriptor { }; +class ToInt32x4Descriptor : public CallInterfaceDescriptor { + public: + DECLARE_DESCRIPTOR(ToInt32x4Descriptor, CallInterfaceDescriptor) +}; + + class ToFloat64x2Descriptor : public CallInterfaceDescriptor { public: DECLARE_DESCRIPTOR(ToFloat64x2Descriptor, CallInterfaceDescriptor) @@ -375,6 +383,12 @@ class AllocateFloat32x4Descriptor : public CallInterfaceDescriptor { }; +class AllocateInt32x4Descriptor : public CallInterfaceDescriptor { + public: + DECLARE_DESCRIPTOR(AllocateInt32x4Descriptor, CallInterfaceDescriptor) +}; + + class AllocateFloat64x2Descriptor : public CallInterfaceDescriptor { public: DECLARE_DESCRIPTOR(AllocateFloat64x2Descriptor, CallInterfaceDescriptor) diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 9dd214c8421..60a44621db1 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -3181,6 +3181,20 @@ void ToFloat32x4Stub::Generate(MacroAssembler* masm) { } +void ToInt32x4Stub::Generate(MacroAssembler* masm) { + // The ToInt32x4Obj stub takes one argument in rax. + Label non_int32x4; + __ JumpIfSmi(rax, &non_int32x4, Label::kNear); + __ CmpObjectType(rax, INT32x4_TYPE, rdi); + __ j(not_equal, &non_int32x4, Label::kNear); + __ Ret(); + + __ bind(&non_int32x4); + __ TailCallRuntime(Runtime::kAllocateInt32x4, 0, 1); + __ Ret(); +} + + void ToFloat64x2Stub::Generate(MacroAssembler* masm) { // The ToFloat64x2Obj stub takes one argument in rax. Label non_float64x2; diff --git a/src/x64/interface-descriptors-x64.cc b/src/x64/interface-descriptors-x64.cc index 8ed316364c3..8be68f98257 100644 --- a/src/x64/interface-descriptors-x64.cc +++ b/src/x64/interface-descriptors-x64.cc @@ -81,6 +81,12 @@ void ToFloat32x4Descriptor::Initialize(CallInterfaceDescriptorData* data) { } +void ToInt32x4Descriptor::Initialize(CallInterfaceDescriptorData* data) { + Register registers[] = {rsi, rax}; + data->Initialize(arraysize(registers), registers, NULL); +} + + void ToFloat64x2Descriptor::Initialize(CallInterfaceDescriptorData* data) { Register registers[] = {rsi, rax}; data->Initialize(arraysize(registers), registers, NULL); @@ -185,6 +191,15 @@ void AllocateFloat32x4Descriptor::Initialize( } +void AllocateInt32x4Descriptor::Initialize( + CallInterfaceDescriptorData* data) { + // register state + // rsi -- context + Register registers[] = {rsi}; + data->Initialize(arraysize(registers), registers, nullptr); +} + + void AllocateFloat64x2Descriptor::Initialize( CallInterfaceDescriptorData* data) { // register state diff --git a/test/mjsunit/asm/int32x4.js b/test/mjsunit/asm/int32x4.js new file mode 100644 index 00000000000..a677b27d301 --- /dev/null +++ b/test/mjsunit/asm/int32x4.js @@ -0,0 +1,418 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Flags: --simd_object --allow-natives-syntax + +function asmModule(stdlib, imports, buffer) { + "use asm" + var i4 = stdlib.SIMD.int32x4; + var i4add = i4.add; + var i4and = i4.and; + var i4sub = i4.sub; + var i4mul = i4.mul; + var i4or = i4.or; + var i4xor = i4.xor; + + var a = i4(imports.a); + var b = i4(imports.b); + + function add(a, b) { + a = i4(a); + b = i4(b); + var ret = i4(); + ret = i4add(a, b); + return i4(ret); + } + + function addLocal() { + var a = i4(+1, +2, +3, +4); + var b = i4(+5, +6, +7, +8); + var ret = i4(); + ret = i4add(a, b); + return i4(ret); + } + + function addImports() { + var ret = i4(); + ret = i4add(a, b); + return i4(ret); + } + + function sub(a, b) { + a = i4(a); + b = i4(b); + var ret = i4(); + ret = i4sub(a, b); + return i4(ret); + } + + function subLocal() { + var a = i4(+1, +2, +3, +4); + var b = i4(+5, +6, +7, +8); + var ret = i4(); + ret = i4sub(a, b); + return i4(ret); + } + + function subImports() { + var ret = i4(); + ret = i4sub(a, b); + return i4(ret); + } + + function mul(a, b) { + a = i4(a); + b = i4(b); + var ret = i4(); + ret = i4mul(a, b); + return i4(ret); + } + + function mulLocal() { + var a = i4(+1, +2, +3, +4); + var b = i4(+5, +6, +7, +8); + var ret = i4(); + ret = i4mul(a, b); + return i4(ret); + } + + function mulImports() { + var ret = i4(); + ret = i4mul(a, b); + return i4(ret); + } + + function and(a, b) { + a = i4(a); + b = i4(b); + var ret = i4(); + ret = i4and(a, b); + return i4(ret); + } + + function andLocal() { + var a = i4(+1, +2, +3, +4); + var b = i4(+5, +6, +7, +8); + var ret = i4(); + ret = i4and(a, b); + return i4(ret); + } + + function andImports() { + var ret = i4(); + ret = i4and(a, b); + return i4(ret); + } + + function or(a, b) { + a = i4(a); + b = i4(b); + var ret = i4(); + ret = i4or(a, b); + return i4(ret); + } + + function orLocal() { + var a = i4(+1, +2, +3, +4); + var b = i4(+5, +6, +7, +8); + var ret = i4(); + ret = i4or(a, b); + return i4(ret); + } + + function orImports() { + var ret = i4(); + ret = i4or(a, b); + return i4(ret); + } + + function xor(a, b) { + a = i4(a); + b = i4(b); + var ret = i4(); + ret = i4xor(a, b); + return i4(ret); + } + + function xorLocal() { + var a = i4(+1, +2, +3, +4); + var b = i4(+5, +6, +7, +8); + var ret = i4(); + ret = i4xor(a, b); + return i4(ret); + } + + function xorImports() { + var ret = i4(); + ret = i4xor(a, b); + return i4(ret); + } + + function getx(a) { + a = i4(a); + var x = a.x; + return x | 0; + } + + function gety(a) { + a = i4(a); + var y = a.y; + return y | 0; + } + + function getz(a) { + a = i4(a); + var z = a.z; + return z | 0; + } + + function getw(a) { + a = i4(a); + var w = a.w; + return w | 0; + } + + function getxLocal() { + var a = i4(+1, +2, +3, +4); + var x = a.x; + return x | 0; + } + + function getyLocal() { + var a = i4(+1, +2, +3, +4); + var y = a.y; + return y | 0; + } + + function getzLocal() { + var a = i4(+1, +2, +3, +4); + var z = a.z; + return z | 0; + } + + function getwLocal() { + var a = i4(+1, +2, +3, +4); + var w = a.w; + return w | 0; + } + + function getxImports() { + var x = a.x; + return x | 0; + } + + function getyImports() { + var y = a.y; + return y | 0; + } + + function getzImports() { + var z = a.z; + return z | 0; + } + + function getwImports() { + var w = a.w; + return w | 0; + } + + return {add : add, addLocal : addLocal, addImports : addImports, + sub : sub, subLocal : subLocal, subImports : subImports, + mul : mul, mulLocal : mulLocal, mulImports : mulImports, + and : and, andLocal : andLocal, andImports : andImports, + or : or, orLocal : orLocal, orImports : orImports, + xor : xor, xorLocal : xorLocal, xorImports : xorImports, + getx : getx, getxLocal : getxLocal, getxImports : getxImports, + gety : gety, getyLocal : getyLocal, getyImports : getyImports, + getz : getz, getzLocal : getzLocal, getzImports : getzImports, + getw : getw, getwLocal : getwLocal, getwImports : getwImports} +} + + +var a = SIMD.int32x4(+1, +2, +3, +4); +var b = SIMD.int32x4(+5, +6, +7, +8); +var m = asmModule(this, {a : a, b : b}); +// and +var result = m.add(a, b); +var expected = SIMD.int32x4.add(a, b); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +var result = m.addLocal(); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +var result = m.addImports(); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +// sub +var result = m.sub(a, b); +var expected = SIMD.int32x4.sub(a, b); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +var result = m.subLocal(); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +var result = m.subImports(); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +// mul +var result = m.mul(a, b); +var expected = SIMD.int32x4.mul(a, b); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +var result = m.mulLocal(); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +var result = m.mulImports(); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +// and +var result = m.and(a, b); +var expected = SIMD.int32x4.and(a, b); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +var result = m.andLocal(); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +var result = m.andImports(); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +// or +var result = m.or(a, b); +var expected = SIMD.int32x4.or(a, b); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +var result = m.orLocal(); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +var result = m.orImports(); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +// xor +var result = m.xor(a, b); +var expected = SIMD.int32x4.xor(a, b); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +var result = m.xorLocal(); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + +var result = m.xorImports(); +assertEquals(result.x, expected.x); +assertEquals(result.y, expected.y); +assertEquals(result.z, expected.z); +assertEquals(result.w, expected.w); + + +var result = m.getx(a); +var expected = a.x; +assertEquals(result, expected); + +var result = m.getxLocal(); +assertEquals(result, expected); + +var result = m.getxImports(); +assertEquals(result, expected); + +var result = m.gety(a); +var expected = a.y; +assertEquals(result, expected); + +var result = m.getyLocal(); +assertEquals(result, expected); + +var result = m.getyImports(); +assertEquals(result, expected); + +var result = m.getz(a); +var expected = a.z; +assertEquals(result, expected); + +var result = m.getzLocal(); +assertEquals(result, expected); + +var result = m.getzImports(); +assertEquals(result, expected); + +var result = m.getw(a); +var expected = a.w; +assertEquals(result, expected); + +var result = m.getwLocal(); +assertEquals(result, expected); + +var result = m.getwImports(); +assertEquals(result, expected);