diff --git a/include/v8.h b/include/v8.h index 4bb3ad97c7b..10613ad0bb9 100644 --- a/include/v8.h +++ b/include/v8.h @@ -1497,6 +1497,18 @@ class V8_EXPORT Value : public Data { */ bool IsFloat32Array() const; + /** + * Returns true if this value is a Float32x4Array. + * This is an experimental feature. + */ + bool IsFloat32x4Array() const; + + /** + * Returns true if this value is a Int32x4Array. + * This is an experimental feature. + */ + bool IsInt32x4Array() const; + /** * Returns true if this value is a Float64Array. * This is an experimental feature. @@ -2005,8 +2017,10 @@ enum ExternalArrayType { kExternalInt16Array, kExternalUint16Array, kExternalInt32Array, + kExternalInt32x4Array, kExternalUint32Array, kExternalFloat32Array, + kExternalFloat32x4Array, kExternalFloat64Array, kExternalUint8ClampedArray, @@ -2850,6 +2864,30 @@ class V8_EXPORT Float32Array : public TypedArray { }; +class V8_EXPORT Float32x4Array : public TypedArray { + public: + static Local New(Handle array_buffer, + size_t byte_offset, size_t length); + V8_INLINE static Float32x4Array* Cast(Value* obj); + + private: + Float32x4Array(); + static void CheckCast(Value* obj); +}; + + +class V8_EXPORT Int32x4Array : public TypedArray { + public: + static Local New(Handle array_buffer, + size_t byte_offset, size_t length); + V8_INLINE static Int32x4Array* Cast(Value* obj); + + private: + Int32x4Array(); + static void CheckCast(Value* obj); +}; + + /** * An instance of Float64Array constructor (ES6 draft 15.13.6). * This API is experimental and may change significantly. @@ -5386,7 +5424,7 @@ class Internals { static const int kJSObjectHeaderSize = 3 * kApiPointerSize; static const int kFixedArrayHeaderSize = 2 * kApiPointerSize; static const int kContextHeaderSize = 2 * kApiPointerSize; - static const int kContextEmbedderDataIndex = 65; + static const int kContextEmbedderDataIndex = 72; static const int kFullStringRepresentationMask = 0x07; static const int kStringEncodingMask = 0x4; static const int kExternalTwoByteRepresentationTag = 0x02; @@ -5398,7 +5436,7 @@ class Internals { static const int kNullValueRootIndex = 7; static const int kTrueValueRootIndex = 8; static const int kFalseValueRootIndex = 9; - static const int kEmptyStringRootIndex = 145; + static const int kEmptyStringRootIndex = 153; static const int kNodeClassIdOffset = 1 * kApiPointerSize; static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3; @@ -5409,10 +5447,10 @@ class Internals { static const int kNodeIsIndependentShift = 4; static const int kNodeIsPartiallyDependentShift = 5; - static const int kJSObjectType = 0xbb; + static const int kJSObjectType = 0xc1; static const int kFirstNonstringType = 0x80; static const int kOddballType = 0x83; - static const int kForeignType = 0x87; + static const int kForeignType = 0x89; static const int kUndefinedOddballKind = 5; static const int kNullOddballKind = 3; @@ -6251,6 +6289,22 @@ Float32Array* Float32Array::Cast(v8::Value* value) { } +Float32x4Array* Float32x4Array::Cast(v8::Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast(value); +} + + +Int32x4Array* Int32x4Array::Cast(v8::Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast(value); +} + + Float64Array* Float64Array::Cast(v8::Value* value) { #ifdef V8_ENABLE_CHECKS CheckCast(value); diff --git a/src/api.h b/src/api.h index 9fc99d9d2a0..8324cc28056 100644 --- a/src/api.h +++ b/src/api.h @@ -179,6 +179,8 @@ class RegisteredExtension { V(Uint32Array, JSTypedArray) \ V(Int32Array, JSTypedArray) \ V(Float32Array, JSTypedArray) \ + V(Float32x4Array, JSTypedArray) \ + V(Int32x4Array, JSTypedArray) \ V(Float64Array, JSTypedArray) \ V(DataView, JSDataView) \ V(String, String) \ @@ -246,6 +248,10 @@ class Utils { v8::internal::Handle obj); static inline Local ToLocalFloat32Array( v8::internal::Handle obj); + static inline Local ToLocalFloat32x4Array( + v8::internal::Handle obj); + static inline Local ToLocalInt32x4Array( + v8::internal::Handle obj); static inline Local ToLocalFloat64Array( v8::internal::Handle obj); diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 2c9b2756ed6..2b3d049ec00 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -4515,6 +4515,14 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); __ cmp(r0, ip); Split(eq, if_true, if_false, fall_through); + } else if (check->Equals(isolate()->heap()->float32x4_string())) { + __ JumpIfSmi(r0, if_false); + __ CompareObjectType(r0, r0, r1, FLOAT32x4_TYPE); + Split(eq, if_true, if_false, fall_through); + } else if (check->Equals(isolate()->heap()->int32x4_string())) { + __ JumpIfSmi(r0, if_false); + __ CompareObjectType(r0, r0, r1, INT32x4_TYPE); + Split(eq, if_true, if_false, fall_through); } else if (check->Equals(isolate()->heap()->string_string())) { __ JumpIfSmi(r0, if_false); // Check for undetectable objects => false. diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index c12e9b80833..cb12d17eff6 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -2079,7 +2079,10 @@ LInstruction* LChunkBuilder::DoLoadExternalArrayPointer( LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { ASSERT(instr->key()->representation().IsSmiOrInteger32()); ElementsKind elements_kind = instr->elements_kind(); - LOperand* key = UseRegisterOrConstantAtStart(instr->key()); + bool load_128bits_without_neon = IsSIMD128ElementsKind(elements_kind); + LOperand* key = load_128bits_without_neon + ? UseRegisterOrConstant(instr->key()) + : UseRegisterOrConstantAtStart(instr->key()); LLoadKeyed* result = NULL; if (!instr->is_typed_elements()) { @@ -2090,15 +2093,24 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { ASSERT(instr->representation().IsSmiOrTagged()); obj = UseRegisterAtStart(instr->elements()); } - result = new(zone()) LLoadKeyed(obj, key); + result = new(zone()) LLoadKeyed(obj, key, NULL, NULL); } else { ASSERT( (instr->representation().IsInteger32() && !IsDoubleOrFloatElementsKind(instr->elements_kind())) || (instr->representation().IsDouble() && - IsDoubleOrFloatElementsKind(instr->elements_kind()))); + IsDoubleOrFloatElementsKind(instr->elements_kind())) || + (instr->representation().IsTagged() && + (IsSIMD128ElementsKind(instr->elements_kind())))); LOperand* backing_store = UseRegister(instr->elements()); - result = new(zone()) LLoadKeyed(backing_store, key); + result = load_128bits_without_neon + ? new(zone()) LLoadKeyed(backing_store, key, + TempRegister(), TempRegister()) + : new(zone()) LLoadKeyed(backing_store, key, NULL, NULL); + if (load_128bits_without_neon) { + info()->MarkAsDeferredCalling(); + AssignPointerMap(result); + } } DefineAsRegister(result); @@ -2147,14 +2159,16 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { } } - return new(zone()) LStoreKeyed(object, key, val); + return new(zone()) LStoreKeyed(object, key, val, NULL); } ASSERT( (instr->value()->representation().IsInteger32() && !IsDoubleOrFloatElementsKind(instr->elements_kind())) || (instr->value()->representation().IsDouble() && - IsDoubleOrFloatElementsKind(instr->elements_kind()))); + IsDoubleOrFloatElementsKind(instr->elements_kind())) || + (instr->value()->representation().IsTagged() && + IsSIMD128ElementsKind(instr->elements_kind()))); ASSERT((instr->is_fixed_typed_array() && instr->elements()->representation().IsTagged()) || (instr->is_external() && @@ -2162,7 +2176,12 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { LOperand* val = UseRegister(instr->value()); LOperand* key = UseRegisterOrConstantAtStart(instr->key()); LOperand* backing_store = UseRegister(instr->elements()); - return new(zone()) LStoreKeyed(backing_store, key, val); + bool store_128bits_without_neon = + IsSIMD128ElementsKind(instr->elements_kind()); + LStoreKeyed* result = + new(zone()) LStoreKeyed(backing_store, key, val, + store_128bits_without_neon ? TempRegister() : NULL); + return store_128bits_without_neon ? AssignEnvironment(result) : result; } diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index cee6b858b0b..72ad246a0b2 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -1581,15 +1581,20 @@ class LLoadExternalArrayPointer V8_FINAL }; -class LLoadKeyed V8_FINAL : public LTemplateInstruction<1, 2, 0> { +class LLoadKeyed V8_FINAL : public LTemplateInstruction<1, 2, 2> { public: - LLoadKeyed(LOperand* elements, LOperand* key) { + LLoadKeyed(LOperand* elements, LOperand* key, + LOperand* temp, LOperand* temp2) { inputs_[0] = elements; inputs_[1] = key; + temps_[0] = temp; + temps_[1] = temp2; } LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } ElementsKind elements_kind() const { return hydrogen()->elements_kind(); } @@ -2203,12 +2208,14 @@ class LStoreNamedGeneric V8_FINAL : public LTemplateInstruction<0, 3, 0> { }; -class LStoreKeyed V8_FINAL : public LTemplateInstruction<0, 3, 0> { +class LStoreKeyed V8_FINAL : public LTemplateInstruction<0, 3, 1> { public: - LStoreKeyed(LOperand* object, LOperand* key, LOperand* value) { + LStoreKeyed(LOperand* object, LOperand* key, LOperand* value, + LOperand* temp) { inputs_[0] = object; inputs_[1] = key; inputs_[2] = value; + temps_[0] = temp; } bool is_external() const { return hydrogen()->is_external(); } @@ -2221,6 +2228,7 @@ class LStoreKeyed V8_FINAL : public LTemplateInstruction<0, 3, 0> { LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } + LOperand* temp() { return temps_[0]; } ElementsKind elements_kind() const { return hydrogen()->elements_kind(); } diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 062c7d18328..0b027ecdcf0 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -3192,6 +3192,95 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { } +void LCodeGen::DoDeferredSIMD128ToTagged(LInstruction* instr, + Runtime::FunctionId id) { + // TODO(3095996): Get rid of this. For now, we need to make the + // result register contain a valid pointer because it is already + // contained in the register pointer map. + Register reg = ToRegister(instr->result()); + __ mov(reg, Operand::Zero()); + + PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); + __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + __ CallRuntimeSaveDoubles(id); + RecordSafepointWithRegisters( + instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); + __ sub(r0, r0, Operand(kHeapObjectTag)); + __ StoreToSafepointRegisterSlot(r0, reg); +} + + +template +void LCodeGen::DoLoadKeyedSIMD128ExternalArray(LLoadKeyed* instr) { + class DeferredSIMD128ToTagged V8_FINAL : public LDeferredCode { + public: + DeferredSIMD128ToTagged(LCodeGen* codegen, LInstruction* instr, + Runtime::FunctionId id) + : LDeferredCode(codegen), instr_(instr), id_(id) { } + virtual void Generate() V8_OVERRIDE { + codegen()->DoDeferredSIMD128ToTagged(instr_, id_); + } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } + private: + LInstruction* instr_; + Runtime::FunctionId id_; + }; + + // Allocate a SIMD128 object on the heap. + Register reg = ToRegister(instr->result()); + Register temp = ToRegister(instr->temp()); + Register temp2 = ToRegister(instr->temp2()); + Register scratch = scratch0(); + + DeferredSIMD128ToTagged* deferred = new(zone()) DeferredSIMD128ToTagged( + this, instr, static_cast(T::kRuntimeAllocatorId())); + if (FLAG_inline_new) { + __ LoadRoot(scratch, static_cast(T::kMapRootIndex())); + __ AllocateSIMDHeapObject(T::kSize, reg, temp, temp2, scratch, + deferred->entry(), DONT_TAG_RESULT); + } else { + __ jmp(deferred->entry()); + } + __ bind(deferred->exit()); + + // Copy the SIMD128 value from the external array to the heap object. + STATIC_ASSERT(T::kValueSize % kPointerSize == 0); + Register external_pointer = ToRegister(instr->elements()); + Register key = no_reg; + ElementsKind elements_kind = instr->elements_kind(); + bool key_is_constant = instr->key()->IsConstantOperand(); + int constant_key = 0; + if (key_is_constant) { + constant_key = ToInteger32(LConstantOperand::cast(instr->key())); + if (constant_key & 0xF0000000) { + Abort(kArrayIndexConstantValueTooBig); + } + } else { + key = ToRegister(instr->key()); + } + int element_size_shift = ElementsKindToShiftSize(elements_kind); + int shift_size = (instr->hydrogen()->key()->representation().IsSmi()) + ? (element_size_shift - kSmiTagSize) : element_size_shift; + int additional_offset = IsFixedTypedArrayElementsKind(elements_kind) + ? FixedTypedArrayBase::kDataOffset - kHeapObjectTag + : 0; + int base_offset = + (instr->additional_index() << element_size_shift) + additional_offset; + Operand operand = key_is_constant + ? Operand(constant_key << element_size_shift) + : Operand(key, LSL, shift_size); + + __ add(scratch, external_pointer, operand); + for (int offset = 0; offset < T::kValueSize; offset += kPointerSize) { + __ ldr(temp, MemOperand(scratch, base_offset + offset)); + __ str(temp, MemOperand(reg, T::kValueOffset + offset)); + } + + // Now that we have finished with the object's real address tag it + __ add(reg, reg, Operand(kHeapObjectTag)); +} + + void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { Register external_pointer = ToRegister(instr->elements()); Register key = no_reg; @@ -3232,6 +3321,10 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { } else { // loading doubles, not floats. __ vldr(result, scratch0(), base_offset); } + } else if (IsFloat32x4ElementsKind(elements_kind)) { + DoLoadKeyedSIMD128ExternalArray(instr); + } else if (IsInt32x4ElementsKind(elements_kind)) { + DoLoadKeyedSIMD128ExternalArray(instr); } else { Register result = ToRegister(instr->result()); MemOperand mem_operand = PrepareKeyedOperand( @@ -3273,6 +3366,10 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { case FLOAT64_ELEMENTS: case EXTERNAL_FLOAT32_ELEMENTS: case EXTERNAL_FLOAT64_ELEMENTS: + case FLOAT32x4_ELEMENTS: + case INT32x4_ELEMENTS: + case EXTERNAL_FLOAT32x4_ELEMENTS: + case EXTERNAL_INT32x4_ELEMENTS: case FAST_HOLEY_DOUBLE_ELEMENTS: case FAST_HOLEY_ELEMENTS: case FAST_HOLEY_SMI_ELEMENTS: @@ -4255,6 +4352,59 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { } +template +void LCodeGen::DoStoreKeyedSIMD128ExternalArray(LStoreKeyed* instr) { + ASSERT(instr->value()->IsRegister()); + Register temp = ToRegister(instr->temp()); + Register input_reg = ToRegister(instr->value()); + __ SmiTst(input_reg); + DeoptimizeIf(eq, instr->environment()); + __ CompareObjectType(input_reg, temp, no_reg, T::kInstanceType); + DeoptimizeIf(ne, instr->environment()); + + STATIC_ASSERT(T::kValueSize % kPointerSize == 0); + Register external_pointer = ToRegister(instr->elements()); + Register key = no_reg; + ElementsKind elements_kind = instr->elements_kind(); + bool key_is_constant = instr->key()->IsConstantOperand(); + int constant_key = 0; + if (key_is_constant) { + constant_key = ToInteger32(LConstantOperand::cast(instr->key())); + if (constant_key & 0xF0000000) { + Abort(kArrayIndexConstantValueTooBig); + } + } else { + key = ToRegister(instr->key()); + } + int element_size_shift = ElementsKindToShiftSize(elements_kind); + int shift_size = (instr->hydrogen()->key()->representation().IsSmi()) + ? (element_size_shift - kSmiTagSize) : element_size_shift; + int additional_offset = IsFixedTypedArrayElementsKind(elements_kind) + ? FixedTypedArrayBase::kDataOffset - kHeapObjectTag + : 0; + + int base_offset = + (instr->additional_index() << element_size_shift) + additional_offset; + Register address = scratch0(); + if (key_is_constant) { + if (constant_key != 0) { + __ add(address, external_pointer, + Operand(constant_key << element_size_shift)); + } else { + address = external_pointer; + } + } else { + __ add(address, external_pointer, Operand(key, LSL, shift_size)); + } + + for (int offset = 0; offset < T::kValueSize; offset += kPointerSize) { + __ ldr(temp, MemOperand(input_reg, + T::kValueOffset - kHeapObjectTag + offset)); + __ str(temp, MemOperand(address, base_offset + offset)); + } +} + + void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { Register external_pointer = ToRegister(instr->elements()); Register key = no_reg; @@ -4301,6 +4451,10 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { } else { // Storing doubles, not floats. __ vstr(value, address, base_offset); } + } else if (IsFloat32x4ElementsKind(elements_kind)) { + DoStoreKeyedSIMD128ExternalArray(instr); + } else if (IsInt32x4ElementsKind(elements_kind)) { + DoStoreKeyedSIMD128ExternalArray(instr); } else { Register value(ToRegister(instr->value())); MemOperand mem_operand = PrepareKeyedOperand( @@ -4332,6 +4486,10 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { case FLOAT64_ELEMENTS: case EXTERNAL_FLOAT32_ELEMENTS: case EXTERNAL_FLOAT64_ELEMENTS: + case FLOAT32x4_ELEMENTS: + case INT32x4_ELEMENTS: + case EXTERNAL_FLOAT32x4_ELEMENTS: + case EXTERNAL_INT32x4_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case FAST_ELEMENTS: case FAST_SMI_ELEMENTS: @@ -5512,6 +5670,16 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, __ CompareRoot(scratch, Heap::kHeapNumberMapRootIndex); final_branch_condition = eq; + } else if (type_name->Equals(heap()->float32x4_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, scratch, no_reg, FLOAT32x4_TYPE); + final_branch_condition = eq; + + } else if (type_name->Equals(heap()->int32x4_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, scratch, no_reg, INT32x4_TYPE); + final_branch_condition = eq; + } else if (type_name->Equals(heap()->string_string())) { __ JumpIfSmi(input, false_label); __ CompareObjectType(input, scratch, no_reg, FIRST_NONSTRING_TYPE); diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h index 5251b85fa91..3d2ebc567df 100644 --- a/src/arm/lithium-codegen-arm.h +++ b/src/arm/lithium-codegen-arm.h @@ -139,6 +139,7 @@ class LCodeGen: public LCodeGenBase { void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, Label* map_check); void DoDeferredInstanceMigration(LCheckMaps* instr, Register object); + void DoDeferredSIMD128ToTagged(LInstruction* instr, Runtime::FunctionId id); // Parallel move support. void DoParallelMove(LParallelMove* move); @@ -360,9 +361,13 @@ class LCodeGen: public LCodeGenBase { void EnsureSpaceForLazyDeopt(int space_needed) V8_OVERRIDE; void DoLoadKeyedExternalArray(LLoadKeyed* instr); + template + void DoLoadKeyedSIMD128ExternalArray(LLoadKeyed* instr); void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); void DoLoadKeyedFixedArray(LLoadKeyed* instr); void DoStoreKeyedExternalArray(LStoreKeyed* instr); + template + void DoStoreKeyedSIMD128ExternalArray(LStoreKeyed* instr); void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); void DoStoreKeyedFixedArray(LStoreKeyed* instr); diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index b8b39c94445..e9613938526 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -3258,6 +3258,26 @@ void MacroAssembler::AllocateHeapNumberWithValue(Register result, } +// Allocates a simd128 object or jumps to the need_gc label if the young space +// is full and a scavenge is needed. +void MacroAssembler::AllocateSIMDHeapObject(int size, + Register result, + Register scratch1, + Register scratch2, + Register map, + Label* gc_required, + TaggingMode tagging_mode) { + Allocate(size, result, scratch1, scratch2, gc_required, + tagging_mode == TAG_RESULT ? TAG_OBJECT : NO_ALLOCATION_FLAGS); + + if (tagging_mode == TAG_RESULT) { + str(map, FieldMemOperand(result, HeapObject::kMapOffset)); + } else { + str(map, MemOperand(result, HeapObject::kMapOffset)); + } +} + + // Copies a fixed number of fields of heap objects from src to dst. void MacroAssembler::CopyFields(Register dst, Register src, diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 9d4c128b927..937bedbf68e 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -802,6 +802,13 @@ class MacroAssembler: public Assembler { Register scratch2, Register heap_number_map, Label* gc_required); + void AllocateSIMDHeapObject(int size, + Register result, + Register scratch1, + Register scratch2, + Register map, + Label* gc_required, + TaggingMode tagging_mode = TAG_RESULT); // Copies a fixed number of fields of heap objects from src to dst. void CopyFields(Register dst, diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 987437bbd7b..581d87fad77 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -1741,6 +1741,24 @@ Register CallStubCompiler::HandlerFrontendHeader(Handle object, masm(), Context::NUMBER_FUNCTION_INDEX, r1, miss); break; } + case FLOAT32x4_CHECK: { + // Check that the object is a float32x4. + __ CompareObjectType(reg, r3, r3, FLOAT32x4_TYPE); + __ b(ne, miss); + // Check that the maps starting from the prototype haven't changed. + GenerateDirectLoadGlobalFunctionPrototype( + masm(), Context::FLOAT32x4_FUNCTION_INDEX, r1, miss); + break; + } + case INT32x4_CHECK: { + // Check that the object is a int32x4. + __ CompareObjectType(reg, r3, r3, INT32x4_TYPE); + __ b(ne, miss); + // Check that the maps starting from the prototype haven't changed. + GenerateDirectLoadGlobalFunctionPrototype( + masm(), Context::INT32x4_FUNCTION_INDEX, r1, miss); + break; + } case BOOLEAN_CHECK: { GenerateBooleanCheck(reg, miss); diff --git a/src/ast.cc b/src/ast.cc index 9d8624ca1b1..5b0272f63b6 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -702,6 +702,12 @@ Handle Call::GetPrototypeForPrimitiveCheck( case NUMBER_CHECK: function = native_context->number_function(); break; + case FLOAT32x4_CHECK: + function = native_context->float32x4_function(); + break; + case INT32x4_CHECK: + function = native_context->int32x4_function(); + break; case BOOLEAN_CHECK: function = native_context->boolean_function(); break; diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 6952a55346f..072d310dc7c 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1444,6 +1444,46 @@ void Genesis::InitializeExperimentalGlobal() { generator_result_map->instance_size()); native_context()->set_generator_result_map(*generator_result_map); } + + if (FLAG_simd_object) { + // --- S I M D --- + Handle name = factory()->InternalizeUtf8String("SIMD"); + Handle cons = + factory()->NewFunction(name, factory()->the_hole_value()); + JSFunction::SetInstancePrototype(cons, + Handle(native_context()->initial_object_prototype(), + isolate())); + cons->SetInstanceClassName(*name); + Handle simd_object = factory()->NewJSObject(cons, TENURED); + ASSERT(simd_object->IsJSObject()); + CHECK_NOT_EMPTY_HANDLE(isolate(), + JSObject::SetLocalPropertyIgnoreAttributes( + global, name, simd_object, DONT_ENUM)); + native_context()->set_simd_object(*simd_object); + // --- f l o a t 3 2 x 4 --- + Handle float32x4_fun = + InstallFunction(simd_object, "float32x4", JS_VALUE_TYPE, JSValue::kSize, + isolate()->initial_object_prototype(), + Builtins::kIllegal, true, true); + native_context()->set_float32x4_function(*float32x4_fun); + + // --- i n t 3 2 x 4 --- + Handle int32x4_fun = + InstallFunction(simd_object, "int32x4", JS_VALUE_TYPE, JSValue::kSize, + isolate()->initial_object_prototype(), + Builtins::kIllegal, true, true); + native_context()->set_int32x4_function(*int32x4_fun); + + // --- F l o a t 3 2 x 4 A r r a y--- + Handle float32x4_array_fun = InstallTypedArray("Float32x4Array", + EXTERNAL_FLOAT32x4_ELEMENTS); + native_context()->set_float32x4_array_fun(*float32x4_array_fun); + + // --- I n t 3 2 x 4 A r r a y--- + Handle int32x4_array_fun = InstallTypedArray("Int32x4Array", + EXTERNAL_INT32x4_ELEMENTS); + native_context()->set_int32x4_array_fun(*int32x4_array_fun); + } } @@ -2054,6 +2094,21 @@ bool Genesis::InstallExperimentalNatives() { INSTALL_EXPERIMENTAL_NATIVE(i, strings, "harmony-string.js") INSTALL_EXPERIMENTAL_NATIVE(i, arrays, "harmony-array.js") INSTALL_EXPERIMENTAL_NATIVE(i, maths, "harmony-math.js") + if (FLAG_simd_object && + strcmp(ExperimentalNatives::GetScriptName(i).start(), + "native simd128.js") == 0) { + if (!CompileExperimentalBuiltin(isolate(), i)) return false; + // Store the map for the float32x4 and int32x4 function prototype after + // the float32x4 and int32x4 function has been set up. + JSObject* float32x4_function_prototype = JSObject::cast( + native_context()->float32x4_function()->instance_prototype()); + native_context()->set_float32x4_function_prototype_map( + float32x4_function_prototype->map()); + JSObject* int32x4_function_prototype = JSObject::cast( + native_context()->int32x4_function()->instance_prototype()); + native_context()->set_int32x4_function_prototype_map( + int32x4_function_prototype->map()); + } } InstallExperimentalNativeFunctions(); diff --git a/src/contexts.h b/src/contexts.h index bd6c6a2bbc1..6f819182cce 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -101,6 +101,12 @@ enum BindingFlags { V(SECURITY_TOKEN_INDEX, Object, security_token) \ V(BOOLEAN_FUNCTION_INDEX, JSFunction, boolean_function) \ V(NUMBER_FUNCTION_INDEX, JSFunction, number_function) \ + V(FLOAT32x4_FUNCTION_INDEX, JSFunction, float32x4_function) \ + V(FLOAT32x4_FUNCTION_PROTOTYPE_MAP_INDEX, Map, \ + float32x4_function_prototype_map) \ + V(INT32x4_FUNCTION_INDEX, JSFunction, int32x4_function) \ + V(INT32x4_FUNCTION_PROTOTYPE_MAP_INDEX, Map, \ + int32x4_function_prototype_map) \ V(STRING_FUNCTION_INDEX, JSFunction, string_function) \ V(STRING_FUNCTION_PROTOTYPE_MAP_INDEX, Map, string_function_prototype_map) \ V(SYMBOL_FUNCTION_INDEX, JSFunction, symbol_function) \ @@ -110,6 +116,7 @@ enum BindingFlags { V(JS_ARRAY_MAPS_INDEX, Object, js_array_maps) \ V(DATE_FUNCTION_INDEX, JSFunction, date_function) \ V(JSON_OBJECT_INDEX, JSObject, json_object) \ + V(SIMD_OBJECT_INDEX, JSObject, simd_object) \ V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \ V(INITIAL_OBJECT_PROTOTYPE_INDEX, JSObject, initial_object_prototype) \ V(INITIAL_ARRAY_PROTOTYPE_INDEX, JSObject, initial_array_prototype) \ @@ -133,6 +140,8 @@ enum BindingFlags { V(INT32_ARRAY_FUN_INDEX, JSFunction, int32_array_fun) \ V(FLOAT32_ARRAY_FUN_INDEX, JSFunction, float32_array_fun) \ V(FLOAT64_ARRAY_FUN_INDEX, JSFunction, float64_array_fun) \ + V(FLOAT32x4_ARRAY_FUN_INDEX, JSFunction, float32x4_array_fun) \ + V(INT32x4_ARRAY_FUN_INDEX, JSFunction, int32x4_array_fun) \ V(UINT8_CLAMPED_ARRAY_FUN_INDEX, JSFunction, uint8_clamped_array_fun) \ V(DATA_VIEW_FUN_INDEX, JSFunction, data_view_fun) \ V(FUNCTION_MAP_INDEX, Map, function_map) \ @@ -267,6 +276,10 @@ class Context: public FixedArray { INITIAL_ARRAY_PROTOTYPE_INDEX, BOOLEAN_FUNCTION_INDEX, NUMBER_FUNCTION_INDEX, + FLOAT32x4_FUNCTION_INDEX, + FLOAT32x4_FUNCTION_PROTOTYPE_MAP_INDEX, + INT32x4_FUNCTION_INDEX, + INT32x4_FUNCTION_PROTOTYPE_MAP_INDEX, STRING_FUNCTION_INDEX, STRING_FUNCTION_PROTOTYPE_MAP_INDEX, SYMBOL_FUNCTION_INDEX, @@ -276,6 +289,7 @@ class Context: public FixedArray { JS_ARRAY_MAPS_INDEX, DATE_FUNCTION_INDEX, JSON_OBJECT_INDEX, + SIMD_OBJECT_INDEX, REGEXP_FUNCTION_INDEX, CREATE_DATE_FUN_INDEX, TO_NUMBER_FUN_INDEX, @@ -297,6 +311,8 @@ class Context: public FixedArray { UINT32_ARRAY_FUN_INDEX, INT32_ARRAY_FUN_INDEX, FLOAT32_ARRAY_FUN_INDEX, + FLOAT32x4_ARRAY_FUN_INDEX, + INT32x4_ARRAY_FUN_INDEX, FLOAT64_ARRAY_FUN_INDEX, UINT8_CLAMPED_ARRAY_FUN_INDEX, DATA_VIEW_FUN_INDEX, diff --git a/src/d8.h b/src/d8.h index db2edb93c98..930254a1ac1 100644 --- a/src/d8.h +++ b/src/d8.h @@ -336,6 +336,8 @@ class Shell : public i::AllStatic { static void Int32Array(const v8::FunctionCallbackInfo& args); static void Uint32Array(const v8::FunctionCallbackInfo& args); static void Float32Array(const v8::FunctionCallbackInfo& args); + static void Float32x4Array(const v8::FunctionCallbackInfo& args); + static void Int32x4Array(const v8::FunctionCallbackInfo& args); static void Float64Array(const v8::FunctionCallbackInfo& args); static void Uint8ClampedArray( const v8::FunctionCallbackInfo& args); diff --git a/src/d8.js b/src/d8.js index 35b61d54ee7..1f7c5153a22 100644 --- a/src/d8.js +++ b/src/d8.js @@ -2210,6 +2210,8 @@ function Stringify(x, depth) { return "undefined"; case "boolean": case "number": + case "float32x4": + case "int32x4": case "function": return x.toString(); case "string": diff --git a/src/elements-kind.cc b/src/elements-kind.cc index d2abb0442a4..6953a9a5838 100644 --- a/src/elements-kind.cc +++ b/src/elements-kind.cc @@ -61,6 +61,11 @@ int ElementsKindToShiftSize(ElementsKind elements_kind) { case FAST_HOLEY_DOUBLE_ELEMENTS: case FLOAT64_ELEMENTS: return 3; + case EXTERNAL_FLOAT32x4_ELEMENTS: + case EXTERNAL_INT32x4_ELEMENTS: + case FLOAT32x4_ELEMENTS: + case INT32x4_ELEMENTS: + return 4; case FAST_SMI_ELEMENTS: case FAST_ELEMENTS: case FAST_HOLEY_SMI_ELEMENTS: diff --git a/src/elements-kind.h b/src/elements-kind.h index 5a3f00dcce9..a439a43ad49 100644 --- a/src/elements-kind.h +++ b/src/elements-kind.h @@ -58,8 +58,10 @@ enum ElementsKind { EXTERNAL_INT16_ELEMENTS, EXTERNAL_UINT16_ELEMENTS, EXTERNAL_INT32_ELEMENTS, + EXTERNAL_INT32x4_ELEMENTS, EXTERNAL_UINT32_ELEMENTS, EXTERNAL_FLOAT32_ELEMENTS, + EXTERNAL_FLOAT32x4_ELEMENTS, EXTERNAL_FLOAT64_ELEMENTS, EXTERNAL_UINT8_CLAMPED_ELEMENTS, @@ -70,7 +72,9 @@ enum ElementsKind { INT16_ELEMENTS, UINT32_ELEMENTS, INT32_ELEMENTS, + INT32x4_ELEMENTS, FLOAT32_ELEMENTS, + FLOAT32x4_ELEMENTS, FLOAT64_ELEMENTS, UINT8_CLAMPED_ELEMENTS, @@ -140,11 +144,31 @@ inline bool IsExternalFloatOrDoubleElementsKind(ElementsKind kind) { } +inline bool IsExternalFloat32x4ElementsKind(ElementsKind kind) { + return kind == EXTERNAL_FLOAT32x4_ELEMENTS; +} + + +inline bool IsExternalInt32x4ElementsKind(ElementsKind kind) { + return kind == EXTERNAL_INT32x4_ELEMENTS; +} + + inline bool IsFixedFloatElementsKind(ElementsKind kind) { return kind == FLOAT32_ELEMENTS || kind == FLOAT64_ELEMENTS; } +inline bool IsFixedFloat32x4ElementsKind(ElementsKind kind) { + return kind == FLOAT32x4_ELEMENTS; +} + + +inline bool IsFixedInt32x4ElementsKind(ElementsKind kind) { + return kind == INT32x4_ELEMENTS; +} + + inline bool IsDoubleOrFloatElementsKind(ElementsKind kind) { return IsFastDoubleElementsKind(kind) || IsExternalFloatOrDoubleElementsKind(kind) || @@ -152,6 +176,23 @@ inline bool IsDoubleOrFloatElementsKind(ElementsKind kind) { } +inline bool IsFloat32x4ElementsKind(ElementsKind kind) { + return IsExternalFloat32x4ElementsKind(kind) || + IsFixedFloat32x4ElementsKind(kind); +} + + +inline bool IsInt32x4ElementsKind(ElementsKind kind) { + return IsExternalInt32x4ElementsKind(kind) || + IsFixedInt32x4ElementsKind(kind); +} + + +inline bool IsSIMD128ElementsKind(ElementsKind kind) { + return IsFloat32x4ElementsKind(kind) || IsInt32x4ElementsKind(kind); +} + + inline bool IsFastSmiOrObjectElementsKind(ElementsKind kind) { return kind == FAST_SMI_ELEMENTS || kind == FAST_HOLEY_SMI_ELEMENTS || diff --git a/src/elements.cc b/src/elements.cc index 2e4667d4a06..0350dc1f80d 100644 --- a/src/elements.cc +++ b/src/elements.cc @@ -54,8 +54,10 @@ // - ExternalInt16ElementsAccessor // - ExternalUint16ElementsAccessor // - ExternalInt32ElementsAccessor +// - ExternalInt32x4ElementsAccessor // - ExternalUint32ElementsAccessor // - ExternalFloat32ElementsAccessor +// - ExternalFloat32x4ElementsAccessor // - ExternalFloat64ElementsAccessor // - ExternalUint8ClampedElementsAccessor // - FixedUint8ElementsAccessor @@ -64,7 +66,9 @@ // - FixedInt16ElementsAccessor // - FixedUint32ElementsAccessor // - FixedInt32ElementsAccessor +// - FixedInt32x4ElementsAccessor // - FixedFloat32ElementsAccessor +// - FixedFloat32x4ElementsAccessor // - FixedFloat64ElementsAccessor // - FixedUint8ClampedElementsAccessor // - DictionaryElementsAccessor @@ -107,10 +111,14 @@ static const int kPackedSizeNotKnown = -1; EXTERNAL_UINT16_ELEMENTS, ExternalUint16Array) \ V(ExternalInt32ElementsAccessor, EXTERNAL_INT32_ELEMENTS, \ ExternalInt32Array) \ + V(ExternalInt32x4ElementsAccessor, EXTERNAL_INT32x4_ELEMENTS, \ + ExternalInt32x4Array) \ V(ExternalUint32ElementsAccessor, \ EXTERNAL_UINT32_ELEMENTS, ExternalUint32Array) \ V(ExternalFloat32ElementsAccessor, \ EXTERNAL_FLOAT32_ELEMENTS, ExternalFloat32Array) \ + V(ExternalFloat32x4ElementsAccessor, \ + EXTERNAL_FLOAT32x4_ELEMENTS, ExternalFloat32x4Array) \ V(ExternalFloat64ElementsAccessor, \ EXTERNAL_FLOAT64_ELEMENTS, ExternalFloat64Array) \ V(ExternalUint8ClampedElementsAccessor, \ @@ -122,7 +130,10 @@ static const int kPackedSizeNotKnown = -1; V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array) \ V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array) \ V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array) \ + V(FixedInt32x4ElementsAccessor, INT32x4_ELEMENTS, FixedInt32x4Array) \ V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array) \ + V(FixedFloat32x4ElementsAccessor, FLOAT32x4_ELEMENTS, \ + FixedFloat32x4Array) \ V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array) \ V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS, \ FixedUint8ClampedArray) diff --git a/src/factory.cc b/src/factory.cc index 0513297a266..8280db684d2 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1010,6 +1010,22 @@ Handle Factory::NewHeapNumber(double value, } +Handle Factory::NewFloat32x4(float32x4_value_t value, + PretenureFlag pretenure) { + CALL_HEAP_FUNCTION( + isolate(), + isolate()->heap()->AllocateFloat32x4(value, pretenure), Float32x4); +} + + +Handle Factory::NewInt32x4(int32x4_value_t value, + PretenureFlag pretenure) { + CALL_HEAP_FUNCTION( + isolate(), + isolate()->heap()->AllocateInt32x4(value, pretenure), Int32x4); +} + + Handle Factory::NewNeanderObject() { CALL_HEAP_FUNCTION( isolate(), diff --git a/src/factory.h b/src/factory.h index 8ca9d481d80..cad48c6bee9 100644 --- a/src/factory.h +++ b/src/factory.h @@ -315,6 +315,11 @@ class Factory { Handle NewHeapNumber(double value, PretenureFlag pretenure = NOT_TENURED); + Handle NewFloat32x4(float32x4_value_t value, + PretenureFlag pretenure = NOT_TENURED); + + Handle NewInt32x4(int32x4_value_t value, + PretenureFlag pretenure = NOT_TENURED); // These objects are used by the api to create env-independent data // structures in the heap. diff --git a/src/flag-definitions.h b/src/flag-definitions.h index e0089e65904..9b9e70ed0a3 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -166,6 +166,7 @@ struct MaybeBoolFlag { #define FLAG FLAG_FULL // Flags for language modes and experimental language features. +DEFINE_bool(simd_object, false, "enable SIMD object and operations") DEFINE_bool(use_strict, false, "enforce strict mode") DEFINE_bool(es5_readonly, true, "activate correct semantics for inheriting readonliness") diff --git a/src/globals.h b/src/globals.h index 2f526a83bbe..c9d2326a7f9 100644 --- a/src/globals.h +++ b/src/globals.h @@ -225,6 +225,9 @@ typedef byte* Address; // ----------------------------------------------------------------------------- // Constants +struct float32x4_value_t { float storage[4]; }; +struct int32x4_value_t { int32_t storage[4]; }; + const int KB = 1024; const int MB = KB * KB; const int GB = KB * KB * KB; @@ -241,14 +244,17 @@ const int kMinUInt16 = 0; const uint32_t kMaxUInt32 = 0xFFFFFFFFu; -const int kCharSize = sizeof(char); // NOLINT -const int kShortSize = sizeof(short); // NOLINT -const int kIntSize = sizeof(int); // NOLINT -const int kInt32Size = sizeof(int32_t); // NOLINT -const int kInt64Size = sizeof(int64_t); // NOLINT -const int kDoubleSize = sizeof(double); // NOLINT -const int kIntptrSize = sizeof(intptr_t); // NOLINT -const int kPointerSize = sizeof(void*); // NOLINT +const int kCharSize = sizeof(char); // NOLINT +const int kShortSize = sizeof(short); // NOLINT +const int kIntSize = sizeof(int); // NOLINT +const int kInt32Size = sizeof(int32_t); // NOLINT +const int kInt64Size = sizeof(int64_t); // NOLINT +const int kDoubleSize = sizeof(double); // NOLINT +const int kFloatSize = sizeof(float); // NOLINT +const int kFloat32x4Size = sizeof(float32x4_value_t); // NOLINT +const int kInt32x4Size = sizeof(int32x4_value_t); // NOLINT +const int kIntptrSize = sizeof(intptr_t); // NOLINT +const int kPointerSize = sizeof(void*); // NOLINT const int kRegisterSize = kPointerSize; const int kPCOnStackSize = kRegisterSize; const int kFPOnStackSize = kRegisterSize; diff --git a/src/heap.cc b/src/heap.cc index 862e2eaa24b..955721ed079 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -2812,6 +2812,8 @@ bool Heap::CreateInitialMaps() { ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, scope_info) ALLOCATE_MAP(HEAP_NUMBER_TYPE, HeapNumber::kSize, heap_number) + ALLOCATE_MAP(FLOAT32x4_TYPE, Float32x4::kSize, float32x4) + ALLOCATE_MAP(INT32x4_TYPE, Int32x4::kSize, int32x4) ALLOCATE_MAP(SYMBOL_TYPE, Symbol::kSize, symbol) ALLOCATE_MAP(FOREIGN_TYPE, Foreign::kSize, foreign) @@ -2931,6 +2933,46 @@ MaybeObject* Heap::AllocateHeapNumber(double value, PretenureFlag pretenure) { } +MaybeObject* Heap::AllocateFloat32x4(float32x4_value_t value, + PretenureFlag pretenure) { + // Statically ensure that it is safe to allocate float32x4 objects in paged + // spaces. + int size = Float32x4::kSize; + STATIC_ASSERT(Float32x4::kSize <= Page::kMaxRegularHeapObjectSize); + + AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); + + Object* result; + { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + + HeapObject::cast(result)->set_map_no_write_barrier(float32x4_map()); + Float32x4::cast(result)->set_value(value); + return result; +} + + +MaybeObject* Heap::AllocateInt32x4(int32x4_value_t value, + PretenureFlag pretenure) { + // Statically ensure that it is safe to allocate int32x4 objects in paged + // spaces. + int size = Int32x4::kSize; + STATIC_ASSERT(Int32x4::kSize <= Page::kMaxRegularHeapObjectSize); + + AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); + + Object* result; + { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + + HeapObject::cast(result)->set_map_no_write_barrier(int32x4_map()); + Int32x4::cast(result)->set_value(value); + return result; +} + + MaybeObject* Heap::AllocateCell(Object* value) { int size = Cell::kSize; STATIC_ASSERT(Cell::kSize <= Page::kMaxRegularHeapObjectSize); diff --git a/src/heap.h b/src/heap.h index c9101bea9f7..456bc8d0e17 100644 --- a/src/heap.h +++ b/src/heap.h @@ -65,6 +65,8 @@ namespace internal { V(Map, shared_function_info_map, SharedFunctionInfoMap) \ V(Map, meta_map, MetaMap) \ V(Map, heap_number_map, HeapNumberMap) \ + V(Map, float32x4_map, Float32x4Map) \ + V(Map, int32x4_map, Int32x4Map) \ V(Map, native_context_map, NativeContextMap) \ V(Map, fixed_array_map, FixedArrayMap) \ V(Map, code_map, CodeMap) \ @@ -138,8 +140,10 @@ namespace internal { V(Map, external_int16_array_map, ExternalInt16ArrayMap) \ V(Map, external_uint16_array_map, ExternalUint16ArrayMap) \ V(Map, external_int32_array_map, ExternalInt32ArrayMap) \ + V(Map, external_int32x4_array_map, ExternalInt32x4ArrayMap) \ V(Map, external_uint32_array_map, ExternalUint32ArrayMap) \ V(Map, external_float32_array_map, ExternalFloat32ArrayMap) \ + V(Map, external_float32x4_array_map, ExternalFloat32x4ArrayMap) \ V(Map, external_float64_array_map, ExternalFloat64ArrayMap) \ V(Map, external_uint8_clamped_array_map, ExternalUint8ClampedArrayMap) \ V(ExternalArray, empty_external_int8_array, \ @@ -150,9 +154,11 @@ namespace internal { V(ExternalArray, empty_external_uint16_array, \ EmptyExternalUint16Array) \ V(ExternalArray, empty_external_int32_array, EmptyExternalInt32Array) \ + V(ExternalArray, empty_external_int32x4_array, EmptyExternalInt32x4Array) \ V(ExternalArray, empty_external_uint32_array, \ EmptyExternalUint32Array) \ V(ExternalArray, empty_external_float32_array, EmptyExternalFloat32Array) \ + V(ExternalArray, empty_external_float32x4_array, EmptyExternalFloat32x4Array)\ V(ExternalArray, empty_external_float64_array, EmptyExternalFloat64Array) \ V(ExternalArray, empty_external_uint8_clamped_array, \ EmptyExternalUint8ClampedArray) \ @@ -162,7 +168,9 @@ namespace internal { V(Map, fixed_int16_array_map, FixedInt16ArrayMap) \ V(Map, fixed_uint32_array_map, FixedUint32ArrayMap) \ V(Map, fixed_int32_array_map, FixedInt32ArrayMap) \ + V(Map, fixed_int32x4_array_map, FixedInt32x4ArrayMap) \ V(Map, fixed_float32_array_map, FixedFloat32ArrayMap) \ + V(Map, fixed_float32x4_array_map, FixedFloat32x4ArrayMap) \ V(Map, fixed_float64_array_map, FixedFloat64ArrayMap) \ V(Map, fixed_uint8_clamped_array_map, FixedUint8ClampedArrayMap) \ V(Map, non_strict_arguments_elements_map, NonStrictArgumentsElementsMap) \ @@ -234,6 +242,8 @@ namespace internal { V(null_string, "null") \ V(number_string, "number") \ V(Number_string, "Number") \ + V(float32x4_string, "float32x4") \ + V(int32x4_string, "int32x4") \ V(nan_string, "NaN") \ V(RegExp_string, "RegExp") \ V(source_string, "source") \ @@ -306,6 +316,16 @@ namespace internal { V(throw_string, "throw") \ V(done_string, "done") \ V(value_string, "value") \ + V(signMask, "signMask") \ + V(x, "x") \ + V(y, "y") \ + V(z, "z") \ + V(w, "w") \ + V(flagX, "flagX") \ + V(flagY, "flagY") \ + V(flagZ, "flagZ") \ + V(flagW, "flagW") \ + V(simd, "SIMD") \ V(next_string, "next") \ V(byte_length_string, "byteLength") \ V(byte_offset_string, "byteOffset") \ @@ -1050,6 +1070,16 @@ class Heap { MUST_USE_RESULT MaybeObject* AllocateHeapNumber( double value, PretenureFlag pretenure = NOT_TENURED); + // Allocated a Float32x4 from value. + MUST_USE_RESULT MaybeObject* AllocateFloat32x4( + float32x4_value_t value, + PretenureFlag pretenure = NOT_TENURED); + + // Allocated a Int32x4 from value. + MUST_USE_RESULT MaybeObject* AllocateInt32x4( + int32x4_value_t value, + PretenureFlag pretenure = NOT_TENURED); + // Converts an int into either a Smi or a HeapNumber object. // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation // failed. diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index dbf61835f8c..208cbd24ca9 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -6431,6 +6431,13 @@ class HLoadKeyed V8_FINAL elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) { set_representation(Representation::Double()); + } else if (elements_kind == EXTERNAL_FLOAT32x4_ELEMENTS || + elements_kind == FLOAT32x4_ELEMENTS || + elements_kind == EXTERNAL_INT32x4_ELEMENTS || + elements_kind == INT32x4_ELEMENTS) { + // TODO(haitao): Set the representation to Float32x4 or Int32x4 after + // SIMD instructions are added. + set_representation(Representation::Tagged()); } else { set_representation(Representation::Integer32()); } @@ -6717,6 +6724,14 @@ class HStoreKeyed V8_FINAL if (IsDoubleOrFloatElementsKind(elements_kind())) { return Representation::Double(); } + if (IsExternalFloat32x4ElementsKind(elements_kind()) || + IsFixedFloat32x4ElementsKind(elements_kind()) || + IsExternalInt32x4ElementsKind(elements_kind()) || + IsFixedInt32x4ElementsKind(elements_kind())) { + // TODO(haitao): Set the required input representation to Float32x4 or + // Int32x4 after SIMD instructions are added. + return Representation::Tagged(); + } if (SmiValuesAre32Bits() && store_mode_ == STORE_TO_INITIALIZED_ENTRY) { return Representation::Integer32(); } @@ -6749,6 +6764,14 @@ class HStoreKeyed V8_FINAL if (IsDoubleOrFloatElementsKind(elements_kind())) { return Representation::Double(); } + if (IsExternalFloat32x4ElementsKind(elements_kind()) || + IsFixedFloat32x4ElementsKind(elements_kind()) || + IsExternalInt32x4ElementsKind(elements_kind()) || + IsFixedInt32x4ElementsKind(elements_kind())) { + // TODO(haitao): Set the required input representation to Float32x4 or + // Int32x4 after SIMD instructions are added. + return Representation::Tagged(); + } if (SmiValuesAre32Bits() && store_mode_ == STORE_TO_INITIALIZED_ENTRY) { return Representation::Integer32(); } diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h index 6ed0bc6d662..43d6d6868a9 100644 --- a/src/ia32/assembler-ia32.h +++ b/src/ia32/assembler-ia32.h @@ -377,6 +377,7 @@ enum ScaleFactor { times_2 = 1, times_4 = 2, times_8 = 3, + maximal_scale_factor = times_8, times_int_size = times_4, times_half_pointer_size = times_2, times_pointer_size = times_4, diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 08686e37c97..f1b8d3b53c9 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -4520,6 +4520,14 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ cmp(FieldOperand(eax, HeapObject::kMapOffset), isolate()->factory()->heap_number_map()); Split(equal, if_true, if_false, fall_through); + } else if (check->Equals(isolate()->heap()->float32x4_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, FLOAT32x4_TYPE, edx); + Split(equal, if_true, if_false, fall_through); + } else if (check->Equals(isolate()->heap()->int32x4_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, INT32x4_TYPE, edx); + Split(equal, if_true, if_false, fall_through); } else if (check->Equals(isolate()->heap()->string_string())) { __ JumpIfSmi(eax, if_false); __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx); diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index dd5465398e5..2588e900407 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -3394,13 +3394,115 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { } +void LCodeGen::DoDeferredSIMD128ToTagged(LInstruction* instr, + Runtime::FunctionId id) { + // TODO(3095996): Get rid of this. For now, we need to make the + // result register contain a valid pointer because it is already + // contained in the register pointer map. + Register reg = ToRegister(instr->result()); + __ Set(reg, Immediate(0)); + + PushSafepointRegistersScope scope(this); + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); + __ CallRuntimeSaveDoubles(id); + RecordSafepointWithRegisters( + instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); + __ StoreToSafepointRegisterSlot(reg, eax); +} + + +void LCodeGen::HandleExternalArrayOpRequiresTemp( + LOperand* key, + Representation key_representation, + ElementsKind elements_kind) { + if (ExternalArrayOpRequiresPreScale(key_representation, elements_kind)) { + int pre_shift_size = ElementsKindToShiftSize(elements_kind) - + static_cast(maximal_scale_factor); + if (key_representation.IsSmi()) { + pre_shift_size -= kSmiTagSize; + } + ASSERT(pre_shift_size > 0); + __ shl(ToRegister(key), pre_shift_size); + } else { + __ SmiUntag(ToRegister(key)); + } +} + + +template +void LCodeGen::DoLoadKeyedSIMD128ExternalArray(LLoadKeyed* instr) { + class DeferredSIMD128ToTagged V8_FINAL : public LDeferredCode { + public: + DeferredSIMD128ToTagged(LCodeGen* codegen, + LInstruction* instr, + Runtime::FunctionId id, + const X87Stack& x87_stack) + : LDeferredCode(codegen, x87_stack), instr_(instr), id_(id) { } + virtual void Generate() V8_OVERRIDE { + codegen()->DoDeferredSIMD128ToTagged(instr_, id_); + } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } + private: + LInstruction* instr_; + Runtime::FunctionId id_; + }; + + // Allocate a SIMD128 object on the heap. + Register reg = ToRegister(instr->result()); + Register tmp = ToRegister(instr->temp()); + DeferredSIMD128ToTagged* deferred = new(zone()) DeferredSIMD128ToTagged( + this, instr, static_cast(T::kRuntimeAllocatorId()), + x87_stack_); + if (FLAG_inline_new) { + __ AllocateSIMDHeapObject(T::kSize, reg, tmp, deferred->entry(), + static_cast(T::kMapRootIndex())); + } else { + __ jmp(deferred->entry()); + } + __ bind(deferred->exit()); + + // Copy the SIMD128 value from the external array to the heap object. + STATIC_ASSERT(T::kValueSize % kPointerSize == 0); + LOperand* key = instr->key(); + ElementsKind elements_kind = instr->elements_kind(); + for (int offset = 0; offset < T::kValueSize; offset += kPointerSize) { + Operand operand(BuildFastArrayOperand( + instr->elements(), + key, + instr->hydrogen()->key()->representation(), + elements_kind, + offset, + instr->additional_index())); + __ mov(tmp, operand); + __ mov(FieldOperand(reg, T::kValueOffset + offset), tmp); + } +} + + void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { + class DeferredSIMD128ToTagged V8_FINAL : public LDeferredCode { + public: + DeferredSIMD128ToTagged(LCodeGen* codegen, + LInstruction* instr, + Runtime::FunctionId id, + const X87Stack& x87_stack) + : LDeferredCode(codegen, x87_stack), instr_(instr), id_(id) { } + virtual void Generate() V8_OVERRIDE { + codegen()->DoDeferredSIMD128ToTagged(instr_, id_); + } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } + private: + LInstruction* instr_; + Runtime::FunctionId id_; + }; + ElementsKind elements_kind = instr->elements_kind(); LOperand* key = instr->key(); if (!key->IsConstantOperand() && ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(), elements_kind)) { - __ SmiUntag(ToRegister(key)); + HandleExternalArrayOpRequiresTemp(key, + instr->hydrogen()->key()->representation(), elements_kind); } Operand operand(BuildFastArrayOperand( instr->elements(), @@ -3427,6 +3529,10 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { } else { X87Mov(ToX87Register(instr->result()), operand); } + } else if (IsFloat32x4ElementsKind(elements_kind)) { + DoLoadKeyedSIMD128ExternalArray(instr); + } else if (IsInt32x4ElementsKind(elements_kind)) { + DoLoadKeyedSIMD128ExternalArray(instr); } else { Register result(ToRegister(instr->result())); switch (elements_kind) { @@ -3462,8 +3568,12 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { break; case EXTERNAL_FLOAT32_ELEMENTS: case EXTERNAL_FLOAT64_ELEMENTS: + case EXTERNAL_FLOAT32x4_ELEMENTS: + case EXTERNAL_INT32x4_ELEMENTS: case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: + case FLOAT32x4_ELEMENTS: + case INT32x4_ELEMENTS: case FAST_SMI_ELEMENTS: case FAST_ELEMENTS: case FAST_DOUBLE_ELEMENTS: @@ -3568,8 +3678,11 @@ Operand LCodeGen::BuildFastArrayOperand( ((constant_value + additional_index) << shift_size) + offset); } else { - // Take the tag bit into account while computing the shift size. - if (key_representation.IsSmi() && (shift_size >= 1)) { + if (ExternalArrayOpRequiresPreScale(key_representation, elements_kind)) { + // Make sure the key is pre-scaled against maximal_scale_factor. + shift_size = static_cast(maximal_scale_factor); + } else if (key_representation.IsSmi() && (shift_size >= 1)) { + // Take the tag bit into account while computing the shift size. shift_size -= kSmiTagSize; } ScaleFactor scale_factor = static_cast(shift_size); @@ -4524,13 +4637,42 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { } +template +void LCodeGen::DoStoreKeyedSIMD128ExternalArray(LStoreKeyed* instr) { + ASSERT(instr->value()->IsRegister()); + Register temp = ToRegister(instr->temp()); + Register input_reg = ToRegister(instr->value()); + __ test(input_reg, Immediate(kSmiTagMask)); + DeoptimizeIf(zero, instr->environment()); + __ CmpObjectType(input_reg, T::kInstanceType, temp); + DeoptimizeIf(not_equal, instr->environment()); + + // Copy the SIMD128 value from the heap object to the external array. + STATIC_ASSERT(T::kValueSize % kPointerSize == 0); + LOperand* key = instr->key(); + ElementsKind elements_kind = instr->elements_kind(); + for (int offset = 0; offset < T::kValueSize; offset += kPointerSize) { + Operand operand(BuildFastArrayOperand( + instr->elements(), + key, + instr->hydrogen()->key()->representation(), + elements_kind, + offset, + instr->additional_index())); + __ mov(temp, FieldOperand(input_reg, T::kValueOffset + offset)); + __ mov(operand, temp); + } +} + + void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { ElementsKind elements_kind = instr->elements_kind(); LOperand* key = instr->key(); if (!key->IsConstantOperand() && ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(), elements_kind)) { - __ SmiUntag(ToRegister(key)); + HandleExternalArrayOpRequiresTemp(key, + instr->hydrogen()->key()->representation(), elements_kind); } Operand operand(BuildFastArrayOperand( instr->elements(), @@ -4558,6 +4700,10 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { } else { X87Mov(operand, ToX87Register(instr->value())); } + } else if (IsFloat32x4ElementsKind(elements_kind)) { + DoStoreKeyedSIMD128ExternalArray(instr); + } else if (IsInt32x4ElementsKind(elements_kind)) { + DoStoreKeyedSIMD128ExternalArray(instr); } else { Register value = ToRegister(instr->value()); switch (elements_kind) { @@ -4583,8 +4729,12 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { break; case EXTERNAL_FLOAT32_ELEMENTS: case EXTERNAL_FLOAT64_ELEMENTS: + case EXTERNAL_FLOAT32x4_ELEMENTS: + case EXTERNAL_INT32x4_ELEMENTS: case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: + case FLOAT32x4_ELEMENTS: + case INT32x4_ELEMENTS: case FAST_SMI_ELEMENTS: case FAST_ELEMENTS: case FAST_DOUBLE_ELEMENTS: @@ -6051,6 +6201,16 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { factory()->heap_number_map()); final_branch_condition = equal; + } else if (type_name->Equals(heap()->float32x4_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, FLOAT32x4_TYPE, input); + final_branch_condition = equal; + + } else if (type_name->Equals(heap()->int32x4_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, INT32x4_TYPE, input); + final_branch_condition = equal; + } else if (type_name->Equals(heap()->string_string())) { __ JumpIfSmi(input, false_label, false_distance); __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input); diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h index fa5e88b0333..0269ab872cf 100644 --- a/src/ia32/lithium-codegen-ia32.h +++ b/src/ia32/lithium-codegen-ia32.h @@ -161,6 +161,7 @@ class LCodeGen: public LCodeGenBase { void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, Label* map_check); void DoDeferredInstanceMigration(LCheckMaps* instr, Register object); + void DoDeferredSIMD128ToTagged(LInstruction* instr, Runtime::FunctionId id); // Parallel move support. void DoParallelMove(LParallelMove* move); @@ -380,9 +381,16 @@ class LCodeGen: public LCodeGenBase { void EnsureSpaceForLazyDeopt(int space_needed) V8_OVERRIDE; void DoLoadKeyedExternalArray(LLoadKeyed* instr); + void HandleExternalArrayOpRequiresTemp(LOperand* key, + Representation key_representation, + ElementsKind elements_kind); + template + void DoLoadKeyedSIMD128ExternalArray(LLoadKeyed* instr); void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); void DoLoadKeyedFixedArray(LLoadKeyed* instr); void DoStoreKeyedExternalArray(LStoreKeyed* instr); + template + void DoStoreKeyedSIMD128ExternalArray(LStoreKeyed* instr); void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); void DoStoreKeyedFixedArray(LStoreKeyed* instr); diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index 95b810f6656..26e84975638 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -2124,17 +2124,25 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { : UseRegisterOrConstantAtStart(instr->key()); LLoadKeyed* result = NULL; + bool load_128bits_without_sse2 = IsSIMD128ElementsKind(elements_kind); if (!instr->is_typed_elements()) { LOperand* obj = UseRegisterAtStart(instr->elements()); - result = new(zone()) LLoadKeyed(obj, key); + result = new(zone()) LLoadKeyed(obj, key, NULL); } else { ASSERT( (instr->representation().IsInteger32() && !(IsDoubleOrFloatElementsKind(instr->elements_kind()))) || (instr->representation().IsDouble() && - (IsDoubleOrFloatElementsKind(instr->elements_kind())))); + (IsDoubleOrFloatElementsKind(instr->elements_kind()))) || + (instr->representation().IsTagged() && + (IsSIMD128ElementsKind(instr->elements_kind())))); LOperand* backing_store = UseRegister(instr->elements()); - result = new(zone()) LLoadKeyed(backing_store, key); + result = new(zone()) LLoadKeyed(backing_store, key, + load_128bits_without_sse2 ? TempRegister() : NULL); + if (load_128bits_without_sse2) { + info()->MarkAsDeferredCalling(); + AssignPointerMap(result); + } } DefineAsRegister(result); @@ -2192,7 +2200,7 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { LOperand* val = NULL; val = UseRegisterAtStart(instr->value()); LOperand* key = UseRegisterOrConstantAtStart(instr->key()); - return new(zone()) LStoreKeyed(object, key, val); + return new(zone()) LStoreKeyed(object, key, val, NULL); } else { ASSERT(instr->value()->representation().IsSmiOrTagged()); bool needs_write_barrier = instr->NeedsWriteBarrier(); @@ -2207,7 +2215,7 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { val = UseRegisterOrConstantAtStart(instr->value()); key = UseRegisterOrConstantAtStart(instr->key()); } - return new(zone()) LStoreKeyed(obj, key, val); + return new(zone()) LStoreKeyed(obj, key, val, NULL); } } @@ -2216,7 +2224,9 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { (instr->value()->representation().IsInteger32() && !IsDoubleOrFloatElementsKind(elements_kind)) || (instr->value()->representation().IsDouble() && - IsDoubleOrFloatElementsKind(elements_kind))); + IsDoubleOrFloatElementsKind(elements_kind)) || + (instr->value()->representation().IsTagged() && + IsSIMD128ElementsKind(elements_kind))); ASSERT((instr->is_fixed_typed_array() && instr->elements()->representation().IsTagged()) || (instr->is_external() && @@ -2229,7 +2239,11 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { LOperand* key = clobbers_key ? UseTempRegister(instr->key()) : UseRegisterOrConstantAtStart(instr->key()); - return new(zone()) LStoreKeyed(backing_store, key, val); + bool store_128bits_without_sse2 = IsSIMD128ElementsKind(elements_kind); + LStoreKeyed* result = + new(zone()) LStoreKeyed(backing_store, key, val, + store_128bits_without_sse2 ? TempRegister() : NULL); + return store_128bits_without_sse2 ? AssignEnvironment(result) : result; } diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index bea6381d086..7cb7da0364f 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -1566,14 +1566,16 @@ class LLoadExternalArrayPointer V8_FINAL }; -class LLoadKeyed V8_FINAL : public LTemplateInstruction<1, 2, 0> { +class LLoadKeyed V8_FINAL : public LTemplateInstruction<1, 2, 1> { public: - LLoadKeyed(LOperand* elements, LOperand* key) { + LLoadKeyed(LOperand* elements, LOperand* key, LOperand* temp) { inputs_[0] = elements; inputs_[1] = key; + temps_[0] = temp; } LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } ElementsKind elements_kind() const { return hydrogen()->elements_kind(); } @@ -1598,19 +1600,30 @@ class LLoadKeyed V8_FINAL : public LTemplateInstruction<1, 2, 0> { }; +inline static bool ExternalArrayOpRequiresPreScale( + Representation key_representation, + ElementsKind kind) { + int shift_size = ElementsKindToShiftSize(kind); + return key_representation.IsSmi() + ? shift_size > static_cast(maximal_scale_factor) + kSmiTagSize + : shift_size > static_cast(maximal_scale_factor); +} + + inline static bool ExternalArrayOpRequiresTemp( Representation key_representation, ElementsKind elements_kind) { - // Operations that require the key to be divided by two to be converted into - // an index cannot fold the scale operation into a load and need an extra - // temp register to do the work. - return key_representation.IsSmi() && - (elements_kind == EXTERNAL_INT8_ELEMENTS || - elements_kind == EXTERNAL_UINT8_ELEMENTS || - elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS || - elements_kind == UINT8_ELEMENTS || - elements_kind == INT8_ELEMENTS || - elements_kind == UINT8_CLAMPED_ELEMENTS); + // Operations that require the key to be scaled by a factor or divided by two + // to be converted into an index cannot fold the scale operation into a load + // and need an extra temp register to do the work. + return ExternalArrayOpRequiresPreScale(key_representation, elements_kind) || + (key_representation.IsSmi() && + (elements_kind == EXTERNAL_INT8_ELEMENTS || + elements_kind == EXTERNAL_UINT8_ELEMENTS || + elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS || + elements_kind == UINT8_ELEMENTS || + elements_kind == INT8_ELEMENTS || + elements_kind == UINT8_CLAMPED_ELEMENTS)); } @@ -2207,12 +2220,13 @@ class LStoreNamedGeneric V8_FINAL : public LTemplateInstruction<0, 3, 0> { }; -class LStoreKeyed V8_FINAL : public LTemplateInstruction<0, 3, 0> { +class LStoreKeyed V8_FINAL : public LTemplateInstruction<0, 3, 1> { public: - LStoreKeyed(LOperand* obj, LOperand* key, LOperand* val) { + LStoreKeyed(LOperand* obj, LOperand* key, LOperand* val, LOperand* temp) { inputs_[0] = obj; inputs_[1] = key; inputs_[2] = val; + temps_[0] = temp; } bool is_external() const { return hydrogen()->is_external(); } @@ -2225,6 +2239,7 @@ class LStoreKeyed V8_FINAL : public LTemplateInstruction<0, 3, 0> { LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } + LOperand* temp() { return temps_[0]; } ElementsKind elements_kind() const { return hydrogen()->elements_kind(); } diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index 78ba28b6a6e..edb68813ac5 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -1832,6 +1832,29 @@ void MacroAssembler::AllocateHeapNumber(Register result, } +void MacroAssembler::AllocateSIMDHeapObject(int size, + Register result, + Register scratch, + Label* gc_required, + Heap::RootListIndex map_index) { + Allocate(size, result, scratch, no_reg, gc_required, TAG_OBJECT); + + // Set the map. + switch (map_index) { + case Heap::kFloat32x4MapRootIndex: + mov(FieldOperand(result, HeapObject::kMapOffset), + Immediate(isolate()->factory()->float32x4_map())); + break; + case Heap::kInt32x4MapRootIndex: + mov(FieldOperand(result, HeapObject::kMapOffset), + Immediate(isolate()->factory()->int32x4_map())); + break; + default: + UNREACHABLE(); + } +} + + void MacroAssembler::AllocateTwoByteString(Register result, Register length, Register scratch1, diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h index e109b20990b..102adb6a32e 100644 --- a/src/ia32/macro-assembler-ia32.h +++ b/src/ia32/macro-assembler-ia32.h @@ -651,6 +651,11 @@ class MacroAssembler: public Assembler { Register scratch1, Register scratch2, Label* gc_required); + void AllocateSIMDHeapObject(int size, + Register result, + Register scratch, + Label* gc_required, + Heap::RootListIndex map_index); // Allocate a sequential string. All the header fields of the string object // are initialized. diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index e76bfb5f3bf..0e3b7967704 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -1746,6 +1746,37 @@ Register CallStubCompiler::HandlerFrontendHeader(Handle object, masm(), Context::NUMBER_FUNCTION_INDEX, eax, miss); break; } + + case FLOAT32x4_CHECK: { + Label fast; + // Check that the object is a float32x4. + __ CmpObjectType(edx, FLOAT32x4_TYPE, eax); + __ j(not_equal, miss); + // Check that the maps starting from the prototype haven't changed. + GenerateDirectLoadGlobalFunctionPrototype( + masm(), Context::FLOAT32x4_FUNCTION_INDEX, eax, miss); + Handle prototype(object->GetPrototype(isolate()), isolate()); + CheckPrototypes( + IC::CurrentTypeOf(prototype, isolate()), + eax, holder, ebx, edx, edi, name, miss); + break; + } + + case INT32x4_CHECK: { + Label fast; + // Check that the object is a int32x4. + __ CmpObjectType(edx, INT32x4_TYPE, eax); + __ j(not_equal, miss); + // Check that the maps starting from the prototype haven't changed. + GenerateDirectLoadGlobalFunctionPrototype( + masm(), Context::INT32x4_FUNCTION_INDEX, eax, miss); + Handle prototype(object->GetPrototype(isolate()), isolate()); + CheckPrototypes( + IC::CurrentTypeOf(prototype, isolate()), + eax, holder, ebx, edx, edi, name, miss); + break; + } + case BOOLEAN_CHECK: { GenerateBooleanCheck(reg, miss); // Check that the maps starting from the prototype haven't changed. diff --git a/src/ic-inl.h b/src/ic-inl.h index e0f807ce4bf..f30a18eabaf 100644 --- a/src/ic-inl.h +++ b/src/ic-inl.h @@ -105,7 +105,8 @@ InlineCacheHolderFlag IC::GetCodeCacheForObject(Object* object) { // If the object is a value, we use the prototype map for the cache. ASSERT(object->IsString() || object->IsSymbol() || - object->IsNumber() || object->IsBoolean()); + object->IsNumber() || object->IsFloat32x4() || + object->IsInt32x4() || object->IsBoolean()); return PROTOTYPE_MAP; } diff --git a/src/ic.cc b/src/ic.cc index b4657579448..8b1975cfaef 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -525,7 +525,8 @@ void CallICBase::ReceiverToObjectIfRequired(Handle callee, } // And only wrap string, number or boolean. - if (object->IsString() || object->IsNumber() || object->IsBoolean()) { + if (object->IsString() || object->IsNumber() || object->IsBoolean() || + object->IsFloat32x4() || object->IsInt32x4()) { // Change the receiver to the result of calling ToObject on it. const int argc = this->target()->arguments_count(); StackFrameLocator locator(isolate()); diff --git a/src/macros.py b/src/macros.py index 1722c6c7de2..8c96159fd42 100644 --- a/src/macros.py +++ b/src/macros.py @@ -99,6 +99,8 @@ macro IS_NULL_OR_UNDEFINED(arg) = (arg == null); macro IS_UNDEFINED(arg) = (typeof(arg) === 'undefined'); macro IS_NUMBER(arg) = (typeof(arg) === 'number'); +macro IsFloat32x4(arg) = (typeof(arg) === 'float32x4'); +macro IsInt32x4(arg) = (typeof(arg) === 'int32x4'); macro IS_STRING(arg) = (typeof(arg) === 'string'); macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean'); macro IS_SYMBOL(arg) = (typeof(arg) === 'symbol'); @@ -112,6 +114,8 @@ macro IS_WEAKSET(arg) = (%_ClassOf(arg) === 'WeakSet'); macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date'); macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number'); +macro IsFloat32x4Wrapper(arg) = (%_ClassOf(arg) === 'float32x4'); +macro IsInt32x4Wrapper(arg) = (%_ClassOf(arg) === 'int32x4'); macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String'); macro IS_SYMBOL_WRAPPER(arg) = (%_ClassOf(arg) === 'Symbol'); macro IS_BOOLEAN_WRAPPER(arg) = (%_ClassOf(arg) === 'Boolean'); @@ -160,6 +164,8 @@ macro TO_NUMBER_INLINE(arg) = (IS_NUMBER(%IS_VAR(arg)) ? arg : NonNumberToNumber(arg)); macro TO_OBJECT_INLINE(arg) = (IS_SPEC_OBJECT(%IS_VAR(arg)) ? arg : ToObject(arg)); macro JSON_NUMBER_TO_STRING(arg) = ((%_IsSmi(%IS_VAR(arg)) || arg - arg == 0) ? %_NumberToString(arg) : "null"); +macro ToFloat32x4(arg) = (IsFloat32x4Wrapper(%IS_VAR(arg))) ? %_ValueOf(arg) : arg; +macro ToInt32x4(arg) = (IsInt32x4Wrapper(%IS_VAR(arg))) ? %_ValueOf(arg) : arg; # Private names. macro NEW_PRIVATE(name) = (%CreatePrivateSymbol(name)); @@ -271,3 +277,7 @@ const PROPERTY_ATTRIBUTES_STRING = 8; const PROPERTY_ATTRIBUTES_SYMBOLIC = 16; const PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL = 32; + +# For simd128.js +macro CheckFloat32x4(arg) = if (typeof(arg) !== 'float32x4') ThrowFloat32x4TypeError(); +macro CheckInt32x4(arg) = if (typeof(arg) !== 'int32x4') ThrowInt32x4TypeError(); diff --git a/src/mark-compact.cc b/src/mark-compact.cc index 81de035b0af..89d4f30b354 100644 --- a/src/mark-compact.cc +++ b/src/mark-compact.cc @@ -310,6 +310,8 @@ class VerifyNativeContextSeparationVisitor: public ObjectVisitor { case CODE_TYPE: case FIXED_DOUBLE_ARRAY_TYPE: case HEAP_NUMBER_TYPE: + case FLOAT32x4_TYPE: + case INT32x4_TYPE: case INTERCEPTOR_INFO_TYPE: case ODDBALL_TYPE: case SCRIPT_TYPE: diff --git a/src/objects-debug.cc b/src/objects-debug.cc index e33b46be799..110f7699160 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -89,6 +89,12 @@ void HeapObject::HeapObjectVerify() { case HEAP_NUMBER_TYPE: HeapNumber::cast(this)->HeapNumberVerify(); break; + case FLOAT32x4_TYPE: + Float32x4::cast(this)->Float32x4Verify(); + break; + case INT32x4_TYPE: + Int32x4::cast(this)->Int32x4Verify(); + break; case FIXED_ARRAY_TYPE: FixedArray::cast(this)->FixedArrayVerify(); break; @@ -236,6 +242,16 @@ void HeapNumber::HeapNumberVerify() { } +void Float32x4::Float32x4Verify() { + CHECK(IsFloat32x4()); +} + + +void Int32x4::Int32x4Verify() { + CHECK(IsInt32x4()); +} + + void ByteArray::ByteArrayVerify() { CHECK(IsByteArray()); } diff --git a/src/objects-inl.h b/src/objects-inl.h index f86e847802b..8c919601b4b 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -177,6 +177,8 @@ bool Object::NonFailureIsHeapObject() { TYPE_CHECKER(HeapNumber, HEAP_NUMBER_TYPE) +TYPE_CHECKER(Float32x4, FLOAT32x4_TYPE) +TYPE_CHECKER(Int32x4, INT32x4_TYPE) TYPE_CHECKER(Symbol, SYMBOL_TYPE) @@ -1136,6 +1138,23 @@ MaybeObject* Object::GetProperty(Name* key, PropertyAttributes* attributes) { write_double_field(p, offset, value) #endif // V8_TARGET_ARCH_MIPS +#define READ_FLOAT32x4_FIELD(p, offset) \ + (*reinterpret_cast(FIELD_ADDR(p, offset))) + +#define WRITE_FLOAT32x4_FIELD(p, offset, value) \ + (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) + +#define READ_INT32x4_FIELD(p, offset) \ + (*reinterpret_cast(FIELD_ADDR(p, offset))) + +#define WRITE_INT32x4_FIELD(p, offset, value) \ + (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) + +#define READ_FLOAT_FIELD(p, offset) \ + (*reinterpret_cast(FIELD_ADDR(p, offset))) + +#define WRITE_FLOAT_FIELD(p, offset, value) \ + (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) #define READ_INT_FIELD(p, offset) \ (*reinterpret_cast(FIELD_ADDR(p, offset))) @@ -1408,6 +1427,58 @@ int HeapNumber::get_sign() { } +int Float32x4::kRuntimeAllocatorId() { + return Runtime::kAllocateFloat32x4; +} + + +int Float32x4::kMapRootIndex() { + return Heap::kFloat32x4MapRootIndex; +} + + +float32x4_value_t Float32x4::value() { + return READ_FLOAT32x4_FIELD(this, kValueOffset); +} + + +void Float32x4::set_value(float32x4_value_t value) { + WRITE_FLOAT32x4_FIELD(this, kValueOffset, value); +} + + +float Float32x4::getAt(int index) { + ASSERT(index >= 0 && index < kLanes); + return READ_FLOAT_FIELD(this, kValueOffset + index * kFloatSize); +} + + +int Int32x4::kRuntimeAllocatorId() { + return Runtime::kAllocateInt32x4; +} + + +int Int32x4::kMapRootIndex() { + return Heap::kInt32x4MapRootIndex; +} + + +int32x4_value_t Int32x4::value() { + return READ_INT32x4_FIELD(this, kValueOffset); +} + + +void Int32x4::set_value(int32x4_value_t value) { + WRITE_INT32x4_FIELD(this, kValueOffset, value); +} + + +int32_t Int32x4::getAt(int index) { + ASSERT(index >= 0 && index < kLanes); + return READ_INT32_FIELD(this, kValueOffset + index * kInt32Size); +} + + ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset) @@ -2807,6 +2878,8 @@ CAST_ACCESSOR(JSObject) CAST_ACCESSOR(Smi) CAST_ACCESSOR(HeapObject) CAST_ACCESSOR(HeapNumber) +CAST_ACCESSOR(Float32x4) +CAST_ACCESSOR(Int32x4) CAST_ACCESSOR(Oddball) CAST_ACCESSOR(Cell) CAST_ACCESSOR(PropertyCell) @@ -2839,8 +2912,10 @@ CAST_ACCESSOR(ExternalUint8Array) CAST_ACCESSOR(ExternalInt16Array) CAST_ACCESSOR(ExternalUint16Array) CAST_ACCESSOR(ExternalInt32Array) +CAST_ACCESSOR(ExternalInt32x4Array) CAST_ACCESSOR(ExternalUint32Array) CAST_ACCESSOR(ExternalFloat32Array) +CAST_ACCESSOR(ExternalFloat32x4Array) CAST_ACCESSOR(ExternalFloat64Array) CAST_ACCESSOR(ExternalUint8ClampedArray) CAST_ACCESSOR(Struct) @@ -3610,6 +3685,62 @@ void ExternalFloat32Array::set(int index, float value) { } +float32x4_value_t ExternalFloat32x4Array::get_scalar(int index) { + ASSERT((index >= 0) && (index < this->length())); + float* ptr = static_cast(external_pointer()); + float32x4_value_t value; + value.storage[0] = ptr[index * 4 + 0]; + value.storage[1] = ptr[index * 4 + 1]; + value.storage[2] = ptr[index * 4 + 2]; + value.storage[3] = ptr[index * 4 + 3]; + return value; +} + + +MaybeObject* ExternalFloat32x4Array::get(int index) { + float32x4_value_t value = get_scalar(index); + return GetHeap()->AllocateFloat32x4(value); +} + + +void ExternalFloat32x4Array::set(int index, const float32x4_value_t& value) { + ASSERT((index >= 0) && (index < this->length())); + float* ptr = static_cast(external_pointer()); + ptr[index * 4 + 0] = value.storage[0]; + ptr[index * 4 + 1] = value.storage[1]; + ptr[index * 4 + 2] = value.storage[2]; + ptr[index * 4 + 3] = value.storage[3]; +} + + +int32x4_value_t ExternalInt32x4Array::get_scalar(int index) { + ASSERT((index >= 0) && (index < this->length())); + int32_t* ptr = static_cast(external_pointer()); + int32x4_value_t value; + value.storage[0] = ptr[index * 4 + 0]; + value.storage[1] = ptr[index * 4 + 1]; + value.storage[2] = ptr[index * 4 + 2]; + value.storage[3] = ptr[index * 4 + 3]; + return value; +} + + +MaybeObject* ExternalInt32x4Array::get(int index) { + int32x4_value_t value = get_scalar(index); + return GetHeap()->AllocateInt32x4(value); +} + + +void ExternalInt32x4Array::set(int index, const int32x4_value_t& value) { + ASSERT((index >= 0) && (index < this->length())); + int32_t* ptr = static_cast(external_pointer()); + ptr[index * 4 + 0] = value.storage[0]; + ptr[index * 4 + 1] = value.storage[1]; + ptr[index * 4 + 2] = value.storage[2]; + ptr[index * 4 + 3] = value.storage[3]; +} + + double ExternalFloat64Array::get_scalar(int index) { ASSERT((index >= 0) && (index < this->length())); double* ptr = static_cast(external_pointer()); @@ -3650,6 +3781,10 @@ int FixedTypedArrayBase::size() { case FIXED_FLOAT64_ARRAY_TYPE: element_size = 8; break; + case FIXED_FLOAT32x4_ARRAY_TYPE: + case FIXED_INT32x4_ARRAY_TYPE: + element_size = 16; + break; default: UNREACHABLE(); return 0; @@ -3710,6 +3845,51 @@ Handle FixedTypedArray::SetValue( Object); } +template<> inline +MaybeObject* FixedTypedArray::SetValue( + uint32_t index, Object* value) { + float32x4_value_t cast_value; + cast_value.storage[0] = static_cast(OS::nan_value()); + cast_value.storage[1] = static_cast(OS::nan_value()); + cast_value.storage[2] = static_cast(OS::nan_value()); + cast_value.storage[3] = static_cast(OS::nan_value()); + Heap* heap = GetHeap(); + if (index < static_cast(length())) { + if (value->IsFloat32x4()) { + cast_value = Float32x4::cast(value)->value(); + } else { + // Clamp undefined to NaN (default). All other types have been + // converted to a number type further up in the call chain. + ASSERT(value->IsUndefined()); + } + set(index, cast_value); + } + return heap->AllocateFloat32x4(cast_value); +} + + +template<> inline +MaybeObject* FixedTypedArray::SetValue( + uint32_t index, Object* value) { + int32x4_value_t cast_value; + cast_value.storage[0] = 0; + cast_value.storage[1] = 0; + cast_value.storage[2] = 0; + cast_value.storage[3] = 0; + Heap* heap = GetHeap(); + if (index < static_cast(length())) { + if (value->IsInt32x4()) { + cast_value = Int32x4::cast(value)->value(); + } else { + // Clamp undefined to zero (default). All other types have been + // converted to a number type further up in the call chain. + ASSERT(value->IsUndefined()); + } + set(index, cast_value); + } + return heap->AllocateInt32x4(cast_value); +} + MaybeObject* Uint8ArrayTraits::ToObject(Heap*, uint8_t scalar) { return Smi::FromInt(scalar); @@ -3751,6 +3931,17 @@ MaybeObject* Float32ArrayTraits::ToObject(Heap* heap, float scalar) { } +MaybeObject* Int32x4ArrayTraits::ToObject(Heap* heap, int32x4_value_t scalar) { + return heap->AllocateInt32x4(scalar); +} + + +MaybeObject* Float32x4ArrayTraits::ToObject( + Heap* heap, float32x4_value_t scalar) { + return heap->AllocateFloat32x4(scalar); +} + + MaybeObject* Float64ArrayTraits::ToObject(Heap* heap, double scalar) { return heap->NumberFromDouble(scalar); } diff --git a/src/objects-printer.cc b/src/objects-printer.cc index 909d8f74210..865bd1b2b7f 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -92,6 +92,12 @@ void HeapObject::HeapObjectPrint(FILE* out) { case HEAP_NUMBER_TYPE: HeapNumber::cast(this)->HeapNumberPrint(out); break; + case FLOAT32x4_TYPE: + Float32x4::cast(this)->Float32x4Print(out); + break; + case INT32x4_TYPE: + Int32x4::cast(this)->Int32x4Print(out); + break; case FIXED_DOUBLE_ARRAY_TYPE: FixedDoubleArray::cast(this)->FixedDoubleArrayPrint(out); break; @@ -301,6 +307,30 @@ static void DoPrintDoubleElements(FILE* out, Object* object) { } +template +static void DoPrintFloat32x4Elements(FILE* out, Object* object) { + T* p = T::cast(object); + for (int i = 0; i < p->length(); i++) { + float32x4_value_t value = p->get_scalar(i); + PrintF(out, " %d: (%f, %f, %f, %f)\n", + i, value.storage[0], value.storage[1], + value.storage[2], value.storage[3]); + } +} + + +template +static void DoPrintInt32x4Elements(FILE* out, Object* object) { + T* p = T::cast(object); + for (int i = 0; i < p->length(); i++) { + int32x4_value_t value = p->get_scalar(i); + PrintF(out, " %d: (%d, %d, %d, %d)\n", + i, value.storage[0], value.storage[1], + value.storage[2], value.storage[3]); + } +} + + void JSObject::PrintElements(FILE* out) { // Don't call GetElementsKind, its validation code can cause the printer to // fail when debugging. @@ -348,6 +378,18 @@ void JSObject::PrintElements(FILE* out) { break; \ } +#define PRINT_FLOAT32x4_ELEMENTS(Kind, Type) \ + case Kind: { \ + DoPrintFloat32x4Elements(out, elements()); \ + break; \ + } + +#define PRINT_INT32x4_ELEMENTS(Kind, Type) \ + case Kind: { \ + DoPrintInt32x4Elements(out, elements()); \ + break; \ + } + PRINT_ELEMENTS(EXTERNAL_UINT8_CLAMPED_ELEMENTS, ExternalUint8ClampedArray) PRINT_ELEMENTS(EXTERNAL_INT8_ELEMENTS, ExternalInt8Array) PRINT_ELEMENTS(EXTERNAL_UINT8_ELEMENTS, @@ -360,6 +402,9 @@ void JSObject::PrintElements(FILE* out) { ExternalUint32Array) PRINT_DOUBLE_ELEMENTS(EXTERNAL_FLOAT32_ELEMENTS, ExternalFloat32Array) PRINT_DOUBLE_ELEMENTS(EXTERNAL_FLOAT64_ELEMENTS, ExternalFloat64Array) + PRINT_FLOAT32x4_ELEMENTS(EXTERNAL_FLOAT32x4_ELEMENTS, + ExternalFloat32x4Array) + PRINT_INT32x4_ELEMENTS(EXTERNAL_INT32x4_ELEMENTS, ExternalInt32x4Array) PRINT_ELEMENTS(UINT8_ELEMENTS, FixedUint8Array) @@ -371,6 +416,8 @@ void JSObject::PrintElements(FILE* out) { PRINT_ELEMENTS(INT32_ELEMENTS, FixedInt32Array) PRINT_DOUBLE_ELEMENTS(FLOAT32_ELEMENTS, FixedFloat32Array) PRINT_DOUBLE_ELEMENTS(FLOAT64_ELEMENTS, FixedFloat64Array) + PRINT_FLOAT32x4_ELEMENTS(FLOAT32x4_ELEMENTS, FixedFloat32x4Array) + PRINT_INT32x4_ELEMENTS(INT32x4_ELEMENTS, FixedInt32x4Array) #undef PRINT_DOUBLE_ELEMENTS #undef PRINT_ELEMENTS diff --git a/src/objects-visiting.cc b/src/objects-visiting.cc index 16c51676b50..bf67259f1ec 100644 --- a/src/objects-visiting.cc +++ b/src/objects-visiting.cc @@ -171,6 +171,8 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( return kVisitJSFunction; case HEAP_NUMBER_TYPE: + case FLOAT32x4_TYPE: + case INT32x4_TYPE: #define EXTERNAL_ARRAY_CASE(Type, type, TYPE, ctype, size) \ case EXTERNAL_##TYPE##_ARRAY_TYPE: @@ -187,6 +189,8 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( case FIXED_UINT32_ARRAY_TYPE: case FIXED_INT32_ARRAY_TYPE: case FIXED_FLOAT32_ARRAY_TYPE: + case FIXED_INT32x4_ARRAY_TYPE: + case FIXED_FLOAT32x4_ARRAY_TYPE: case FIXED_UINT8_CLAMPED_ARRAY_TYPE: return kVisitFixedTypedArray; diff --git a/src/objects.cc b/src/objects.cc index 731d602b47a..1f08b31d489 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -76,6 +76,10 @@ MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor, MaybeObject* Object::ToObject(Context* native_context) { if (IsNumber()) { return CreateJSValue(native_context->number_function(), this); + } else if (IsFloat32x4()) { + return CreateJSValue(native_context->float32x4_function(), this); + } else if (IsInt32x4()) { + return CreateJSValue(native_context->int32x4_function(), this); } else if (IsBoolean()) { return CreateJSValue(native_context->boolean_function(), this); } else if (IsString()) { @@ -92,6 +96,14 @@ MaybeObject* Object::ToObject(Isolate* isolate) { } else if (IsNumber()) { Context* native_context = isolate->context()->native_context(); return CreateJSValue(native_context->number_function(), this); + } else if (IsFloat32x4()) { + Isolate* isolate = HeapObject::cast(this)->GetIsolate(); + Context* native_context = isolate->context()->native_context(); + return CreateJSValue(native_context->float32x4_function(), this); + } else if (IsInt32x4()) { + Isolate* isolate = HeapObject::cast(this)->GetIsolate(); + Context* native_context = isolate->context()->native_context(); + return CreateJSValue(native_context->int32x4_function(), this); } else if (IsBoolean()) { Context* native_context = isolate->context()->native_context(); return CreateJSValue(native_context->boolean_function(), this); @@ -138,6 +150,10 @@ void Object::Lookup(Name* name, LookupResult* result) { Context* native_context = result->isolate()->context()->native_context(); if (IsNumber()) { holder = native_context->number_function()->instance_prototype(); + } else if (IsFloat32x4()) { + holder = native_context->float32x4_function()->instance_prototype(); + } else if (IsInt32x4()) { + holder = native_context->int32x4_function()->instance_prototype(); } else if (IsString()) { holder = native_context->string_function()->instance_prototype(); } else if (IsSymbol()) { @@ -987,6 +1003,10 @@ MaybeObject* Object::GetElementWithReceiver(Isolate* isolate, Context* native_context = isolate->context()->native_context(); if (holder->IsNumber()) { holder = native_context->number_function()->instance_prototype(); + } else if (holder->IsFloat32x4()) { + holder = native_context->float32x4_function()->instance_prototype(); + } else if (holder->IsInt32x4()) { + holder = native_context->int32x4_function()->instance_prototype(); } else if (holder->IsString()) { holder = native_context->string_function()->instance_prototype(); } else if (holder->IsSymbol()) { @@ -1050,6 +1070,12 @@ Object* Object::GetPrototype(Isolate* isolate) { if (heap_object->IsHeapNumber()) { return context->number_function()->instance_prototype(); } + if (heap_object->IsFloat32x4()) { + return context->float32x4_function()->instance_prototype(); + } + if (heap_object->IsInt32x4()) { + return context->int32x4_function()->instance_prototype(); + } if (heap_object->IsString()) { return context->string_function()->instance_prototype(); } @@ -1709,6 +1735,16 @@ void HeapObject::HeapObjectShortPrint(StringStream* accumulator) { HeapNumber::cast(this)->HeapNumberPrint(accumulator); accumulator->Put('>'); break; + case FLOAT32x4_TYPE: + accumulator->Add("Float32x4Print(accumulator); + accumulator->Put('>'); + break; + case INT32x4_TYPE: + accumulator->Add("Int32x4Print(accumulator); + accumulator->Put('>'); + break; case JS_PROXY_TYPE: accumulator->Add(""); break; @@ -1832,6 +1868,8 @@ void HeapObject::IterateBody(InstanceType type, int object_size, break; case HEAP_NUMBER_TYPE: + case FLOAT32x4_TYPE: + case INT32x4_TYPE: case FILLER_TYPE: case BYTE_ARRAY_TYPE: case FREE_SPACE_TYPE: @@ -1905,6 +1943,42 @@ void HeapNumber::HeapNumberPrint(StringStream* accumulator) { } +void Float32x4::Float32x4Print(FILE* out) { + PrintF(out, "%.16g %.16g %.16g %.16g", x(), y(), z(), w()); +} + + +void Float32x4::Float32x4Print(StringStream* accumulator) { + // The Windows version of vsnprintf can allocate when printing a %g string + // into a buffer that may not be big enough. We don't want random memory + // allocation when producing post-crash stack traces, so we print into a + // buffer that is plenty big enough for any floating point number, then + // print that using vsnprintf (which may truncate but never allocate if + // there is no more space in the buffer). + EmbeddedVector buffer; + OS::SNPrintF(buffer, "%.16g %.16g %.16g %.16g", x(), y(), z(), w()); + accumulator->Add("%s", buffer.start()); +} + + +void Int32x4::Int32x4Print(FILE* out) { + PrintF(out, "%u %u %u %u", x(), y(), z(), w()); +} + + +void Int32x4::Int32x4Print(StringStream* accumulator) { + // The Windows version of vsnprintf can allocate when printing a %g string + // into a buffer that may not be big enough. We don't want random memory + // allocation when producing post-crash stack traces, so we print into a + // buffer that is plenty big enough for any floating point number, then + // print that using vsnprintf (which may truncate but never allocate if + // there is no more space in the buffer). + EmbeddedVector buffer; + OS::SNPrintF(buffer, "%u %u %u %u", x(), y(), z(), w()); + accumulator->Add("%s", buffer.start()); +} + + String* JSReceiver::class_name() { if (IsJSFunction() && IsJSFunctionProxy()) { return GetHeap()->function_class_string(); @@ -12492,7 +12566,10 @@ Handle JSObject::SetElement(Handle object, Isolate* isolate = object->GetIsolate(); if (object->HasExternalArrayElements()) { - if (!value->IsNumber() && !value->IsUndefined()) { + // TODO(ningxin): Throw an error if setting a Float32x4Array element + // while the value is not Float32x4Object. + if (!value->IsNumber() && !value->IsFloat32x4() && + !value->IsInt32x4() && !value->IsUndefined()) { bool has_exception; Handle number = Execution::ToNumber(isolate, value, &has_exception); @@ -14759,6 +14836,66 @@ MaybeObject* ExternalFloat64Array::SetValue(uint32_t index, Object* value) { } +Handle ExternalFloat32x4Array::SetValue( + Handle array, + uint32_t index, + Handle value) { + CALL_HEAP_FUNCTION(array->GetIsolate(), + array->SetValue(index, *value), + Object); +} + + +MaybeObject* ExternalFloat32x4Array::SetValue(uint32_t index, Object* value) { + float32x4_value_t cast_value; + cast_value.storage[0] = static_cast(OS::nan_value()); + cast_value.storage[1] = static_cast(OS::nan_value()); + cast_value.storage[2] = static_cast(OS::nan_value()); + cast_value.storage[3] = static_cast(OS::nan_value()); + Heap* heap = GetHeap(); + if (index < static_cast(length())) { + if (value->IsFloat32x4()) { + cast_value = Float32x4::cast(value)->value(); + } else { + // Clamp undefined to NaN (default). All other types have been + // converted to a number type further up in the call chain. + ASSERT(value->IsUndefined()); + } + set(index, cast_value); + } + return heap->AllocateFloat32x4(cast_value); +} + + +Handle ExternalInt32x4Array::SetValue( + Handle array, uint32_t index, Handle value) { + CALL_HEAP_FUNCTION(array->GetIsolate(), + array->SetValue(index, *value), + Object); +} + + +MaybeObject* ExternalInt32x4Array::SetValue(uint32_t index, Object* value) { + int32x4_value_t cast_value; + cast_value.storage[0] = 0; + cast_value.storage[1] = 0; + cast_value.storage[2] = 0; + cast_value.storage[3] = 0; + Heap* heap = GetHeap(); + if (index < static_cast(length())) { + if (value->IsInt32x4()) { + cast_value = Int32x4::cast(value)->value(); + } else { + // Clamp undefined to zero (default). All other types have been + // converted to a number type further up in the call chain. + ASSERT(value->IsUndefined()); + } + set(index, cast_value); + } + return heap->AllocateInt32x4(cast_value); +} + + PropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) { ASSERT(!HasFastProperties()); Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry()); diff --git a/src/objects.h b/src/objects.h index c6f36bf63bd..73923b9aca8 100644 --- a/src/objects.h +++ b/src/objects.h @@ -104,6 +104,8 @@ // - ExternalInt32Array // - ExternalUint32Array // - ExternalFloat32Array +// - ExternalFloat32x4Array +// - ExternalInt32x4Array // - Name // - String // - SeqString @@ -124,6 +126,8 @@ // - ExternalTwoByteInternalizedString // - Symbol // - HeapNumber +// - Float32x4 +// - Int32x4 // - Cell // - PropertyCell // - Code @@ -371,6 +375,8 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; V(PROPERTY_CELL_TYPE) \ \ V(HEAP_NUMBER_TYPE) \ + V(FLOAT32x4_TYPE) \ + V(INT32x4_TYPE) \ V(FOREIGN_TYPE) \ V(BYTE_ARRAY_TYPE) \ V(FREE_SPACE_TYPE) \ @@ -384,6 +390,8 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; V(EXTERNAL_INT32_ARRAY_TYPE) \ V(EXTERNAL_UINT32_ARRAY_TYPE) \ V(EXTERNAL_FLOAT32_ARRAY_TYPE) \ + V(EXTERNAL_FLOAT32x4_ARRAY_TYPE) \ + V(EXTERNAL_INT32x4_ARRAY_TYPE) \ V(EXTERNAL_FLOAT64_ARRAY_TYPE) \ V(EXTERNAL_UINT8_CLAMPED_ARRAY_TYPE) \ \ @@ -392,8 +400,10 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; V(FIXED_INT16_ARRAY_TYPE) \ V(FIXED_UINT16_ARRAY_TYPE) \ V(FIXED_INT32_ARRAY_TYPE) \ + V(FIXED_INT32x4_ARRAY_TYPE) \ V(FIXED_UINT32_ARRAY_TYPE) \ V(FIXED_FLOAT32_ARRAY_TYPE) \ + V(FIXED_FLOAT32x4_ARRAY_TYPE) \ V(FIXED_FLOAT64_ARRAY_TYPE) \ V(FIXED_UINT8_CLAMPED_ARRAY_TYPE) \ \ @@ -719,6 +729,8 @@ enum InstanceType { // "Data", objects that cannot contain non-map-word pointers to heap // objects. HEAP_NUMBER_TYPE, + FLOAT32x4_TYPE, + INT32x4_TYPE, FOREIGN_TYPE, BYTE_ARRAY_TYPE, FREE_SPACE_TYPE, @@ -730,6 +742,8 @@ enum InstanceType { EXTERNAL_INT32_ARRAY_TYPE, EXTERNAL_UINT32_ARRAY_TYPE, EXTERNAL_FLOAT32_ARRAY_TYPE, + EXTERNAL_FLOAT32x4_ARRAY_TYPE, + EXTERNAL_INT32x4_ARRAY_TYPE, EXTERNAL_FLOAT64_ARRAY_TYPE, EXTERNAL_UINT8_CLAMPED_ARRAY_TYPE, // LAST_EXTERNAL_ARRAY_TYPE @@ -738,8 +752,10 @@ enum InstanceType { FIXED_INT16_ARRAY_TYPE, FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, + FIXED_INT32x4_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE, FIXED_FLOAT32_ARRAY_TYPE, + FIXED_FLOAT32x4_ARRAY_TYPE, FIXED_FLOAT64_ARRAY_TYPE, FIXED_UINT8_CLAMPED_ARRAY_TYPE, // LAST_FIXED_TYPED_ARRAY_TYPE @@ -991,6 +1007,8 @@ class MaybeObject BASE_EMBEDDED { #define HEAP_OBJECT_TYPE_LIST(V) \ V(HeapNumber) \ + V(Float32x4) \ + V(Int32x4) \ V(Name) \ V(UniqueName) \ V(String) \ @@ -1013,6 +1031,8 @@ class MaybeObject BASE_EMBEDDED { V(ExternalInt32Array) \ V(ExternalUint32Array) \ V(ExternalFloat32Array) \ + V(ExternalFloat32x4Array) \ + V(ExternalInt32x4Array) \ V(ExternalFloat64Array) \ V(ExternalUint8ClampedArray) \ V(FixedTypedArrayBase) \ @@ -1023,6 +1043,8 @@ class MaybeObject BASE_EMBEDDED { V(FixedUint32Array) \ V(FixedInt32Array) \ V(FixedFloat32Array) \ + V(FixedFloat32x4Array) \ + V(FixedInt32x4Array) \ V(FixedFloat64Array) \ V(FixedUint8ClampedArray) \ V(ByteArray) \ @@ -1944,6 +1966,82 @@ class HeapNumber: public HeapObject { }; +class Float32x4: public HeapObject { + public: + typedef float32x4_value_t value_t; + static const int kLanes = 4; + static const int kValueSize = kFloat32x4Size; + static const InstanceType kInstanceType = FLOAT32x4_TYPE; + static inline int kRuntimeAllocatorId(); + static inline int kMapRootIndex(); + + // [value]: float32x4 value. + inline float32x4_value_t value(); + inline void set_value(float32x4_value_t value); + + // Casting. + static inline Float32x4* cast(Object* obj); + + inline void Float32x4Print() { + Float32x4Print(stdout); + } + void Float32x4Print(FILE* out); + void Float32x4Print(StringStream* accumulator); + DECLARE_VERIFIER(Float32x4) + + inline float getAt(int index); + inline float x() { return getAt(0); } + inline float y() { return getAt(1); } + inline float z() { return getAt(2); } + inline float w() { return getAt(3); } + + // Layout description. + static const int kValueOffset = HeapObject::kHeaderSize; + static const int kSize = kValueOffset + kValueSize; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Float32x4); +}; + + +class Int32x4: public HeapObject { + public: + typedef int32x4_value_t value_t; + static const int kValueSize = kInt32x4Size; + static const InstanceType kInstanceType = INT32x4_TYPE; + static inline int kRuntimeAllocatorId(); + static inline int kMapRootIndex(); + + // [value]: int32x4 value. + inline int32x4_value_t value(); + inline void set_value(int32x4_value_t value); + + // Casting. + static inline Int32x4* cast(Object* obj); + + inline void Int32x4Print() { + Int32x4Print(stdout); + } + void Int32x4Print(FILE* out); + void Int32x4Print(StringStream* accumulator); + DECLARE_VERIFIER(Int32x4) + + static const int kLanes = 4; + inline int32_t getAt(int32_t index); + inline int32_t x() { return getAt(0); } + inline int32_t y() { return getAt(1); } + inline int32_t z() { return getAt(2); } + inline int32_t w() { return getAt(3); } + + // Layout description. + static const int kValueOffset = HeapObject::kHeaderSize; + static const int kSize = kValueOffset + kValueSize; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Int32x4); +}; + + enum EnsureElementsMode { DONT_ALLOW_DOUBLE_ELEMENTS, ALLOW_COPIED_DOUBLE_ELEMENTS, @@ -2153,6 +2251,8 @@ class JSObject: public JSReceiver { inline bool HasExternalInt32Elements(); inline bool HasExternalUint32Elements(); inline bool HasExternalFloat32Elements(); + inline bool HasExternalFloat32x4Elements(); + inline bool HasExternalInt32x4Elements(); inline bool HasExternalFloat64Elements(); inline bool HasFixedTypedArrayElements(); @@ -4579,6 +4679,8 @@ class FreeSpace: public HeapObject { V(Int32, int32, INT32, int32_t, 4) \ V(Float32, float32, FLOAT32, float, 4) \ V(Float64, float64, FLOAT64, double, 8) \ + V(Float32x4, float32x4, FLOAT32x4, v8::internal::float32x4_value_t, 16) \ + V(Int32x4, int32x4, INT32x4, v8::internal::int32x4_value_t, 16) \ V(Uint8Clamped, uint8_clamped, UINT8_CLAMPED, uint8_t, 1) @@ -4845,6 +4947,59 @@ class ExternalFloat32Array: public ExternalArray { }; +class ExternalFloat32x4Array: public ExternalArray { + public: + // Setter and getter. + inline float32x4_value_t get_scalar(int index); + MUST_USE_RESULT inline MaybeObject* get(int index); + inline void set(int index, const float32x4_value_t& value); + + static Handle SetValue(Handle array, + uint32_t index, + Handle value); + + // This accessor applies the correct conversion from Smi, HeapNumber + // and undefined. + MUST_USE_RESULT MaybeObject* SetValue(uint32_t index, Object* value); + + // Casting. + static inline ExternalFloat32x4Array* cast(Object* obj); + + // Dispatched behavior. + DECLARE_PRINTER(ExternalFloat32x4Array) + DECLARE_VERIFIER(ExternalFloat32x4Array) + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalFloat32x4Array); +}; + + +class ExternalInt32x4Array: public ExternalArray { + public: + // Setter and getter. + inline int32x4_value_t get_scalar(int index); + MUST_USE_RESULT inline MaybeObject* get(int index); + inline void set(int index, const int32x4_value_t& value); + + static Handle SetValue(Handle array, + uint32_t index, + Handle value); + // This accessor applies the correct conversion from Smi, HeapNumber + // and undefined. + MUST_USE_RESULT MaybeObject* SetValue(uint32_t index, Object* value); + + // Casting. + static inline ExternalInt32x4Array* cast(Object* obj); + + // Dispatched behavior. + DECLARE_PRINTER(ExternalInt32x4Array) + DECLARE_VERIFIER(ExternalInt32x4Array) + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalInt32x4Array); +}; + + class ExternalFloat64Array: public ExternalArray { public: // Setter and getter. @@ -4925,7 +5080,7 @@ class FixedTypedArray: public FixedTypedArrayBase { static const InstanceType kInstanceType = FIXED_##TYPE##_ARRAY_TYPE; \ static const char* Designator() { return #type " array"; } \ static inline MaybeObject* ToObject(Heap* heap, elementType scalar); \ - static elementType defaultValue() { return 0; } \ + static elementType defaultValue() { return elementType(); } \ }; \ \ typedef FixedTypedArray Fixed##Type##Array; @@ -6639,6 +6794,7 @@ class Script: public Struct { V(Math, min, MathMin) \ V(Math, imul, MathImul) + enum BuiltinFunctionId { kArrayCode, #define DECLARE_FUNCTION_ID(ignored1, ignore2, name) \ @@ -7674,7 +7830,8 @@ class JSBuiltinsObject: public GlobalObject { }; -// Representation for JS Wrapper objects, String, Number, Boolean, etc. +// Representation for JS Wrapper objects, String, Number, Float32x4, Int32x4, +// Boolean, etc. class JSValue: public JSObject { public: // [value]: the object being wrapped. diff --git a/src/property-details.h b/src/property-details.h index 5f0920b6705..99dd1211b24 100644 --- a/src/property-details.h +++ b/src/property-details.h @@ -94,6 +94,8 @@ class Representation { kSmi, kInteger32, kDouble, + kFloat32x4, + kInt32x4, kHeapObject, kTagged, kExternal, @@ -111,6 +113,8 @@ class Representation { static Representation Smi() { return Representation(kSmi); } static Representation Integer32() { return Representation(kInteger32); } static Representation Double() { return Representation(kDouble); } + static Representation Float32x4() { return Representation(kFloat32x4); } + static Representation Int32x4() { return Representation(kInt32x4); } static Representation HeapObject() { return Representation(kHeapObject); } static Representation External() { return Representation(kExternal); } @@ -138,7 +142,10 @@ class Representation { ASSERT(kind_ != kExternal); ASSERT(other.kind_ != kExternal); - if (IsHeapObject()) return other.IsDouble() || other.IsNone(); + if (IsHeapObject()) { + return other.IsDouble() || other.IsFloat32x4() || other.IsInt32x4() || + other.IsNone(); + } if (kind_ == kUInteger8 && other.kind_ == kInteger8) return false; if (kind_ == kUInteger16 && other.kind_ == kInteger16) return false; return kind_ > other.kind_; @@ -180,6 +187,8 @@ class Representation { bool IsInteger32() const { return kind_ == kInteger32; } bool IsSmiOrInteger32() const { return IsSmi() || IsInteger32(); } bool IsDouble() const { return kind_ == kDouble; } + bool IsFloat32x4() const { return kind_ == kFloat32x4; } + bool IsInt32x4() const { return kind_ == kInt32x4; } bool IsHeapObject() const { return kind_ == kHeapObject; } bool IsExternal() const { return kind_ == kExternal; } bool IsSpecialization() const { diff --git a/src/runtime.cc b/src/runtime.cc index a2bc186d61a..72f88120857 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -5197,7 +5197,10 @@ Handle Runtime::SetObjectProperty(Isolate* isolate, js_object->ValidateElements(); if (js_object->HasExternalArrayElements() || js_object->HasFixedTypedArrayElements()) { - if (!value->IsNumber() && !value->IsUndefined()) { + // TODO(ningxin): Throw an error if setting a Float32x4Array element + // while the value is not Float32x4Object. + if (!value->IsNumber() && !value->IsFloat32x4() && + !value->IsInt32x4() && !value->IsUndefined()) { bool has_exception; Handle number = Execution::ToNumber(isolate, value, &has_exception); @@ -5217,7 +5220,10 @@ Handle Runtime::SetObjectProperty(Isolate* isolate, Handle name = Handle::cast(key); if (name->AsArrayIndex(&index)) { if (js_object->HasExternalArrayElements()) { - if (!value->IsNumber() && !value->IsUndefined()) { + // TODO(ningxin): Throw an error if setting a Float32x4Array element + // while the value is not Float32x4Object. + if (!value->IsNumber() && !value->IsFloat32x4() && + !value->IsInt32x4() && !value->IsUndefined()) { bool has_exception; Handle number = Execution::ToNumber(isolate, value, &has_exception); @@ -6025,6 +6031,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) { Object* obj = args[0]; if (obj->IsNumber()) return isolate->heap()->number_string(); + if (obj->IsFloat32x4()) return isolate->heap()->float32x4_string(); + if (obj->IsInt32x4()) return isolate->heap()->int32x4_string(); HeapObject* heap_obj = HeapObject::cast(obj); // typeof an undetectable object is 'undefined' @@ -6892,6 +6900,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) { } +RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateFloat32x4) { + SealHandleScope shs(isolate); + ASSERT(args.length() == 0); + + float32x4_value_t zero = {{0, 0, 0, 0}}; + return isolate->heap()->AllocateFloat32x4(zero); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInt32x4) { + SealHandleScope shs(isolate); + ASSERT(args.length() == 0); + + int32x4_value_t zero = {{0, 0, 0, 0}}; + return isolate->heap()->AllocateInt32x4(zero); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) { SealHandleScope shs(isolate); ASSERT(args.length() == 2); @@ -10035,6 +10061,38 @@ static void IterateExternalArrayElements(Isolate* isolate, } +static void IterateExternalFloat32x4ArrayElements(Isolate* isolate, + Handle receiver, + ArrayConcatVisitor* visitor) { + Handle array( + ExternalFloat32x4Array::cast(receiver->elements())); + uint32_t len = static_cast(array->length()); + + ASSERT(visitor != NULL); + for (uint32_t j = 0; j < len; j++) { + HandleScope loop_scope(isolate); + Handle e = isolate->factory()->NewFloat32x4(array->get_scalar(j)); + visitor->visit(j, e); + } +} + + +static void IterateExternalInt32x4ArrayElements(Isolate* isolate, + Handle receiver, + ArrayConcatVisitor* visitor) { + Handle array( + ExternalInt32x4Array::cast(receiver->elements())); + uint32_t len = static_cast(array->length()); + + ASSERT(visitor != NULL); + for (uint32_t j = 0; j < len; j++) { + HandleScope loop_scope(isolate); + Handle e = isolate->factory()->NewInt32x4(array->get_scalar(j)); + visitor->visit(j, e); + } +} + + // Used for sorting indices in a List. static int compareUInt32(const uint32_t* ap, const uint32_t* bp) { uint32_t a = *ap; @@ -10259,6 +10317,14 @@ static bool IterateElements(Isolate* isolate, isolate, receiver, false, false, visitor); break; } + case EXTERNAL_FLOAT32x4_ELEMENTS: { + IterateExternalFloat32x4ArrayElements(isolate, receiver, visitor); + break; + } + case EXTERNAL_INT32x4_ELEMENTS: { + IterateExternalInt32x4ArrayElements(isolate, receiver, visitor); + break; + } case EXTERNAL_FLOAT64_ELEMENTS: { IterateExternalArrayElements( isolate, receiver, false, false, visitor); @@ -14751,6 +14817,568 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_MaxSmi) { } +#define RETURN_Float32x4_RESULT(value) \ + Float32x4* float32x4; \ + MaybeObject* maybe = isolate->heap()->AllocateFloat32x4(value); \ + if (!maybe->To(&float32x4)) return maybe; \ + return float32x4; + + +#define RETURN_Int32x4_RESULT(value) \ + Int32x4* int32x4; \ + MaybeObject* maybe = isolate->heap()->AllocateInt32x4(value); \ + if (!maybe->To(&int32x4)) return maybe; \ + return int32x4; + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateFloat32x4) { + HandleScope scope(isolate); + ASSERT(args.length() == 4); + RUNTIME_ASSERT(args[0]->IsNumber()); + RUNTIME_ASSERT(args[1]->IsNumber()); + RUNTIME_ASSERT(args[2]->IsNumber()); + RUNTIME_ASSERT(args[3]->IsNumber()); + + float32x4_value_t value; + value.storage[0] = static_cast(args.number_at(0)); + value.storage[1] = static_cast(args.number_at(1)); + value.storage[2] = static_cast(args.number_at(2)); + value.storage[3] = static_cast(args.number_at(3)); + + RETURN_Float32x4_RESULT(value); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateInt32x4) { + HandleScope scope(isolate); + ASSERT(args.length() == 4); + RUNTIME_ASSERT(args[0]->IsNumber()); + RUNTIME_ASSERT(args[1]->IsNumber()); + RUNTIME_ASSERT(args[2]->IsNumber()); + RUNTIME_ASSERT(args[3]->IsNumber()); + + int32x4_value_t value; + value.storage[0] = NumberToInt32(args[0]); + value.storage[1] = NumberToInt32(args[1]); + value.storage[2] = NumberToInt32(args[2]); + value.storage[3] = NumberToInt32(args[3]); + + RETURN_Int32x4_RESULT(value); +} + + +// Used to convert between uint32_t and float32 without breaking strict +// aliasing rules. +union float32_uint32 { + float f; + uint32_t u; + float32_uint32(float v) { + f = v; + } + float32_uint32(uint32_t v) { + u = v; + } +}; + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_Float32x4GetSignMask) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_CHECKED(Float32x4, self, 0); + float32_uint32 x(self->x()); + float32_uint32 y(self->y()); + float32_uint32 z(self->z()); + float32_uint32 w(self->w()); + uint32_t mx = (x.u & 0x80000000) >> 31; + uint32_t my = (y.u & 0x80000000) >> 31; + uint32_t mz = (z.u & 0x80000000) >> 31; + uint32_t mw = (w.u & 0x80000000) >> 31; + uint32_t value = mx | (my << 1) | (mz << 2) | (mw << 3); + return isolate->heap()->NumberFromUint32(value); +} + + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_Int32x4GetSignMask) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_CHECKED(Int32x4, self, 0); + uint32_t mx = (self->x() & 0x80000000) >> 31; + uint32_t my = (self->y() & 0x80000000) >> 31; + uint32_t mz = (self->z() & 0x80000000) >> 31; + uint32_t mw = (self->w() & 0x80000000) >> 31; + uint32_t value = mx | (my << 1) | (mz << 2) | (mw << 3); + return isolate->heap()->NumberFromUint32(value); +} + + +#define LANE_VALUE(VALUE, LANE) \ + VALUE->LANE() + + +#define LANE_FLAG(VALUE, LANE) \ + VALUE->LANE() != 0 + + +#define SIMD128_LANE_ACCESS_FUNCTIONS(V) \ + V(Float32x4, GetX, AllocateHeapNumber, x, LANE_VALUE) \ + V(Float32x4, GetY, AllocateHeapNumber, y, LANE_VALUE) \ + V(Float32x4, GetZ, AllocateHeapNumber, z, LANE_VALUE) \ + V(Float32x4, GetW, AllocateHeapNumber, w, LANE_VALUE) \ + V(Int32x4, GetX, NumberFromInt32, x, LANE_VALUE) \ + V(Int32x4, GetY, NumberFromInt32, y, LANE_VALUE) \ + V(Int32x4, GetZ, NumberFromInt32, z, LANE_VALUE) \ + V(Int32x4, GetW, NumberFromInt32, w, LANE_VALUE) \ + V(Int32x4, GetFlagX, ToBoolean, x, LANE_FLAG) \ + V(Int32x4, GetFlagY, ToBoolean, y, LANE_FLAG) \ + V(Int32x4, GetFlagZ, ToBoolean, z, LANE_FLAG) \ + V(Int32x4, GetFlagW, ToBoolean, w, LANE_FLAG) + + +#define DECLARE_SIMD_LANE_ACCESS_FUNCTION( \ + TYPE, NAME, HEAP_FUNCTION, LANE, ACCESS_FUNCTION) \ +RUNTIME_FUNCTION(MaybeObject*, Runtime_##TYPE##NAME) { \ + SealHandleScope shs(isolate); \ + ASSERT(args.length() == 1); \ + \ + CONVERT_ARG_CHECKED(TYPE, a, 0); \ + \ + return isolate->heap()->HEAP_FUNCTION( \ + ACCESS_FUNCTION(a, LANE)); \ +} + + +SIMD128_LANE_ACCESS_FUNCTIONS(DECLARE_SIMD_LANE_ACCESS_FUNCTION) + + +template +static inline T Neg(T a) { + return -a; +} + + +template +static inline T Not(T a) { + return ~a; +} + + +template +static inline T Reciprocal(T a) { + UNIMPLEMENTED(); +} + + +template<> +inline float Reciprocal(float a) { + return 1.0f / a; +} + + +template +static inline T ReciprocalSqrt(T a) { + UNIMPLEMENTED(); +} + + +template<> +inline float ReciprocalSqrt(float a) { + return sqrtf(1.0f / a); +} + + +template +static inline T Sqrt(T a) { + UNIMPLEMENTED(); +} + + +template<> +inline float Sqrt(float a) { + return sqrtf(a); +} + + +#define SIMD128_UNARY_FUNCTIONS(V) \ + V(Float32x4, Abs) \ + V(Float32x4, Neg) \ + V(Float32x4, Reciprocal) \ + V(Float32x4, ReciprocalSqrt) \ + V(Float32x4, Sqrt) \ + V(Int32x4, Neg) \ + V(Int32x4, Not) + + +#define DECLARE_SIMD_UNARY_FUNCTION(TYPE, FUNCTION) \ +RUNTIME_FUNCTION(MaybeObject*, Runtime_##TYPE##FUNCTION) { \ + SealHandleScope shs(isolate); \ + ASSERT(args.length() == 1); \ + \ + CONVERT_ARG_CHECKED(TYPE, a, 0); \ + \ + TYPE::value_t result; \ + for (int i = 0; i < TYPE::kLanes; i++) { \ + result.storage[i] = FUNCTION(a->getAt(i)); \ + } \ + \ + RETURN_##TYPE##_RESULT(result); \ +} + + +SIMD128_UNARY_FUNCTIONS(DECLARE_SIMD_UNARY_FUNCTION) + + +template +inline void BitsTo(T1 s, T2* t) { + memcpy(t, &s, sizeof(T2)); +} + + +template +inline void To(T1 s, T2* t) { +} + + +template<> +inline void To(int32_t s, float* t) { + *t = static_cast(s); +} + + +template<> +inline void To(float s, int32_t* t) { + *t = DoubleToInt32(static_cast(s)); +} + + +#define SIMD128_CONVERSION_FUNCTIONS(V) \ + V(Float32x4, BitsTo, Int32x4) \ + V(Float32x4, To, Int32x4) \ + V(Int32x4, BitsTo, Float32x4) \ + V(Int32x4, To, Float32x4) + + +#define DECLARE_SIMD_CONVERSION_FUNCTION( \ + SOURCE_TYPE, FUNCTION, TARGET_TYPE) \ +RUNTIME_FUNCTION(MaybeObject*, \ + Runtime_##SOURCE_TYPE##FUNCTION##TARGET_TYPE) { \ + SealHandleScope shs(isolate); \ + ASSERT(args.length() == 1); \ + \ + CONVERT_ARG_CHECKED(SOURCE_TYPE, a, 0); \ + \ + TARGET_TYPE::value_t result; \ + for (int i = 0; i < SOURCE_TYPE::kLanes; i++) { \ + FUNCTION(a->getAt(i), &result.storage[i]); \ + } \ + \ + RETURN_##TARGET_TYPE##_RESULT(result); \ +} + + +SIMD128_CONVERSION_FUNCTIONS(DECLARE_SIMD_CONVERSION_FUNCTION) + + +template +static inline T Add(T a, T b) { + return a + b; +} + + +template +static inline T Div(T a, T b) { + return a / b; +} + + +template +static inline T Mul(T a, T b) { + return a * b; +} + + +template +static inline T Sub(T a, T b) { + return a - b; +} + + +template +static inline int32_t Equal(T a, T b) { + return a == b ? -1 : 0; +} + + +template +static inline int32_t NotEqual(T a, T b) { + return a != b ? -1 : 0; +} + + +template +static inline int32_t GreaterThanOrEqual(T a, T b) { + return a >= b ? -1 : 0; +} + + +template +static inline int32_t GreaterThan(T a, T b) { + return a > b ? -1 : 0; +} + + +template +static inline int32_t LessThan(T a, T b) { + return a < b ? -1 : 0; +} + + +template +static inline int32_t LessThanOrEqual(T a, T b) { + return a <= b ? -1 : 0; +} + + +template +static inline T And(T a, T b) { + return a & b; +} + + +template +static inline T Or(T a, T b) { + return a | b; +} + + +template +static inline T Xor(T a, T b) { + return a ^ b; +} + + +#define SIMD128_BINARY_FUNCTIONS(V) \ + V(Float32x4, Add, Float32x4) \ + V(Float32x4, Div, Float32x4) \ + V(Float32x4, Max, Float32x4) \ + V(Float32x4, Min, Float32x4) \ + V(Float32x4, Mul, Float32x4) \ + V(Float32x4, Sub, Float32x4) \ + V(Float32x4, Equal, Int32x4) \ + V(Float32x4, NotEqual, Int32x4) \ + V(Float32x4, GreaterThanOrEqual, Int32x4) \ + V(Float32x4, GreaterThan, Int32x4) \ + V(Float32x4, LessThan, Int32x4) \ + V(Float32x4, LessThanOrEqual, Int32x4) \ + V(Int32x4, Add, Int32x4) \ + V(Int32x4, And, Int32x4) \ + V(Int32x4, Mul, Int32x4) \ + V(Int32x4, Or, Int32x4) \ + V(Int32x4, Sub, Int32x4) \ + V(Int32x4, Xor, Int32x4) \ + V(Int32x4, Equal, Int32x4) \ + V(Int32x4, GreaterThan, Int32x4) \ + V(Int32x4, LessThan, Int32x4) + + +#define DECLARE_SIMD_BINARY_FUNCTION( \ + TYPE, FUNCTION, RETURN_TYPE) \ +RUNTIME_FUNCTION(MaybeObject*, Runtime_##TYPE##FUNCTION) { \ + SealHandleScope shs(isolate); \ + ASSERT(args.length() == 2); \ + \ + CONVERT_ARG_CHECKED(TYPE, a, 0); \ + CONVERT_ARG_CHECKED(TYPE, b, 1); \ + \ + RETURN_TYPE::value_t result; \ + for (int i = 0; i < TYPE::kLanes; i++) { \ + result.storage[i] = FUNCTION(a->getAt(i), b->getAt(i)); \ + } \ + \ + RETURN_##RETURN_TYPE##_RESULT(result); \ +} + + +SIMD128_BINARY_FUNCTIONS(DECLARE_SIMD_BINARY_FUNCTION) + + +#define SIMD128_SHUFFLE_FUNCTIONS(V) \ + V(Float32x4) \ + V(Int32x4) + + +#define DECLARE_SIMD_SHUFFLE_FUNCTION(TYPE) \ +RUNTIME_FUNCTION(MaybeObject*, Runtime_##TYPE##Shuffle) { \ + SealHandleScope shs(isolate); \ + ASSERT(args.length() == 2); \ + \ + CONVERT_ARG_CHECKED(TYPE, a, 0); \ + RUNTIME_ASSERT(args[1]->IsNumber()); \ + uint32_t m = NumberToUint32(args[1]); \ + \ + TYPE::value_t result; \ + for (int i = 0; i < TYPE::kLanes; i++) { \ + result.storage[i] = a->getAt((m >> (i * 2)) & 0x3); \ + } \ + \ + RETURN_##TYPE##_RESULT(result); \ +} + + +SIMD128_SHUFFLE_FUNCTIONS(DECLARE_SIMD_SHUFFLE_FUNCTION) + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_Float32x4Scale) { + SealHandleScope shs(isolate); + ASSERT(args.length() == 2); + + CONVERT_ARG_CHECKED(Float32x4, self, 0); + RUNTIME_ASSERT(args[1]->IsNumber()); + + float _s = static_cast(args.number_at(1)); + float32x4_value_t result; + result.storage[0] = self->x() * _s; + result.storage[1] = self->y() * _s; + result.storage[2] = self->z() * _s; + result.storage[3] = self->w() * _s; + + RETURN_Float32x4_RESULT(result); +} + + +#define ARG_TO_FLOAT32(x) \ + CONVERT_DOUBLE_ARG_CHECKED(t, 1); \ + float x = static_cast(t); + + +#define ARG_TO_INT32(x) \ + RUNTIME_ASSERT(args[1]->IsNumber()); \ + int32_t x = NumberToInt32(args[1]); + + +#define ARG_TO_BOOLEAN(x) \ + CONVERT_BOOLEAN_ARG_CHECKED(flag, 1); \ + int32_t x = flag ? -1 : 0; + +#define SIMD128_SET_LANE_FUNCTIONS(V) \ + V(Float32x4, WithX, ARG_TO_FLOAT32, 0) \ + V(Float32x4, WithY, ARG_TO_FLOAT32, 1) \ + V(Float32x4, WithZ, ARG_TO_FLOAT32, 2) \ + V(Float32x4, WithW, ARG_TO_FLOAT32, 3) \ + V(Int32x4, WithX, ARG_TO_INT32, 0) \ + V(Int32x4, WithY, ARG_TO_INT32, 1) \ + V(Int32x4, WithZ, ARG_TO_INT32, 2) \ + V(Int32x4, WithW, ARG_TO_INT32, 3) \ + V(Int32x4, WithFlagX, ARG_TO_BOOLEAN, 0) \ + V(Int32x4, WithFlagY, ARG_TO_BOOLEAN, 1) \ + V(Int32x4, WithFlagZ, ARG_TO_BOOLEAN, 2) \ + V(Int32x4, WithFlagW, ARG_TO_BOOLEAN, 3) + + +#define DECLARE_SIMD_SET_LANE_FUNCTION( \ + TYPE, NAME, ARG_FUNCTION, LANE) \ +RUNTIME_FUNCTION(MaybeObject*, Runtime_##TYPE##NAME) { \ + SealHandleScope shs(isolate); \ + ASSERT(args.length() == 2); \ + \ + CONVERT_ARG_CHECKED(TYPE, a, 0); \ + ARG_FUNCTION(value); \ + \ + TYPE::value_t result; \ + for (int i = 0; i < TYPE::kLanes; i++) { \ + if (i != LANE) \ + result.storage[i] = a->getAt(i); \ + else \ + result.storage[i] = value; \ + } \ + \ + RETURN_##TYPE##_RESULT(result); \ +} + + +SIMD128_SET_LANE_FUNCTIONS(DECLARE_SIMD_SET_LANE_FUNCTION) + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_Float32x4Clamp) { + SealHandleScope shs(isolate); + ASSERT(args.length() == 3); + + CONVERT_ARG_CHECKED(Float32x4, self, 0); + CONVERT_ARG_CHECKED(Float32x4, lo, 1); + CONVERT_ARG_CHECKED(Float32x4, hi, 2); + + float32x4_value_t result; + float _x = self->x() > lo->x() ? self->x() : lo->x(); + float _y = self->y() > lo->y() ? self->y() : lo->y(); + float _z = self->z() > lo->z() ? self->z() : lo->z(); + float _w = self->w() > lo->w() ? self->w() : lo->w(); + result.storage[0] = _x > hi->x() ? hi->x() : _x; + result.storage[1] = _y > hi->y() ? hi->y() : _y; + result.storage[2] = _z > hi->z() ? hi->z() : _z; + result.storage[3] = _w > hi->w() ? hi->w() : _w; + + RETURN_Float32x4_RESULT(result); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_Float32x4ShuffleMix) { + SealHandleScope shs(isolate); + ASSERT(args.length() == 3); + + CONVERT_ARG_CHECKED(Float32x4, first, 0); + CONVERT_ARG_CHECKED(Float32x4, second, 1); + RUNTIME_ASSERT(args[2]->IsNumber()); + + uint32_t m = NumberToUint32(args[2]); + float32x4_value_t result; + float data1[4] = { first->x(), first->y(), first->z(), first->w() }; + float data2[4] = { second->x(), second->y(), second->z(), second->w() }; + result.storage[0] = data1[m & 0x3]; + result.storage[1] = data1[(m >> 2) & 0x3]; + result.storage[2] = data2[(m >> 4) & 0x3]; + result.storage[3] = data2[(m >> 6) & 0x3]; + + RETURN_Float32x4_RESULT(result); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_Int32x4Select) { + SealHandleScope shs(isolate); + ASSERT(args.length() == 3); + + CONVERT_ARG_CHECKED(Int32x4, self, 0); + CONVERT_ARG_CHECKED(Float32x4, tv, 1); + CONVERT_ARG_CHECKED(Float32x4, fv, 2); + + uint32_t _maskX = self->x(); + uint32_t _maskY = self->y(); + uint32_t _maskZ = self->z(); + uint32_t _maskW = self->w(); + // Extract floats and interpret them as masks. + float32_uint32 tvx(tv->x()); + float32_uint32 tvy(tv->y()); + float32_uint32 tvz(tv->z()); + float32_uint32 tvw(tv->w()); + float32_uint32 fvx(fv->x()); + float32_uint32 fvy(fv->y()); + float32_uint32 fvz(fv->z()); + float32_uint32 fvw(fv->w()); + // Perform select. + float32_uint32 tempX((_maskX & tvx.u) | (~_maskX & fvx.u)); + float32_uint32 tempY((_maskY & tvy.u) | (~_maskY & fvy.u)); + float32_uint32 tempZ((_maskZ & tvz.u) | (~_maskZ & fvz.u)); + float32_uint32 tempW((_maskW & tvw.u) | (~_maskW & fvw.u)); + + float32x4_value_t result; + result.storage[0] = tempX.f; + result.storage[1] = tempY.f; + result.storage[2] = tempZ.f; + result.storage[3] = tempW.f; + + RETURN_Float32x4_RESULT(result); +} + + // ---------------------------------------------------------------------------- // Implementation of Runtime diff --git a/src/runtime.h b/src/runtime.h index 532066f63eb..8f6019e631a 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -186,6 +186,62 @@ namespace internal { F(RoundNumber, 1, 1) \ F(Math_sqrt, 1, 1) \ \ + /* Float32x4 and Int32x4 */ \ + F(AllocateFloat32x4, 0, 1) \ + F(AllocateInt32x4, 0, 1) \ + \ + /* SIMD */ \ + F(Float32x4Abs, 1, 1) \ + F(Float32x4BitsToInt32x4, 1, 1) \ + F(Float32x4Neg, 1, 1) \ + F(Float32x4Reciprocal, 1, 1) \ + F(Float32x4ReciprocalSqrt, 1, 1) \ + F(Float32x4Sqrt, 1, 1) \ + F(Float32x4ToInt32x4, 1, 1) \ + F(Float32x4Add, 2, 1) \ + F(Float32x4Div, 2, 1) \ + F(Float32x4Max, 2, 1) \ + F(Float32x4Min, 2, 1) \ + F(Float32x4Mul, 2, 1) \ + F(Float32x4Sub, 2, 1) \ + F(Float32x4Equal, 2, 1) \ + F(Float32x4NotEqual, 2, 1) \ + F(Float32x4GreaterThanOrEqual, 2, 1) \ + F(Float32x4GreaterThan, 2, 1) \ + F(Float32x4LessThan, 2, 1) \ + F(Float32x4LessThanOrEqual, 2, 1) \ + F(Float32x4Shuffle, 2, 1) \ + F(Float32x4Scale, 2, 1) \ + F(Float32x4WithX, 2, 1) \ + F(Float32x4WithY, 2, 1) \ + F(Float32x4WithZ, 2, 1) \ + F(Float32x4WithW, 2, 1) \ + F(Float32x4Clamp, 3, 1) \ + F(Float32x4ShuffleMix, 3, 1) \ + F(Int32x4BitsToFloat32x4, 1, 1) \ + F(Int32x4Neg, 1, 1) \ + F(Int32x4Not, 1, 1) \ + F(Int32x4ToFloat32x4, 1, 1) \ + F(Int32x4And, 2, 1) \ + F(Int32x4Or, 2, 1) \ + F(Int32x4Xor, 2, 1) \ + F(Int32x4Add, 2, 1) \ + F(Int32x4Sub, 2, 1) \ + F(Int32x4Mul, 2, 1) \ + F(Int32x4Shuffle, 2, 1) \ + F(Int32x4WithX, 2, 1) \ + F(Int32x4WithY, 2, 1) \ + F(Int32x4WithZ, 2, 1) \ + F(Int32x4WithW, 2, 1) \ + F(Int32x4WithFlagX, 2, 1) \ + F(Int32x4WithFlagY, 2, 1) \ + F(Int32x4WithFlagZ, 2, 1) \ + F(Int32x4WithFlagW, 2, 1) \ + F(Int32x4GreaterThan, 2, 1) \ + F(Int32x4Equal, 2, 1) \ + F(Int32x4LessThan, 2, 1) \ + F(Int32x4Select, 3, 1) \ + \ /* Regular expressions */ \ F(RegExpCompile, 3, 1) \ F(RegExpExec, 4, 1) \ @@ -267,6 +323,24 @@ namespace internal { \ /* Numbers */ \ \ + /* Float32x4 and Int32x4 */ \ + F(CreateFloat32x4, 4, 1) \ + F(Float32x4GetX, 1, 1) \ + F(Float32x4GetY, 1, 1) \ + F(Float32x4GetZ, 1, 1) \ + F(Float32x4GetW, 1, 1) \ + F(Float32x4GetSignMask, 1, 1) \ + F(CreateInt32x4, 4, 1) \ + F(Int32x4GetX, 1, 1) \ + F(Int32x4GetY, 1, 1) \ + F(Int32x4GetZ, 1, 1) \ + F(Int32x4GetW, 1, 1) \ + F(Int32x4GetFlagX, 1, 1) \ + F(Int32x4GetFlagY, 1, 1) \ + F(Int32x4GetFlagZ, 1, 1) \ + F(Int32x4GetFlagW, 1, 1) \ + F(Int32x4GetSignMask, 1, 1) \ + \ /* Globals */ \ F(CompileString, 2, 1) \ F(GlobalPrint, 1, 1) \ @@ -470,6 +544,8 @@ namespace internal { F(HasExternalInt32Elements, 1, 1) \ F(HasExternalUint32Elements, 1, 1) \ F(HasExternalFloat32Elements, 1, 1) \ + F(HasExternalFloat32x4Elements, 1, 1) \ + F(HasExternalInt32x4Elements, 1, 1) \ F(HasExternalFloat64Elements, 1, 1) \ F(HasFastProperties, 1, 1) \ F(TransitionElementsKind, 2, 1) \ @@ -839,7 +915,9 @@ class Runtime : public AllStatic { ARRAY_ID_INT32 = 6, ARRAY_ID_FLOAT32 = 7, ARRAY_ID_FLOAT64 = 8, - ARRAY_ID_UINT8_CLAMPED = 9 + ARRAY_ID_UINT8_CLAMPED = 9, + ARRAY_ID_FLOAT32x4 = 10, + ARRAY_ID_INT32x4 = 11 }; static void ArrayIdToTypeAndSize(int array_id, diff --git a/src/runtime.js b/src/runtime.js index 2a949ae8d1d..9ed48278208 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -538,6 +538,8 @@ function NonNumberToNumber(x) { if (IS_BOOLEAN(x)) return x ? 1 : 0; if (IS_UNDEFINED(x)) return NAN; if (IS_SYMBOL(x)) return NAN; + if (IsFloat32x4(x)) return NaN; + if (IsInt32x4(x)) return NaN; return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x)); } diff --git a/src/simd128.js b/src/simd128.js new file mode 100644 index 00000000000..becc7d02011 --- /dev/null +++ b/src/simd128.js @@ -0,0 +1,865 @@ +// Copyright 2013 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. + +"use strict"; + +// This file relies on the fact that the following declaration has been made +// in runtime.js: +// var $Array = global.Array; + +var $SIMD = global.SIMD; +var $Float32x4 = $SIMD.float32x4; +var $Int32x4 = $SIMD.int32x4; + +macro SIMD128_DATA_TYPES(FUNCTION) +FUNCTION(Float32x4, float32x4) +FUNCTION(Int32x4, int32x4) +endmacro + +macro DECLARE_DATA_TYPE_COMMON_FUNCTION(NAME, TYPE) +function ThrowNAMETypeError() { + throw MakeTypeError("this is not a TYPE value."); +} + +function NAMEToString() { + if (IsNAMEWrapper(this)) { + return ObjectToString.apply(this); + } else if (IsNAME(this)) { + return "TYPE(" + this.x + "," + this.y + "," + this.z + "," + this.w + ")"; + } else { + throw MakeTypeError('TYPE_to_string'); + } +} + +function NAMEValueOf() { + if (!IsNAME(this) && !IsNAMEWrapper(this)) { + ThrowNAMETypeError(); + } + return %_ValueOf(this); +} +endmacro + +SIMD128_DATA_TYPES(DECLARE_DATA_TYPE_COMMON_FUNCTION) + +macro SIMD128_DATA_TYPE_FUNCTIONS(FUNCTION) +FUNCTION(Float32x4, GetX) +FUNCTION(Float32x4, GetY) +FUNCTION(Float32x4, GetZ) +FUNCTION(Float32x4, GetW) +FUNCTION(Float32x4, GetSignMask) +FUNCTION(Int32x4, GetX) +FUNCTION(Int32x4, GetY) +FUNCTION(Int32x4, GetZ) +FUNCTION(Int32x4, GetW) +FUNCTION(Int32x4, GetFlagX) +FUNCTION(Int32x4, GetFlagY) +FUNCTION(Int32x4, GetFlagZ) +FUNCTION(Int32x4, GetFlagW) +FUNCTION(Int32x4, GetSignMask) +endmacro + +macro DECLARE_DATA_TYPE_FUNCTION(TYPE, FUNCTION) +function TYPEFUNCTION() { + var x4 = ToTYPE(this); + CheckTYPE(x4); + return %TYPEFUNCTION(x4); +} +endmacro + +SIMD128_DATA_TYPE_FUNCTIONS(DECLARE_DATA_TYPE_FUNCTION) + +function Float32x4Constructor(x, y, z, w) { + x = TO_NUMBER_INLINE(x); + y = TO_NUMBER_INLINE(y); + z = TO_NUMBER_INLINE(z); + w = TO_NUMBER_INLINE(w); + + var value = %CreateFloat32x4(x, y, z, w); + if (%_IsConstructCall()) { + %_SetValueOf(this, value); + } else { + return value; + } +} + +function Int32x4Constructor(x, y, z, w) { + x = TO_INT32(x); + y = TO_INT32(y); + z = TO_INT32(z); + w = TO_INT32(w); + + var value = %CreateInt32x4(x, y, z, w); + if (%_IsConstructCall()) { + %_SetValueOf(this, value); + } else { + return value; + } +} + +function SetUpFloat32x4() { + %CheckIsBootstrapping(); + + %SetCode($Float32x4, Float32x4Constructor); + + %FunctionSetPrototype($Float32x4, new $Float32x4(0.0, 0.0, 0.0, 0.0)); + %SetProperty($Float32x4.prototype, "constructor", $Float32x4, DONT_ENUM); + + InstallGetter($Float32x4.prototype, "x", Float32x4GetX); + InstallGetter($Float32x4.prototype, "y", Float32x4GetY); + InstallGetter($Float32x4.prototype, "z", Float32x4GetZ); + InstallGetter($Float32x4.prototype, "w", Float32x4GetW); + InstallGetter($Float32x4.prototype, "signMask", Float32x4GetSignMask); + InstallFunctions($Float32x4.prototype, DONT_ENUM, $Array( + "toString", Float32x4ToString, + "valueOf", Float32x4ValueOf + )); +} + +function SetUpInt32x4() { + %CheckIsBootstrapping(); + + %SetCode($Int32x4, Int32x4Constructor); + + %FunctionSetPrototype($Int32x4, new $Int32x4(0, 0, 0, 0)); + %SetProperty($Int32x4.prototype, "constructor", $Int32x4, DONT_ENUM); + + InstallGetter($Int32x4.prototype, "x", Int32x4GetX); + InstallGetter($Int32x4.prototype, "y", Int32x4GetY); + InstallGetter($Int32x4.prototype, "z", Int32x4GetZ); + InstallGetter($Int32x4.prototype, "w", Int32x4GetW); + InstallGetter($Int32x4.prototype, "flagX", Int32x4GetFlagX); + InstallGetter($Int32x4.prototype, "flagY", Int32x4GetFlagY); + InstallGetter($Int32x4.prototype, "flagZ", Int32x4GetFlagZ); + InstallGetter($Int32x4.prototype, "flagW", Int32x4GetFlagW); + InstallGetter($Int32x4.prototype, "signMask", Int32x4GetSignMask); + InstallFunctions($Int32x4.prototype, DONT_ENUM, $Array( + "toString", Int32x4ToString, + "valueOf", Int32x4ValueOf + )); +} + +SetUpFloat32x4(); +SetUpInt32x4(); + +//------------------------------------------------------------------------------ + +macro SIMD128_UNARY_FUNCTIONS(FUNCTION) +FUNCTION(Float32x4, Abs) +FUNCTION(Float32x4, BitsToInt32x4) +FUNCTION(Float32x4, Neg) +FUNCTION(Float32x4, Reciprocal) +FUNCTION(Float32x4, ReciprocalSqrt) +FUNCTION(Float32x4, Sqrt) +FUNCTION(Float32x4, ToInt32x4) +FUNCTION(Int32x4, BitsToFloat32x4) +FUNCTION(Int32x4, Neg) +FUNCTION(Int32x4, Not) +FUNCTION(Int32x4, ToFloat32x4) +endmacro + +macro SIMD128_BINARY_FUNCTIONS(FUNCTION) +FUNCTION(Float32x4, Add) +FUNCTION(Float32x4, Div) +FUNCTION(Float32x4, Max) +FUNCTION(Float32x4, Min) +FUNCTION(Float32x4, Mul) +FUNCTION(Float32x4, Sub) +FUNCTION(Float32x4, Equal) +FUNCTION(Float32x4, NotEqual) +FUNCTION(Float32x4, GreaterThanOrEqual) +FUNCTION(Float32x4, GreaterThan) +FUNCTION(Float32x4, LessThan) +FUNCTION(Float32x4, LessThanOrEqual) +FUNCTION(Int32x4, Add) +FUNCTION(Int32x4, And) +FUNCTION(Int32x4, Mul) +FUNCTION(Int32x4, Or) +FUNCTION(Int32x4, Sub) +FUNCTION(Int32x4, Xor) +FUNCTION(Int32x4, Equal) +FUNCTION(Int32x4, GreaterThan) +FUNCTION(Int32x4, LessThan) +endmacro + +macro SIMD128_BINARY_SHUFFLE_FUNCTIONS(FUNCTION) +FUNCTION(Float32x4) +FUNCTION(Int32x4) +endmacro + +macro FLOAT32x4_BINARY_FUNCTIONS_WITH_FLOAT32_PARAMETER(FUNCTION) +FUNCTION(Scale) +FUNCTION(WithX) +FUNCTION(WithY) +FUNCTION(WithZ) +FUNCTION(WithW) +endmacro + +macro INT32x4_BINARY_FUNCTIONS_WITH_INT32_PARAMETER(FUNCTION) +FUNCTION(WithX) +FUNCTION(WithY) +FUNCTION(WithZ) +FUNCTION(WithW) +endmacro + +macro INT32x4_BINARY_FUNCTIONS_WITH_BOOLEAN_PARAMETER(FUNCTION) +FUNCTION(WithFlagX) +FUNCTION(WithFlagY) +FUNCTION(WithFlagZ) +FUNCTION(WithFlagW) +endmacro + +macro DECLARE_SIMD_UNARY_FUNCTION(TYPE, FUNCTION) +function TYPEFUNCTION(x4) { + x4 = ToTYPE(x4); + CheckTYPE(x4); + return %TYPEFUNCTION(x4); +} +endmacro + +macro DECLARE_SIMD_BINARY_FUNCTION(TYPE, FUNCTION) +function TYPEFUNCTION(a4, b4) { + a4 = ToTYPE(a4); + CheckTYPE(a4); + b4 = ToTYPE(b4); + CheckTYPE(b4); + return %TYPEFUNCTION(a4, b4); +} +endmacro + +macro DECLARE_SIMD_BINARY_SHUFFLE_FUNCTION(TYPE) +function TYPEShuffle(x4, mask) { + x4 = ToTYPE(x4); + CheckTYPE(x4); + var value = TO_INT32(mask); + if ((value < 0) || (value > 0xFF)) { + throw MakeRangeError("invalid_simd_shuffle_mask"); + } + return %TYPEShuffle(x4, mask); +} +endmacro + +macro DECLARE_FLOAT32x4_BINARY_FUNCTION_WITH_FLOAT32_PARAMETER(FUNCTION) +function Float32x4FUNCTION(x4, f) { + x4 = ToFloat32x4(x4); + CheckFloat32x4(x4); + f = TO_NUMBER_INLINE(f); + return %Float32x4FUNCTION(x4, f); +} +endmacro + +macro DECLARE_INT32x4_BINARY_FUNCTION_WITH_INT32_PARAMETER(FUNCTION) +function Int32x4FUNCTION(x4, i) { + x4 = ToInt32x4(x4); + CheckInt32x4(x4); + i = TO_INT32(i); + return %Int32x4FUNCTION(x4, i); +} +endmacro + +macro DECLARE_INT32x4_BINARY_FUNCTION_WITH_BOOLEAN_PARAMETER(FUNCTION) +function Int32x4FUNCTION(x4, b) { + x4 = ToInt32x4(x4); + CheckInt32x4(x4); + b = ToBoolean(b); + return %Int32x4FUNCTION(x4, b); +} +endmacro + +SIMD128_UNARY_FUNCTIONS(DECLARE_SIMD_UNARY_FUNCTION) +SIMD128_BINARY_FUNCTIONS(DECLARE_SIMD_BINARY_FUNCTION) +SIMD128_BINARY_SHUFFLE_FUNCTIONS(DECLARE_SIMD_BINARY_SHUFFLE_FUNCTION) +FLOAT32x4_BINARY_FUNCTIONS_WITH_FLOAT32_PARAMETER(DECLARE_FLOAT32x4_BINARY_FUNCTION_WITH_FLOAT32_PARAMETER) +INT32x4_BINARY_FUNCTIONS_WITH_INT32_PARAMETER(DECLARE_INT32x4_BINARY_FUNCTION_WITH_INT32_PARAMETER) +INT32x4_BINARY_FUNCTIONS_WITH_BOOLEAN_PARAMETER(DECLARE_INT32x4_BINARY_FUNCTION_WITH_BOOLEAN_PARAMETER) + +function Float32x4Splat(f) { + f = TO_NUMBER_INLINE(f); + return %CreateFloat32x4(f, f, f, f); +} + +function Float32x4Zero() { + return %CreateFloat32x4(0.0, 0.0, 0.0, 0.0); +} + +function Float32x4And(a4, b4) { + a4 = Float32x4BitsToInt32x4(a4); + b4 = Float32x4BitsToInt32x4(b4); + return Int32x4BitsToFloat32x4(Int32x4And(a4, b4)); +} + +function Float32x4Or(a4, b4) { + a4 = Float32x4BitsToInt32x4(a4); + b4 = Float32x4BitsToInt32x4(b4); + return Int32x4BitsToFloat32x4(Int32x4Or(a4, b4)); +} + +function Float32x4XOr(a4, b4) { + a4 = Float32x4BitsToInt32x4(a4); + b4 = Float32x4BitsToInt32x4(b4); + return Int32x4BitsToFloat32x4(Int32x4Xor(a4, b4)); +} + +function Float32x4Not(x4) { + x4 = Float32x4BitsToInt32x4(x4); + return Int32x4BitsToFloat32x4(Int32x4Not(x4)); +} + +function Float32x4Clamp(x4, lowerLimit, upperLimit) { + x4 = ToFloat32x4(x4); + CheckFloat32x4(x4); + lowerLimit = ToFloat32x4(lowerLimit); + CheckFloat32x4(lowerLimit); + upperLimit = ToFloat32x4(upperLimit); + CheckFloat32x4(upperLimit); + return %Float32x4Clamp(x4, lowerLimit, upperLimit); +} + +function Float32x4ShuffleMix(a4, b4, mask) { + a4 = ToFloat32x4(a4); + CheckFloat32x4(a4); + b4 = ToFloat32x4(b4); + CheckFloat32x4(b4); + var value = TO_INT32(mask); + if ((value < 0) || (value > 0xFF)) { + throw MakeRangeError("invalid_simd_shuffleMix_mask"); + } + return %Float32x4ShuffleMix(a4, b4, mask); +} + +function Int32x4Zero() { + return %CreateInt32x4(0, 0, 0, 0); +} + +function Int32x4Bool(x, y, z, w) { + x = x ? -1 : 0; + y = y ? -1 : 0; + z = z ? -1 : 0; + w = w ? -1 : 0; + return %CreateInt32x4(x, y, z, w); +} + +function Int32x4Splat(s) { + s = TO_INT32(s); + return %CreateInt32x4(s, s, s, s); +} + +function Int32x4Select(x4, trueValue, falseValue) { + x4 = ToInt32x4(x4); + CheckInt32x4(x4); + trueValue = ToFloat32x4(trueValue); + CheckFloat32x4(trueValue); + falseValue = ToFloat32x4(falseValue); + CheckFloat32x4(falseValue); + return %Int32x4Select(x4, trueValue, falseValue); +} + +function Int32x4ShiftLeft(t, s) { + t = ToInt32x4(t); + CheckInt32x4(t); + s = TO_NUMBER_INLINE(s); + var x = t.x << s; + var y = t.y << s; + var z = t.z << s; + var w = t.w << s; + return %CreateInt32x4(x, y, z, w); +} + +function Int32x4ShiftRight(t, s) { + t = ToInt32x4(t); + CheckInt32x4(t); + s = TO_NUMBER_INLINE(s); + var x = t.x >>> s; + var y = t.y >>> s; + var z = t.z >>> s; + var w = t.w >>> s; + return %CreateInt32x4(x, y, z, w); +} + +function Int32x4ShiftRightArithmetic(t, s) { + t = ToInt32x4(t); + CheckInt32x4(t); + s = TO_NUMBER_INLINE(s); + var x = t.x >> s; + var y = t.y >> s; + var z = t.z >> s; + var w = t.w >> s; + return %CreateInt32x4(x, y, z, w); +} + +function SetUpSIMD() { + %CheckIsBootstrapping(); + + %OptimizeObjectForAddingMultipleProperties($SIMD, 258); + %SetProperty($SIMD, "XXXX", 0x00, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXXY", 0x40, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXXZ", 0x80, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXXW", 0xC0, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXYX", 0x10, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXYY", 0x50, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXYZ", 0x90, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXYW", 0xD0, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXZX", 0x20, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXZY", 0x60, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXZZ", 0xA0, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXZW", 0xE0, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXWX", 0x30, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXWY", 0x70, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXWZ", 0xB0, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XXWW", 0xF0, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYXX", 0x04, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYXY", 0x44, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYXZ", 0x84, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYXW", 0xC4, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYYX", 0x14, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYYY", 0x54, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYYZ", 0x94, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYYW", 0xD4, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYZX", 0x24, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYZY", 0x64, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYZZ", 0xA4, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYZW", 0xE4, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYWX", 0x34, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYWY", 0x74, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYWZ", 0xB4, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XYWW", 0xF4, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZXX", 0x08, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZXY", 0x48, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZXZ", 0x88, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZXW", 0xC8, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZYX", 0x18, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZYY", 0x58, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZYZ", 0x98, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZYW", 0xD8, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZZX", 0x28, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZZY", 0x68, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZZZ", 0xA8, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZZW", 0xE8, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZWX", 0x38, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZWY", 0x78, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZWZ", 0xB8, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XZWW", 0xF8, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWXX", 0x0C, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWXY", 0x4C, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWXZ", 0x8C, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWXW", 0xCC, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWYX", 0x1C, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWYY", 0x5C, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWYZ", 0x9C, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWYW", 0xDC, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWZX", 0x2C, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWZY", 0x6C, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWZZ", 0xAC, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWZW", 0xEC, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWWX", 0x3C, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWWY", 0x7C, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWWZ", 0xBC, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "XWWW", 0xFC, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXXX", 0x01, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXXY", 0x41, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXXZ", 0x81, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXXW", 0xC1, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXYX", 0x11, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXYY", 0x51, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXYZ", 0x91, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXYW", 0xD1, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXZX", 0x21, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXZY", 0x61, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXZZ", 0xA1, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXZW", 0xE1, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXWX", 0x31, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXWY", 0x71, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXWZ", 0xB1, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YXWW", 0xF1, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYXX", 0x05, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYXY", 0x45, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYXZ", 0x85, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYXW", 0xC5, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYYX", 0x15, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYYY", 0x55, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYYZ", 0x95, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYYW", 0xD5, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYZX", 0x25, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYZY", 0x65, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYZZ", 0xA5, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYZW", 0xE5, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYWX", 0x35, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYWY", 0x75, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYWZ", 0xB5, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YYWW", 0xF5, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZXX", 0x09, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZXY", 0x49, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZXZ", 0x89, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZXW", 0xC9, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZYX", 0x19, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZYY", 0x59, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZYZ", 0x99, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZYW", 0xD9, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZZX", 0x29, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZZY", 0x69, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZZZ", 0xA9, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZZW", 0xE9, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZWX", 0x39, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZWY", 0x79, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZWZ", 0xB9, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YZWW", 0xF9, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWXX", 0x0D, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWXY", 0x4D, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWXZ", 0x8D, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWXW", 0xCD, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWYX", 0x1D, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWYY", 0x5D, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWYZ", 0x9D, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWYW", 0xDD, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWZX", 0x2D, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWZY", 0x6D, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWZZ", 0xAD, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWZW", 0xED, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWWX", 0x3D, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWWY", 0x7D, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWWZ", 0xBD, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "YWWW", 0xFD, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXXX", 0x02, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXXY", 0x42, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXXZ", 0x82, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXXW", 0xC2, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXYX", 0x12, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXYY", 0x52, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXYZ", 0x92, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXYW", 0xD2, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXZX", 0x22, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXZY", 0x62, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXZZ", 0xA2, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXZW", 0xE2, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXWX", 0x32, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXWY", 0x72, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXWZ", 0xB2, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZXWW", 0xF2, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYXX", 0x06, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYXY", 0x46, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYXZ", 0x86, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYXW", 0xC6, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYYX", 0x16, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYYY", 0x56, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYYZ", 0x96, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYYW", 0xD6, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYZX", 0x26, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYZY", 0x66, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYZZ", 0xA6, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYZW", 0xE6, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYWX", 0x36, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYWY", 0x76, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYWZ", 0xB6, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZYWW", 0xF6, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZXX", 0x0A, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZXY", 0x4A, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZXZ", 0x8A, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZXW", 0xCA, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZYX", 0x1A, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZYY", 0x5A, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZYZ", 0x9A, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZYW", 0xDA, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZZX", 0x2A, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZZY", 0x6A, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZZZ", 0xAA, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZZW", 0xEA, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZWX", 0x3A, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZWY", 0x7A, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZWZ", 0xBA, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZZWW", 0xFA, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWXX", 0x0E, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWXY", 0x4E, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWXZ", 0x8E, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWXW", 0xCE, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWYX", 0x1E, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWYY", 0x5E, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWYZ", 0x9E, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWYW", 0xDE, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWZX", 0x2E, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWZY", 0x6E, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWZZ", 0xAE, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWZW", 0xEE, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWWX", 0x3E, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWWY", 0x7E, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWWZ", 0xBE, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "ZWWW", 0xFE, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXXX", 0x03, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXXY", 0x43, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXXZ", 0x83, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXXW", 0xC3, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXYX", 0x13, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXYY", 0x53, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXYZ", 0x93, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXYW", 0xD3, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXZX", 0x23, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXZY", 0x63, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXZZ", 0xA3, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXZW", 0xE3, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXWX", 0x33, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXWY", 0x73, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXWZ", 0xB3, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WXWW", 0xF3, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYXX", 0x07, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYXY", 0x47, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYXZ", 0x87, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYXW", 0xC7, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYYX", 0x17, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYYY", 0x57, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYYZ", 0x97, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYYW", 0xD7, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYZX", 0x27, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYZY", 0x67, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYZZ", 0xA7, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYZW", 0xE7, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYWX", 0x37, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYWY", 0x77, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYWZ", 0xB7, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WYWW", 0xF7, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZXX", 0x0B, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZXY", 0x4B, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZXZ", 0x8B, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZXW", 0xCB, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZYX", 0x1B, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZYY", 0x5B, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZYZ", 0x9B, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZYW", 0xDB, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZZX", 0x2B, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZZY", 0x6B, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZZZ", 0xAB, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZZW", 0xEB, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZWX", 0x3B, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZWY", 0x7B, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZWZ", 0xBB, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WZWW", 0xFB, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWXX", 0x0F, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWXY", 0x4F, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWXZ", 0x8F, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWXW", 0xCF, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWYX", 0x1F, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWYY", 0x5F, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWYZ", 0x9F, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWYW", 0xDF, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWZX", 0x2F, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWZY", 0x6F, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWZZ", 0xAF, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWZW", 0xEF, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWWX", 0x3F, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWWY", 0x7F, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWWZ", 0xBF, DONT_ENUM | DONT_DELETE | READ_ONLY); + %SetProperty($SIMD, "WWWW", 0xFF, DONT_ENUM | DONT_DELETE | READ_ONLY); + + %ToFastProperties($SIMD); + + // Set up non-enumerable properties of the SIMD float32x4 object. + InstallFunctions($SIMD.float32x4, DONT_ENUM, $Array( + // Float32x4 operations + "splat", Float32x4Splat, + "zero", Float32x4Zero, + // Unary + "abs", Float32x4Abs, + "bitsToInt32x4", Float32x4BitsToInt32x4, + "neg", Float32x4Neg, + "reciprocal", Float32x4Reciprocal, + "reciprocalSqrt", Float32x4ReciprocalSqrt, + "sqrt", Float32x4Sqrt, + "toInt32x4", Float32x4ToInt32x4, + // Binary + "add", Float32x4Add, + "div", Float32x4Div, + "max", Float32x4Max, + "min", Float32x4Min, + "mul", Float32x4Mul, + "sub", Float32x4Sub, + "lessThan", Float32x4LessThan, + "lessThanOrEqual", Float32x4LessThanOrEqual, + "equal", Float32x4Equal, + "notEqual", Float32x4NotEqual, + "greaterThanOrEqual", Float32x4GreaterThanOrEqual, + "greaterThan", Float32x4GreaterThan, + "and", Float32x4And, + "or", Float32x4Or, + "xor", Float32x4XOr, + "not", Float32x4Not, + "scale", Float32x4Scale, + "withX", Float32x4WithX, + "withY", Float32x4WithY, + "withZ", Float32x4WithZ, + "withW", Float32x4WithW, + "shuffle", Float32x4Shuffle, + // Ternary + "clamp", Float32x4Clamp, + "shuffleMix", Float32x4ShuffleMix + )); + + // Set up non-enumerable properties of the SIMD int32x4 object. + InstallFunctions($SIMD.int32x4, DONT_ENUM, $Array( + // Int32x4 operations + "zero", Int32x4Zero, + "splat", Int32x4Splat, + "bool", Int32x4Bool, + // Unary + "bitsToFloat32x4", Int32x4BitsToFloat32x4, + "neg", Int32x4Neg, + "not", Int32x4Not, + "toFloat32x4", Int32x4ToFloat32x4, + // Binary + "add", Int32x4Add, + "and", Int32x4And, + "mul", Int32x4Mul, + "or", Int32x4Or, + "sub", Int32x4Sub, + "xor", Int32x4Xor, + "shuffle", Int32x4Shuffle, + "withX", Int32x4WithX, + "withY", Int32x4WithY, + "withZ", Int32x4WithZ, + "withW", Int32x4WithW, + "withFlagX", Int32x4WithFlagX, + "withFlagY", Int32x4WithFlagY, + "withFlagZ", Int32x4WithFlagZ, + "withFlagW", Int32x4WithFlagW, + "greaterThan", Int32x4GreaterThan, + "equal", Int32x4Equal, + "lessThan", Int32x4LessThan, + "shiftLeft", Int32x4ShiftLeft, + "shiftRight", Int32x4ShiftRight, + "shiftRightArithmetic", Int32x4ShiftRightArithmetic, + // Ternary + "select", Int32x4Select + )); + + %SetInlineBuiltinFlag(Float32x4And); + %SetInlineBuiltinFlag(Float32x4Or); + %SetInlineBuiltinFlag(Float32x4XOr); + %SetInlineBuiltinFlag(Float32x4Not); +} + +SetUpSIMD(); + +//------------------------------------------------------------------------------ + +macro FLOAT32x4OrINT32x4_TYPED_ARRAYS(FUNCTION) +// arrayIds below should be synchronized with Runtime_TypedArrayInitialize. +FUNCTION(10, Float32x4Array, 16) +FUNCTION(11, Int32x4Array, 16) +endmacro + +macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE) + function NAMEConstructor(arg1, arg2, arg3) { + function ConstructByArrayBuffer(obj, buffer, byteOffset, length) { + var offset = ToPositiveInteger(byteOffset, "invalid_typed_array_length") + + if (offset % ELEMENT_SIZE !== 0) { + throw MakeRangeError("invalid_typed_array_alignment", + "start offset", "NAME", ELEMENT_SIZE); + } + var bufferByteLength = %ArrayBufferGetByteLength(buffer); + if (offset > bufferByteLength) { + throw MakeRangeError("invalid_typed_array_offset"); + } + + var newByteLength; + var newLength; + if (IS_UNDEFINED(length)) { + if (bufferByteLength % ELEMENT_SIZE !== 0) { + throw MakeRangeError("invalid_typed_array_alignment", + "byte length", "NAME", ELEMENT_SIZE); + } + newByteLength = bufferByteLength - offset; + newLength = newByteLength / ELEMENT_SIZE; + } else { + var newLength = ToPositiveInteger(length, "invalid_typed_array_length"); + newByteLength = newLength * ELEMENT_SIZE; + } + if (offset + newByteLength > bufferByteLength) { + throw MakeRangeError("invalid_typed_array_length"); + } + %TypedArrayInitialize(obj, ARRAY_ID, buffer, offset, newByteLength); + } + + function ConstructByLength(obj, length) { + var l = ToPositiveInteger(length, "invalid_typed_array_length"); + var byteLength = l * ELEMENT_SIZE; + var buffer = new $ArrayBuffer(byteLength); + %TypedArrayInitialize(obj, ARRAY_ID, buffer, 0, byteLength); + } + + function ConstructByArrayLike(obj, arrayLike) { + var length = arrayLike.length; + var l = ToPositiveInteger(length, "invalid_typed_array_length"); + if(!%TypedArrayInitializeFromArrayLike(obj, ARRAY_ID, arrayLike, l)) { + for (var i = 0; i < l; i++) { + // It is crucial that we let any execptions from arrayLike[i] + // propagate outside the function. + obj[i] = arrayLike[i]; + } + } + } + + if (%_IsConstructCall()) { + if (IS_ARRAYBUFFER(arg1)) { + ConstructByArrayBuffer(this, arg1, arg2, arg3); + } else if (IS_NUMBER(arg1) || IS_STRING(arg1) || + IS_BOOLEAN(arg1) || IS_UNDEFINED(arg1)) { + ConstructByLength(this, arg1); + } else { + ConstructByArrayLike(this, arg1); + } + } else { + throw MakeTypeError("constructor_not_function", ["NAME"]) + } + } +endmacro + +FLOAT32x4OrINT32x4_TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTOR) + +macro DECLARE_TYPED_ARRAY_FUNCTION(NAME) +function NAMEArrayGet(i) { + return this[i]; +} + +function NAMEArraySet(i, v) { + v = ToNAME(v); + CheckNAME(v); + this[i] = v; +} + +function SetUpNAMEArray() { + // Keep synced with typedarray.js. + SetupTypedArray(global.NAMEArray, NAMEArrayConstructor, 16); + + InstallFunctions(global.NAMEArray.prototype, DONT_ENUM, $Array( + "getAt", NAMEArrayGet, + "setAt", NAMEArraySet + )); +} +endmacro + +DECLARE_TYPED_ARRAY_FUNCTION(Float32x4) +DECLARE_TYPED_ARRAY_FUNCTION(Int32x4) + +SetUpFloat32x4Array(); +SetUpInt32x4Array(); diff --git a/src/stub-cache.cc b/src/stub-cache.cc index f7155735562..ff92b3c8102 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -270,6 +270,10 @@ Handle StubCache::ComputeCallConstant(int argc, check = SYMBOL_CHECK; } else if (object->IsNumber()) { check = NUMBER_CHECK; + } else if (object->IsFloat32x4()) { + check = FLOAT32x4_CHECK; + } else if (object->IsInt32x4()) { + check = INT32x4_CHECK; } else if (object->IsBoolean()) { check = BOOLEAN_CHECK; } @@ -318,7 +322,8 @@ Handle StubCache::ComputeCallField(int argc, // because they may be represented as immediates without a // map. Instead, we check against the map in the holder. if (object->IsNumber() || object->IsSymbol() || - object->IsBoolean() || object->IsString()) { + object->IsBoolean() || object->IsString() || + object->IsFloat32x4() || object->IsInt32x4()) { object = holder; } @@ -356,7 +361,8 @@ Handle StubCache::ComputeCallInterceptor(int argc, // because they may be represented as immediates without a // map. Instead, we check against the map in the holder. if (object->IsNumber() || object->IsSymbol() || - object->IsBoolean() || object->IsString()) { + object->IsBoolean() || object->IsString() || + object->IsFloat32x4() || object->IsInt32x4()) { object = holder; } @@ -1321,6 +1327,10 @@ Register LoadStubCompiler::HandlerFrontendHeader( function_index = Context::SYMBOL_FUNCTION_INDEX; } else if (type->Is(HeapType::Number())) { function_index = Context::NUMBER_FUNCTION_INDEX; + } else if (type->Is(HeapType::Float32x4())) { + function_index = Context::FLOAT32x4_FUNCTION_INDEX; + } else if (type->Is(HeapType::Int32x4())) { + function_index = Context::INT32x4_FUNCTION_INDEX; } else if (type->Is(HeapType::Boolean())) { // Booleans use the generic oddball map, so an additional check is needed to // ensure the receiver is really a boolean. diff --git a/src/types.cc b/src/types.cc index 7867899d71d..820eb039831 100644 --- a/src/types.cc +++ b/src/types.cc @@ -202,6 +202,10 @@ int TypeImpl::LubBitset(i::Map* map) { return kOddball; case HEAP_NUMBER_TYPE: return kDouble; + case FLOAT32x4_TYPE: + return kFloat32x4; + case INT32x4_TYPE: + return kInt32x4; case JS_VALUE_TYPE: case JS_DATE_TYPE: case JS_OBJECT_TYPE: @@ -570,6 +574,8 @@ Representation Representation::FromType(Type* type) { if (type->Is(Type::Smi())) return Representation::Smi(); if (type->Is(Type::Signed32())) return Representation::Integer32(); if (type->Is(Type::Number())) return Representation::Double(); + if (type->Is(Type::Float32x4())) return Representation::Float32x4(); + if (type->Is(Type::Int32x4())) return Representation::Int32x4(); return Representation::Tagged(); } diff --git a/src/types.h b/src/types.h index 99a809dc10d..a8fd8cc0227 100644 --- a/src/types.h +++ b/src/types.h @@ -104,30 +104,32 @@ namespace internal { V(OtherSigned32, 1 << 4) \ V(Unsigned32, 1 << 5) \ V(Double, 1 << 6) \ - V(Symbol, 1 << 7) \ - V(InternalizedString, 1 << 8) \ - V(OtherString, 1 << 9) \ - V(Undetectable, 1 << 10) \ - V(Array, 1 << 11) \ - V(Function, 1 << 12) \ - V(RegExp, 1 << 13) \ - V(OtherObject, 1 << 14) \ - V(Proxy, 1 << 15) \ - V(Internal, 1 << 16) \ + V(Float32x4, 1 << 7) \ + V(Int32x4, 1 << 8) \ + V(Symbol, 1 << 9) \ + V(InternalizedString, 1 << 10) \ + V(OtherString, 1 << 11) \ + V(Undetectable, 1 << 12) \ + V(Array, 1 << 13) \ + V(Function, 1 << 14) \ + V(RegExp, 1 << 15) \ + V(OtherObject, 1 << 16) \ + V(Proxy, 1 << 17) \ + V(Internal, 1 << 18) \ \ - V(Oddball, kBoolean | kNull | kUndefined) \ - V(Signed32, kSmi | kOtherSigned32) \ - V(Number, kSigned32 | kUnsigned32 | kDouble) \ - V(String, kInternalizedString | kOtherString) \ - V(UniqueName, kSymbol | kInternalizedString) \ - V(Name, kSymbol | kString) \ - V(NumberOrString, kNumber | kString) \ - V(Object, kUndetectable | kArray | kFunction | \ - kRegExp | kOtherObject) \ - V(Receiver, kObject | kProxy) \ - V(Allocated, kDouble | kName | kReceiver) \ - V(Any, kOddball | kNumber | kAllocated | kInternal) \ - V(NonNumber, kAny - kNumber) \ + V(Oddball, kBoolean | kNull | kUndefined) \ + V(Signed32, kSmi | kOtherSigned32) \ + V(Number, kSigned32 | kUnsigned32 | kDouble) \ + V(String, kInternalizedString | kOtherString) \ + V(UniqueName, kSymbol | kInternalizedString) \ + V(Name, kSymbol | kString) \ + V(NumberOrString, kNumber | kString) \ + V(Object, kUndetectable | kArray | kFunction | \ + kRegExp | kOtherObject) \ + V(Receiver, kObject | kProxy) \ + V(Allocated, kDouble | kFloat32x4 | kInt32x4 | kName | kReceiver) \ + V(Any, kOddball | kNumber | kAllocated | kInternal) \ + V(NonNumber, kAny - kNumber) \ V(Detectable, kAllocated - kUndetectable) diff --git a/src/v8globals.h b/src/v8globals.h index ac05ca9d862..61ea2b4af45 100644 --- a/src/v8globals.h +++ b/src/v8globals.h @@ -284,6 +284,8 @@ enum CheckType { STRING_CHECK, SYMBOL_CHECK, NUMBER_CHECK, + FLOAT32x4_CHECK, + INT32x4_CHECK, BOOLEAN_CHECK }; diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h index 9692ec02f98..d4a51cd4dd9 100644 --- a/src/x64/assembler-x64.h +++ b/src/x64/assembler-x64.h @@ -394,6 +394,7 @@ enum ScaleFactor { times_2 = 1, times_4 = 2, times_8 = 3, + maximal_scale_factor = times_8, times_int_size = times_4, times_pointer_size = times_8 }; diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index c4aedd4b684..1c75165443a 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -4516,6 +4516,14 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset)); __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); Split(equal, if_true, if_false, fall_through); + } else if (check->Equals(isolate()->heap()->float32x4_string())) { + __ JumpIfSmi(rax, if_false); + __ CmpObjectType(rax, FLOAT32x4_TYPE, rdx); + Split(equal, if_true, if_false, fall_through); + } else if (check->Equals(isolate()->heap()->int32x4_string())) { + __ JumpIfSmi(rax, if_false); + __ CmpObjectType(rax, INT32x4_TYPE, rdx); + Split(equal, if_true, if_false, fall_through); } else if (check->Equals(isolate()->heap()->string_string())) { __ JumpIfSmi(rax, if_false); // Check for undetectable objects => false. diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 17ded772bc8..4717a8b9f85 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -2936,6 +2936,95 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { } +void LCodeGen::DoDeferredSIMD128ToTagged(LInstruction* instr, + Runtime::FunctionId id) { + // TODO(3095996): Get rid of this. For now, we need to make the + // result register contain a valid pointer because it is already + // contained in the register pointer map. + Register reg = ToRegister(instr->result()); + __ Move(reg, Smi::FromInt(0)); + + { + PushSafepointRegistersScope scope(this); + __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); + __ CallRuntimeSaveDoubles(id); + RecordSafepointWithRegisters( + instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); + __ movp(kScratchRegister, rax); + } + __ movp(reg, kScratchRegister); +} + + +void LCodeGen::HandleExternalArrayOpRequiresPreScale( + LOperand* key, + ElementsKind elements_kind) { + if (ExternalArrayOpRequiresPreScale(elements_kind)) { + int pre_shift_size = ElementsKindToShiftSize(elements_kind) - + static_cast(maximal_scale_factor); + ASSERT(pre_shift_size > 0); + __ shl(ToRegister(key), Immediate(pre_shift_size)); + } +} + + +template +void LCodeGen::DoLoadKeyedSIMD128ExternalArray(LLoadKeyed* instr) { + class DeferredSIMD128ToTagged V8_FINAL : public LDeferredCode { + public: + DeferredSIMD128ToTagged(LCodeGen* codegen, + LInstruction* instr, + Runtime::FunctionId id) + : LDeferredCode(codegen), instr_(instr), id_(id) { } + virtual void Generate() V8_OVERRIDE { + codegen()->DoDeferredSIMD128ToTagged(instr_, id_); + } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } + private: + LInstruction* instr_; + Runtime::FunctionId id_; + }; + + // Pre scale key if necessary. + LOperand* key = instr->key(); + ElementsKind elements_kind = instr->elements_kind(); + if (!key->IsConstantOperand()) { + HandleExternalArrayOpRequiresPreScale(key, elements_kind); + } + + // Allocate a SIMD128 object on the heap. + Register reg = ToRegister(instr->result()); + DeferredSIMD128ToTagged* deferred = + new(zone()) DeferredSIMD128ToTagged(this, instr, + static_cast(T::kRuntimeAllocatorId())); + if (FLAG_inline_new) { + __ AllocateSIMDHeapObject(Float32x4::kSize, reg, kScratchRegister, + deferred->entry(), + static_cast(T::kMapRootIndex())); + } else { + __ jmp(deferred->entry()); + } + __ bind(deferred->exit()); + + // Copy the SIMD128 value from the external array to the heap object. + STATIC_ASSERT(T::kValueSize % kPointerSize == 0); + int base_offset = instr->is_fixed_typed_array() + ? FixedTypedArrayBase::kDataOffset - kHeapObjectTag + : 0; + for (int offset = 0; offset < T::kValueSize; offset += kPointerSize) { + Operand operand(BuildFastArrayOperand( + instr->elements(), + key, + elements_kind, + base_offset + offset, + instr->additional_index())); + __ movp(kScratchRegister, operand); + __ movp(FieldOperand(reg, Float32x4::kValueOffset + offset), + kScratchRegister); + } +} + + void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { ElementsKind elements_kind = instr->elements_kind(); LOperand* key = instr->key(); @@ -2970,6 +3059,10 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) { __ movsd(ToDoubleRegister(instr->result()), operand); + } else if (IsFloat32x4ElementsKind(elements_kind)) { + DoLoadKeyedSIMD128ExternalArray(instr); + } else if (IsInt32x4ElementsKind(elements_kind)) { + DoLoadKeyedSIMD128ExternalArray(instr); } else { Register result(ToRegister(instr->result())); switch (elements_kind) { @@ -3005,8 +3098,12 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { break; case EXTERNAL_FLOAT32_ELEMENTS: case EXTERNAL_FLOAT64_ELEMENTS: + case EXTERNAL_FLOAT32x4_ELEMENTS: + case EXTERNAL_INT32x4_ELEMENTS: case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: + case FLOAT32x4_ELEMENTS: + case INT32x4_ELEMENTS: case FAST_ELEMENTS: case FAST_SMI_ELEMENTS: case FAST_DOUBLE_ELEMENTS: @@ -3141,6 +3238,10 @@ Operand LCodeGen::BuildFastArrayOperand( ((constant_value + additional_index) << shift_size) + offset); } else { + if (ExternalArrayOpRequiresPreScale(elements_kind)) { + // Make sure the key is pre-scaled against maximal_scale_factor. + shift_size = static_cast(maximal_scale_factor); + } ScaleFactor scale_factor = static_cast(shift_size); return Operand(elements_pointer_reg, ToRegister(key), @@ -4128,6 +4229,42 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { } +template +void LCodeGen::DoStoreKeyedSIMD128ExternalArray(LStoreKeyed* instr) { + ASSERT(instr->value()->IsRegister()); + Register input_reg = ToRegister(instr->value()); + Condition cc = masm()->CheckSmi(input_reg); + DeoptimizeIf(cc, instr->environment()); + __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), + static_cast(T::kMapRootIndex())); + DeoptimizeIf(not_equal, instr->environment()); + + // Pre scale key if necessary. + LOperand* key = instr->key(); + ElementsKind elements_kind = instr->elements_kind(); + if (!key->IsConstantOperand()) { + HandleExternalArrayOpRequiresPreScale(key, elements_kind); + } + + // Copy the SIMD128 value from the heap object to the external array. + STATIC_ASSERT(T::kValueSize % kPointerSize == 0); + int base_offset = instr->is_fixed_typed_array() + ? FixedTypedArrayBase::kDataOffset - kHeapObjectTag + : 0; + for (int offset = 0; offset < T::kValueSize; offset += kPointerSize) { + Operand operand(BuildFastArrayOperand( + instr->elements(), + key, + elements_kind, + base_offset + offset, + instr->additional_index())); + __ movp(kScratchRegister, + FieldOperand(input_reg, T::kValueOffset + offset)); + __ movp(operand, kScratchRegister); + } +} + + void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { ElementsKind elements_kind = instr->elements_kind(); LOperand* key = instr->key(); @@ -4162,6 +4299,10 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) { __ movsd(operand, ToDoubleRegister(instr->value())); + } else if (IsFloat32x4ElementsKind(elements_kind)) { + DoStoreKeyedSIMD128ExternalArray(instr); + } else if (IsInt32x4ElementsKind(elements_kind)) { + DoStoreKeyedSIMD128ExternalArray(instr); } else { Register value(ToRegister(instr->value())); switch (elements_kind) { @@ -4187,8 +4328,12 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { break; case EXTERNAL_FLOAT32_ELEMENTS: case EXTERNAL_FLOAT64_ELEMENTS: + case EXTERNAL_FLOAT32x4_ELEMENTS: + case EXTERNAL_INT32x4_ELEMENTS: case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: + case FLOAT32x4_ELEMENTS: + case INT32x4_ELEMENTS: case FAST_ELEMENTS: case FAST_SMI_ELEMENTS: case FAST_DOUBLE_ELEMENTS: @@ -5329,6 +5474,16 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { final_branch_condition = equal; + } else if (type_name->Equals(heap()->float32x4_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, FLOAT32x4_TYPE, input); + final_branch_condition = equal; + + } else if (type_name->Equals(heap()->int32x4_string())) { + __ JumpIfSmi(input, false_label, false_distance); + __ CmpObjectType(input, INT32x4_TYPE, input); + final_branch_condition = equal; + } else if (type_name->Equals(heap()->string_string())) { __ JumpIfSmi(input, false_label, false_distance); __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input); diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h index 0f1a9cdb709..0c20c4b2026 100644 --- a/src/x64/lithium-codegen-x64.h +++ b/src/x64/lithium-codegen-x64.h @@ -116,6 +116,7 @@ class LCodeGen: public LCodeGenBase { void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, Label* map_check); void DoDeferredInstanceMigration(LCheckMaps* instr, Register object); + void DoDeferredSIMD128ToTagged(LInstruction* instr, Runtime::FunctionId id); // Parallel move support. void DoParallelMove(LParallelMove* move); @@ -324,9 +325,15 @@ class LCodeGen: public LCodeGenBase { void EnsureSpaceForLazyDeopt(int space_needed) V8_OVERRIDE; void DoLoadKeyedExternalArray(LLoadKeyed* instr); + void HandleExternalArrayOpRequiresPreScale(LOperand* key, + ElementsKind elements_kind); + template + void DoLoadKeyedSIMD128ExternalArray(LLoadKeyed* instr); void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); void DoLoadKeyedFixedArray(LLoadKeyed* instr); void DoStoreKeyedExternalArray(LStoreKeyed* instr); + template + void DoStoreKeyedSIMD128ExternalArray(LStoreKeyed* instr); void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); void DoStoreKeyedFixedArray(LStoreKeyed* instr); #ifdef _MSC_VER diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index 493650328d9..5aad9f84208 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -2001,9 +2001,13 @@ LInstruction* LChunkBuilder::DoLoadExternalArrayPointer( LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { ASSERT(instr->key()->representation().IsInteger32()); ElementsKind elements_kind = instr->elements_kind(); - LOperand* key = UseRegisterOrConstantAtStart(instr->key()); + bool clobbers_key = ExternalArrayOpRequiresPreScale(elements_kind); + LOperand* key = clobbers_key + ? UseTempRegisterOrConstant(instr->key()) + : UseRegisterOrConstantAtStart(instr->key()); LLoadKeyed* result = NULL; + bool load_128bits_without_sse2 = IsSIMD128ElementsKind(elements_kind); if (!instr->is_typed_elements()) { LOperand* obj = UseRegisterAtStart(instr->elements()); result = new(zone()) LLoadKeyed(obj, key); @@ -2012,9 +2016,15 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { (instr->representation().IsInteger32() && !(IsDoubleOrFloatElementsKind(instr->elements_kind()))) || (instr->representation().IsDouble() && - (IsDoubleOrFloatElementsKind(instr->elements_kind())))); + (IsDoubleOrFloatElementsKind(instr->elements_kind()))) || + (instr->representation().IsTagged() && + (IsSIMD128ElementsKind(instr->elements_kind())))); LOperand* backing_store = UseRegister(instr->elements()); result = new(zone()) LLoadKeyed(backing_store, key); + if (load_128bits_without_sse2) { + info()->MarkAsDeferredCalling(); + AssignPointerMap(result); + } } DefineAsRegister(result); @@ -2074,7 +2084,9 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { (instr->value()->representation().IsInteger32() && !IsDoubleOrFloatElementsKind(elements_kind)) || (instr->value()->representation().IsDouble() && - IsDoubleOrFloatElementsKind(elements_kind))); + IsDoubleOrFloatElementsKind(elements_kind)) || + (instr->value()->representation().IsTagged() && + IsSIMD128ElementsKind(elements_kind))); ASSERT((instr->is_fixed_typed_array() && instr->elements()->representation().IsTagged()) || (instr->is_external() && @@ -2087,7 +2099,9 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { : UseRegister(instr->value()); LOperand* key = UseRegisterOrConstantAtStart(instr->key()); LOperand* backing_store = UseRegister(instr->elements()); - return new(zone()) LStoreKeyed(backing_store, key, val); + LStoreKeyed* result = new(zone()) LStoreKeyed(backing_store, key, val); + bool store_128bits_without_sse2 = IsSIMD128ElementsKind(elements_kind); + return store_128bits_without_sse2 ? AssignEnvironment(result) : result; } diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h index da432d2dbd1..66fd6752ac0 100644 --- a/src/x64/lithium-x64.h +++ b/src/x64/lithium-x64.h @@ -1555,6 +1555,11 @@ class LLoadKeyed V8_FINAL : public LTemplateInstruction<1, 2, 0> { }; +inline static bool ExternalArrayOpRequiresPreScale(ElementsKind kind) { + return ElementsKindToShiftSize(kind) > static_cast(maximal_scale_factor); +} + + class LLoadKeyedGeneric V8_FINAL : public LTemplateInstruction<1, 3, 0> { public: LLoadKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key) { diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 1fa2c8dc225..a11a6a5cb3f 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -4205,6 +4205,19 @@ void MacroAssembler::AllocateHeapNumber(Register result, } +void MacroAssembler::AllocateSIMDHeapObject(int size, + Register result, + Register scratch, + Label* gc_required, + Heap::RootListIndex map_index) { + Allocate(size, result, scratch, no_reg, gc_required, TAG_OBJECT); + + // Set the map. + LoadRoot(kScratchRegister, map_index); + movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); +} + + void MacroAssembler::AllocateTwoByteString(Register result, Register length, Register scratch1, diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index 048eff1d140..eafeba6cc51 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -1146,6 +1146,11 @@ class MacroAssembler: public Assembler { void AllocateHeapNumber(Register result, Register scratch, Label* gc_required); + void AllocateSIMDHeapObject(int size, + Register result, + Register scratch, + Label* gc_required, + Heap::RootListIndex map_index); // Allocate a sequential string. All the header fields of the string object // are initialized. diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index dbfd419290c..384fca5b76c 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -1663,6 +1663,35 @@ Register CallStubCompiler::HandlerFrontendHeader(Handle object, masm(), Context::NUMBER_FUNCTION_INDEX, rax, miss); break; } + + case FLOAT32x4_CHECK: { + // Check that the object is a float32x4. + __ CmpObjectType(rdx, FLOAT32x4_TYPE, rax); + __ j(not_equal, miss); + // Check that the maps starting from the prototype haven't changed. + GenerateDirectLoadGlobalFunctionPrototype( + masm(), Context::FLOAT32x4_FUNCTION_INDEX, rax, miss); + Handle prototype(object->GetPrototype(isolate()), isolate()); + CheckPrototypes( + IC::CurrentTypeOf(prototype, isolate()), + rax, holder, rbx, rdx, rdi, name, miss); + break; + } + + case INT32x4_CHECK: { + // Check that the object is a int32x4. + __ CmpObjectType(rdx, INT32x4_TYPE, rax); + __ j(not_equal, miss); + // Check that the maps starting from the prototype haven't changed. + GenerateDirectLoadGlobalFunctionPrototype( + masm(), Context::INT32x4_FUNCTION_INDEX, rax, miss); + Handle prototype(object->GetPrototype(isolate()), isolate()); + CheckPrototypes( + IC::CurrentTypeOf(prototype, isolate()), + rax, holder, rbx, rdx, rdi, name, miss); + break; + } + case BOOLEAN_CHECK: { GenerateBooleanCheck(reg, miss); // Check that the maps starting from the prototype haven't changed. diff --git a/test/mjsunit/simd/float32x4.js b/test/mjsunit/simd/float32x4.js new file mode 100644 index 00000000000..01ffa3f7ef7 --- /dev/null +++ b/test/mjsunit/simd/float32x4.js @@ -0,0 +1,897 @@ +// 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 testConstructor() { + var f4 = SIMD.float32x4(1.0, 2.0, 3.0, 4.0); + assertEquals(1.0, f4.x); + assertEquals(2.0, f4.y); + assertEquals(3.0, f4.z); + assertEquals(4.0, f4.w); + + f4 = SIMD.float32x4(1.1, 2.2, 3.3, 4.4); + assertEquals(1.100000023841858, f4.x); + assertEquals(2.200000047683716, f4.y); + assertEquals(3.299999952316284, f4.z); + assertEquals(4.400000095367432, f4.w); +} + +testConstructor(); + +function testZeroConstructor() { + var z4 = SIMD.float32x4.zero(); + assertEquals(0.0, z4.x); + assertEquals(0.0, z4.y); + assertEquals(0.0, z4.z); + assertEquals(0.0, z4.w); +} + +testZeroConstructor(); +testZeroConstructor(); +%OptimizeFunctionOnNextCall(testZeroConstructor); +testZeroConstructor(); + +function testSplatConstructor() { + var z4 = SIMD.float32x4.splat(5.0); + assertEquals(5.0, z4.x); + assertEquals(5.0, z4.y); + assertEquals(5.0, z4.z); + assertEquals(5.0, z4.w); +} + +testSplatConstructor(); +testSplatConstructor(); +%OptimizeFunctionOnNextCall(testSplatConstructor); +testSplatConstructor(); + +function testTypeof() { + var z4 = SIMD.float32x4.zero(); + assertEquals(typeof(z4), "float32x4"); + + var new_z4 = new SIMD.float32x4(0, 0, 0, 0); + assertEquals(typeof(new_z4), "object"); + assertEquals(typeof(new_z4.valueOf()), "float32x4"); + assertEquals(Object.prototype.toString.call(new_z4), "[object float32x4]"); +} + +testTypeof(); + +function testSignMaskGetter() { + var a = SIMD.float32x4(-1.0, -2.0, -3.0, -4.0); + assertEquals(0xf, a.signMask); + var b = SIMD.float32x4(1.0, 2.0, 3.0, 4.0); + assertEquals(0x0, b.signMask); + var c = SIMD.float32x4(1.0, -2.0, -3.0, 4.0); + assertEquals(0x6, c.signMask); +} + +testSignMaskGetter(); +testSignMaskGetter(); +%OptimizeFunctionOnNextCall(testSignMaskGetter); +testSignMaskGetter(); + +function testSIMDAbs() { + var a4 = SIMD.float32x4(1.0, -1.0, 1.0, -1.0); + var b4 = SIMD.float32x4.abs(a4); + + assertEquals(1.0, b4.x); + assertEquals(1.0, b4.y); + assertEquals(1.0, b4.z); + assertEquals(1.0, b4.w); +} + +testSIMDAbs(); +testSIMDAbs(); +%OptimizeFunctionOnNextCall(testSIMDAbs); +testSIMDAbs(); + +function testSIMDNeg() { + var a4 = SIMD.float32x4(1.0, -1.0, 1.0, -1.0); + var b4 = SIMD.float32x4.neg(a4); + + assertEquals(-1.0, b4.x); + assertEquals(1.0, b4.y); + assertEquals(-1.0, b4.z); + assertEquals(1.0, b4.w); +} + +testSIMDNeg(); +testSIMDNeg(); +%OptimizeFunctionOnNextCall(testSIMDNeg); +testSIMDNeg(); + +function testSIMDAdd() { + var a4 = SIMD.float32x4(1.0, 1.0, 1.0, 1.0); + var b4 = SIMD.float32x4(2.0, 2.0, 2.0, 2.0); + var c4 = SIMD.float32x4.add(a4, b4); + + assertEquals(3.0, c4.x); + assertEquals(3.0, c4.y); + assertEquals(3.0, c4.z); + assertEquals(3.0, c4.w); +} + +testSIMDAdd(); +testSIMDAdd(); +%OptimizeFunctionOnNextCall(testSIMDAdd); +testSIMDAdd(); + +function testSIMDSub() { + var a4 = SIMD.float32x4(1.0, 1.0, 1.0, 1.0); + var b4 = SIMD.float32x4(2.0, 2.0, 2.0, 2.0); + var c4 = SIMD.float32x4.sub(a4, b4); + + assertEquals(-1.0, c4.x); + assertEquals(-1.0, c4.y); + assertEquals(-1.0, c4.z); + assertEquals(-1.0, c4.w); +} + +testSIMDSub(); +testSIMDSub(); +%OptimizeFunctionOnNextCall(testSIMDSub); +testSIMDSub(); + +function testSIMDMul() { + var a4 = SIMD.float32x4(1.0, 1.0, 1.0, 1.0); + var b4 = SIMD.float32x4(2.0, 2.0, 2.0, 2.0); + var c4 = SIMD.float32x4.mul(a4, b4); + + assertEquals(2.0, c4.x); + assertEquals(2.0, c4.y); + assertEquals(2.0, c4.z); + assertEquals(2.0, c4.w); +} + +testSIMDMul(); +testSIMDMul(); +%OptimizeFunctionOnNextCall(testSIMDMul); +testSIMDMul(); + +function testSIMDDiv() { + var a4 = SIMD.float32x4(1.0, 1.0, 1.0, 1.0); + var b4 = SIMD.float32x4(2.0, 2.0, 2.0, 2.0); + var c4 = SIMD.float32x4.div(a4, b4); + + assertEquals(0.5, c4.x); + assertEquals(0.5, c4.y); + assertEquals(0.5, c4.z); + assertEquals(0.5, c4.w); +} + +testSIMDDiv(); +testSIMDDiv(); +%OptimizeFunctionOnNextCall(testSIMDDiv); +testSIMDDiv(); + +function testSIMDClamp() { + var m = SIMD.float32x4(1.0, -2.0, 3.0, -4.0); + var lo = SIMD.float32x4(0.0, 0.0, 0.0, 0.0); + var hi = SIMD.float32x4(2.0, 2.0, 2.0, 2.0); + m = SIMD.float32x4.clamp(m, lo, hi); + assertEquals(1.0, m.x); + assertEquals(0.0, m.y); + assertEquals(2.0, m.z); + assertEquals(0.0, m.w); +} + +testSIMDClamp(); +testSIMDClamp(); +%OptimizeFunctionOnNextCall(testSIMDClamp); +testSIMDClamp(); + +function testSIMDMin() { + var m = SIMD.float32x4(1.0, 2.0, 3.0, 4.0); + var n = SIMD.float32x4(1.0, 0.0, 2.5, 5.0); + m = SIMD.float32x4.min(m, n); + assertEquals(1.0, m.x); + assertEquals(0.0, m.y); + assertEquals(2.5, m.z); + assertEquals(4.0, m.w); +} + +testSIMDMin(); +testSIMDMin(); +%OptimizeFunctionOnNextCall(testSIMDMin); +testSIMDMin(); + +function testSIMDMax() { + var m = SIMD.float32x4(1.0, 2.0, 3.0, 4.0); + var n = SIMD.float32x4(1.0, 0.0, 2.5, 5.0); + m = SIMD.float32x4.max(m, n); + assertEquals(1.0, m.x); + assertEquals(2.0, m.y); + assertEquals(3.0, m.z); + assertEquals(5.0, m.w); +} + +testSIMDMax(); +testSIMDMax(); +%OptimizeFunctionOnNextCall(testSIMDMax); +testSIMDMax(); + +function testSIMDReciprocal() { + var m = SIMD.float32x4(1.0, 4.0, 9.0, 16.0); + m = SIMD.float32x4.reciprocal(m); + assertTrue(Math.abs(1.0 - m.x) <= 0.001); + assertTrue(Math.abs(0.25 - m.y) <= 0.001); + assertTrue(Math.abs(0.1111111 - m.z) <= 0.001); + assertTrue(Math.abs(0.0625 - m.w) <= 0.001); +} + +testSIMDReciprocal(); +testSIMDReciprocal(); +%OptimizeFunctionOnNextCall(testSIMDReciprocal); +testSIMDReciprocal(); + +function testSIMDReciprocalSqrt() { + var m = SIMD.float32x4(1.0, 0.25, 0.111111, 0.0625); + m = SIMD.float32x4.reciprocalSqrt(m); + assertTrue(Math.abs(1.0 - m.x) <= 0.001); + assertTrue(Math.abs(2.0 - m.y) <= 0.001); + assertTrue(Math.abs(3.0 - m.z) <= 0.001); + assertTrue(Math.abs(4.0 - m.w) <= 0.001); +} + +testSIMDReciprocalSqrt(); +testSIMDReciprocalSqrt(); +%OptimizeFunctionOnNextCall(testSIMDReciprocalSqrt); +testSIMDReciprocalSqrt(); + +function testSIMDScale() { + var m = SIMD.float32x4(1.0, -2.0, 3.0, -4.0); + m = SIMD.float32x4.scale(m, 20.0); + assertEquals(20.0, m.x); + assertEquals(-40.0, m.y); + assertEquals(60.0, m.z); + assertEquals(-80.0, m.w); +} + +testSIMDScale(); +testSIMDScale(); +%OptimizeFunctionOnNextCall(testSIMDScale); +testSIMDScale(); + +function testSIMDSqrt() { + var m = SIMD.float32x4(1.0, 4.0, 9.0, 16.0); + m = SIMD.float32x4.sqrt(m); + assertEquals(1.0, m.x); + assertEquals(2.0, m.y); + assertEquals(3.0, m.z); + assertEquals(4.0, m.w); +} + +testSIMDSqrt(); +testSIMDSqrt(); +%OptimizeFunctionOnNextCall(testSIMDSqrt); +testSIMDSqrt(); + +function testSIMDShuffle() { + var m = SIMD.float32x4(1.0, 2.0, 3.0, 4.0); + var xxxx = SIMD.float32x4.shuffle(m, SIMD.XXXX); + assertEquals(1.0, xxxx.x); + assertEquals(1.0, xxxx.y); + assertEquals(1.0, xxxx.z); + assertEquals(1.0, xxxx.w); + var yyyy = SIMD.float32x4.shuffle(m, SIMD.YYYY); + assertEquals(2.0, yyyy.x); + assertEquals(2.0, yyyy.y); + assertEquals(2.0, yyyy.z); + assertEquals(2.0, yyyy.w); + var zzzz = SIMD.float32x4.shuffle(m, SIMD.ZZZZ); + assertEquals(3.0, zzzz.x); + assertEquals(3.0, zzzz.y); + assertEquals(3.0, zzzz.z); + assertEquals(3.0, zzzz.w); + var wwww = SIMD.float32x4.shuffle(m, SIMD.WWWW); + assertEquals(4.0, wwww.x); + assertEquals(4.0, wwww.y); + assertEquals(4.0, wwww.z); + assertEquals(4.0, wwww.w); + var wzyx = SIMD.float32x4.shuffle(m, SIMD.WZYX); + assertEquals(4.0, wzyx.x); + assertEquals(3.0, wzyx.y); + assertEquals(2.0, wzyx.z); + assertEquals(1.0, wzyx.w); + var wwzz = SIMD.float32x4.shuffle(m, SIMD.WWZZ); + assertEquals(4.0, wwzz.x); + assertEquals(4.0, wwzz.y); + assertEquals(3.0, wwzz.z); + assertEquals(3.0, wwzz.w); + var xxyy = SIMD.float32x4.shuffle(m, SIMD.XXYY); + assertEquals(1.0, xxyy.x); + assertEquals(1.0, xxyy.y); + assertEquals(2.0, xxyy.z); + assertEquals(2.0, xxyy.w); + var yyww = SIMD.float32x4.shuffle(m, SIMD.YYWW); + assertEquals(2.0, yyww.x); + assertEquals(2.0, yyww.y); + assertEquals(4.0, yyww.z); + assertEquals(4.0, yyww.w); +} + +testSIMDShuffle(); +testSIMDShuffle(); +%OptimizeFunctionOnNextCall(testSIMDShuffle); +testSIMDShuffle(); + +function testSIMDShuffleMix() { + var a = SIMD.float32x4(1.0, 2.0, 3.0, 4.0); + var b = SIMD.float32x4(5.0, 6.0, 7.0, 8.0); + var xxxx = SIMD.float32x4.shuffleMix(a, b, SIMD.XXXX); + assertEquals(1.0, xxxx.x); + assertEquals(1.0, xxxx.y); + assertEquals(5.0, xxxx.z); + assertEquals(5.0, xxxx.w); + var yyyy = SIMD.float32x4.shuffleMix(a, b, SIMD.YYYY); + assertEquals(2.0, yyyy.x); + assertEquals(2.0, yyyy.y); + assertEquals(6.0, yyyy.z); + assertEquals(6.0, yyyy.w); + var zzzz = SIMD.float32x4.shuffleMix(a, b, SIMD.ZZZZ); + assertEquals(3.0, zzzz.x); + assertEquals(3.0, zzzz.y); + assertEquals(7.0, zzzz.z); + assertEquals(7.0, zzzz.w); + var wwww = SIMD.float32x4.shuffleMix(a, b, SIMD.WWWW); + assertEquals(4.0, wwww.x); + assertEquals(4.0, wwww.y); + assertEquals(8.0, wwww.z); + assertEquals(8.0, wwww.w); + var wzyx = SIMD.float32x4.shuffleMix(a, b, SIMD.WZYX); + assertEquals(4.0, wzyx.x); + assertEquals(3.0, wzyx.y); + assertEquals(6.0, wzyx.z); + assertEquals(5.0, wzyx.w); + var wwzz = SIMD.float32x4.shuffleMix(a, b, SIMD.WWZZ); + assertEquals(4.0, wwzz.x); + assertEquals(4.0, wwzz.y); + assertEquals(7.0, wwzz.z); + assertEquals(7.0, wwzz.w); + var xxyy = SIMD.float32x4.shuffleMix(a, b, SIMD.XXYY); + assertEquals(1.0, xxyy.x); + assertEquals(1.0, xxyy.y); + assertEquals(6.0, xxyy.z); + assertEquals(6.0, xxyy.w); + var yyww = SIMD.float32x4.shuffleMix(a, b, SIMD.YYWW); + assertEquals(2.0, yyww.x); + assertEquals(2.0, yyww.y); + assertEquals(8.0, yyww.z); + assertEquals(8.0, yyww.w); +} + +testSIMDShuffleMix(); +testSIMDShuffleMix(); +%OptimizeFunctionOnNextCall(testSIMDShuffleMix); +testSIMDShuffleMix(); + +function testSIMDSetters() { + var f = SIMD.float32x4.zero(); + assertEquals(0.0, f.x); + assertEquals(0.0, f.y); + assertEquals(0.0, f.z); + assertEquals(0.0, f.w); + f = SIMD.float32x4.withX(f, 4.0); + assertEquals(4.0, f.x); + f = SIMD.float32x4.withY(f, 3.0); + assertEquals(3.0, f.y); + f = SIMD.float32x4.withZ(f, 2.0); + assertEquals(2.0, f.z); + f = SIMD.float32x4.withW(f, 1.0); + assertEquals(1.0, f.w); + f = SIMD.float32x4.zero(); +} + +testSIMDSetters(); +testSIMDSetters(); +%OptimizeFunctionOnNextCall(testSIMDSetters); +testSIMDSetters(); + +function testSIMDConversion() { + var m = SIMD.int32x4(0x3F800000, 0x40000000, 0x40400000, 0x40800000); + var n = SIMD.int32x4.bitsToFloat32x4(m); + assertEquals(1.0, n.x); + assertEquals(2.0, n.y); + assertEquals(3.0, n.z); + assertEquals(4.0, n.w); + n = SIMD.float32x4(5.0, 6.0, 7.0, 8.0); + m = SIMD.float32x4.bitsToInt32x4(n); + assertEquals(0x40A00000, m.x); + assertEquals(0x40C00000, m.y); + assertEquals(0x40E00000, m.z); + assertEquals(0x41000000, m.w); + // Flip sign using bit-wise operators. + n = SIMD.float32x4(9.0, 10.0, 11.0, 12.0); + m = SIMD.int32x4(0x80000000, 0x80000000, 0x80000000, 0x80000000); + var nMask = SIMD.float32x4.bitsToInt32x4(n); + nMask = SIMD.int32x4.xor(nMask, m); // flip sign. + n = SIMD.int32x4.bitsToFloat32x4(nMask); + assertEquals(-9.0, n.x); + assertEquals(-10.0, n.y); + assertEquals(-11.0, n.z); + assertEquals(-12.0, n.w); + nMask = SIMD.float32x4.bitsToInt32x4(n); + nMask = SIMD.int32x4.xor(nMask, m); // flip sign. + n = SIMD.int32x4.bitsToFloat32x4(nMask); + assertEquals(9.0, n.x); + assertEquals(10.0, n.y); + assertEquals(11.0, n.z); + assertEquals(12.0, n.w); +} + +testSIMDConversion(); +testSIMDConversion(); +%OptimizeFunctionOnNextCall(testSIMDConversion); +testSIMDConversion(); + +function testSIMDConversion2() { + var m = SIMD.int32x4(1, 2, 3, 4); + var n = SIMD.int32x4.toFloat32x4(m); + assertEquals(1.0, n.x); + assertEquals(2.0, n.y); + assertEquals(3.0, n.z); + assertEquals(4.0, n.w); + n = SIMD.float32x4(5.0, 6.0, 7.0, 8.0); + m = SIMD.float32x4.toInt32x4(n); + assertEquals(5, m.x); + assertEquals(6, m.y); + assertEquals(7, m.z); + assertEquals(8, m.w); +} + +testSIMDConversion2(); +testSIMDConversion2(); +%OptimizeFunctionOnNextCall(testSIMDConversion2); +testSIMDConversion2(); + + +function testSIMDComparisons() { + var m = SIMD.float32x4(1.0, 2.0, 0.1, 0.001); + var n = SIMD.float32x4(2.0, 2.0, 0.001, 0.1); + var cmp; + cmp = SIMD.float32x4.lessThan(m, n); + assertEquals(-1, cmp.x); + assertEquals(0x0, cmp.y); + assertEquals(0x0, cmp.z); + assertEquals(-1, cmp.w); + + cmp = SIMD.float32x4.lessThanOrEqual(m, n); + assertEquals(-1, cmp.x); + assertEquals(-1, cmp.y); + assertEquals(0x0, cmp.z); + assertEquals(-1, cmp.w); + + cmp = SIMD.float32x4.equal(m, n); + assertEquals(0x0, cmp.x); + assertEquals(-1, cmp.y); + assertEquals(0x0, cmp.z); + assertEquals(0x0, cmp.w); + + cmp = SIMD.float32x4.notEqual(m, n); + assertEquals(-1, cmp.x); + assertEquals(0x0, cmp.y); + assertEquals(-1, cmp.z); + assertEquals(-1, cmp.w); + + cmp = SIMD.float32x4.greaterThanOrEqual(m, n); + assertEquals(0x0, cmp.x); + assertEquals(-1, cmp.y); + assertEquals(-1, cmp.z); + assertEquals(0x0, cmp.w); + + cmp = SIMD.float32x4.greaterThan(m, n); + assertEquals(0x0, cmp.x); + assertEquals(0x0, cmp.y); + assertEquals(-1, cmp.z); + assertEquals(0x0, cmp.w); +} + +testSIMDComparisons(); +testSIMDComparisons(); +%OptimizeFunctionOnNextCall(testSIMDComparisons); +testSIMDComparisons(); + +function testFloat32x4ArrayBasic() { + var a = new Float32x4Array(1); + assertEquals(1, a.length); + assertEquals(16, a.byteLength); + assertEquals(16, a.BYTES_PER_ELEMENT); + assertEquals(16, Float32x4Array.BYTES_PER_ELEMENT); + assertEquals(0, a.byteOffset); + assertTrue(undefined != a.buffer); + var b = new Float32x4Array(4); + assertEquals(4, b.length); + assertEquals(64, b.byteLength); + assertEquals(16, b.BYTES_PER_ELEMENT); + assertEquals(16, Float32x4Array.BYTES_PER_ELEMENT); + assertEquals(0, b.byteOffset); + assertTrue(undefined != b.buffer); +} + +testFloat32x4ArrayBasic(); + +function testFloat32x4ArrayGetAndSet() { + var a = new Float32x4Array(4); + a[0] = SIMD.float32x4(1, 2, 3, 4); + a[1] = SIMD.float32x4(5, 6, 7, 8); + a[2] = SIMD.float32x4(9, 10, 11, 12); + a[3] = SIMD.float32x4(13, 14, 15, 16); + assertEquals(a[0].x, 1); + assertEquals(a[0].y, 2); + assertEquals(a[0].z, 3); + assertEquals(a[0].w, 4); + + assertEquals(a[1].x, 5); + assertEquals(a[1].y, 6); + assertEquals(a[1].z, 7); + assertEquals(a[1].w, 8); + + assertEquals(a[2].x, 9); + assertEquals(a[2].y, 10); + assertEquals(a[2].z, 11); + assertEquals(a[2].w, 12); + + assertEquals(a[3].x, 13); + assertEquals(a[3].y, 14); + assertEquals(a[3].z, 15); + assertEquals(a[3].w, 16); + + var b = new Float32x4Array(4); + b.setAt(0,SIMD.float32x4(1, 2, 3, 4)); + b.setAt(1,SIMD.float32x4(5, 6, 7, 8)); + b.setAt(2,SIMD.float32x4(9, 10, 11, 12)); + b.setAt(3,SIMD.float32x4(13, 14, 15, 16)); + + assertEquals(b.getAt(0).x, 1); + assertEquals(b.getAt(0).y, 2); + assertEquals(b.getAt(0).z, 3); + assertEquals(b.getAt(0).w, 4); + + assertEquals(b.getAt(1).x, 5); + assertEquals(b.getAt(1).y, 6); + assertEquals(b.getAt(1).z, 7); + assertEquals(b.getAt(1).w, 8); + + assertEquals(b.getAt(2).x, 9); + assertEquals(b.getAt(2).y, 10); + assertEquals(b.getAt(2).z, 11); + assertEquals(b.getAt(2).w, 12); + + assertEquals(b.getAt(3).x, 13); + assertEquals(b.getAt(3).y, 14); + assertEquals(b.getAt(3).z, 15); + assertEquals(b.getAt(3).w, 16); +} + +testFloat32x4ArrayGetAndSet(); +testFloat32x4ArrayGetAndSet(); +%OptimizeFunctionOnNextCall(testFloat32x4ArrayGetAndSet); +testFloat32x4ArrayGetAndSet(); + +function testFloat32x4ArraySwap() { + var a = new Float32x4Array(4); + a[0] = SIMD.float32x4(1, 2, 3, 4); + a[1] = SIMD.float32x4(5, 6, 7, 8); + a[2] = SIMD.float32x4(9, 10, 11, 12); + a[3] = SIMD.float32x4(13, 14, 15, 16); + + // Swap element 0 and element 3 + var t = a[0]; + a[0] = a[3]; + a[3] = t; + + assertEquals(a[3].x, 1); + assertEquals(a[3].y, 2); + assertEquals(a[3].z, 3); + assertEquals(a[3].w, 4); + + assertEquals(a[1].x, 5); + assertEquals(a[1].y, 6); + assertEquals(a[1].z, 7); + assertEquals(a[1].w, 8); + + assertEquals(a[2].x, 9); + assertEquals(a[2].y, 10); + assertEquals(a[2].z, 11); + assertEquals(a[2].w, 12); + + assertEquals(a[0].x, 13); + assertEquals(a[0].y, 14); + assertEquals(a[0].z, 15); + assertEquals(a[0].w, 16); +} + +testFloat32x4ArraySwap(); + +function testFloat32x4ArrayCopy() { + var a = new Float32x4Array(4); + a[0] = SIMD.float32x4(1, 2, 3, 4); + a[1] = SIMD.float32x4(5, 6, 7, 8); + a[2] = SIMD.float32x4(9, 10, 11, 12); + a[3] = SIMD.float32x4(13, 14, 15, 16); + var b = new Float32x4Array(a); + assertEquals(a[0].x, b[0].x); + assertEquals(a[0].y, b[0].y); + assertEquals(a[0].z, b[0].z); + assertEquals(a[0].w, b[0].w); + + assertEquals(a[1].x, b[1].x); + assertEquals(a[1].y, b[1].y); + assertEquals(a[1].z, b[1].z); + assertEquals(a[1].w, b[1].w); + + assertEquals(a[2].x, b[2].x); + assertEquals(a[2].y, b[2].y); + assertEquals(a[2].z, b[2].z); + assertEquals(a[2].w, b[2].w); + + assertEquals(a[3].x, b[3].x); + assertEquals(a[3].y, b[3].y); + assertEquals(a[3].z, b[3].z); + assertEquals(a[3].w, b[3].w); + + a[2] = SIMD.float32x4(17, 18, 19, 20); + + assertEquals(a[2].x, 17); + assertEquals(a[2].y, 18); + assertEquals(a[2].z, 19); + assertEquals(a[2].w, 20); + + assertTrue(a[2].x != b[2].x); + assertTrue(a[2].y != b[2].y); + assertTrue(a[2].z != b[2].z); + assertTrue(a[2].w != b[2].w); +} + +testFloat32x4ArrayCopy(); + +function testFloat32x4ArrayViewBasic() { + var a = new Float32Array(8); + // view with no offset. + var b = new Float32x4Array(a.buffer, 0); + // view with offset. + var c = new Float32x4Array(a.buffer, 16); + // view with no offset but shorter than original list. + var d = new Float32x4Array(a.buffer, 0, 1); + assertEquals(a.length, 8); + assertEquals(b.length, 2); + assertEquals(c.length, 1); + assertEquals(d.length, 1); + assertEquals(a.byteLength, 32); + assertEquals(b.byteLength, 32); + assertEquals(c.byteLength, 16); + assertEquals(d.byteLength, 16) + assertEquals(a.byteOffset, 0); + assertEquals(b.byteOffset, 0); + assertEquals(c.byteOffset, 16); + assertEquals(d.byteOffset, 0); +} + +testFloat32x4ArrayViewBasic(); + +function testFloat32x4ArrayViewValues() { + var a = new Float32Array(8); + var b = new Float32x4Array(a.buffer, 0); + var c = new Float32x4Array(a.buffer, 16); + var d = new Float32x4Array(a.buffer, 0, 1); + var start = 100; + for (var i = 0; i < b.length; i++) { + assertEquals(0.0, b[i].x); + assertEquals(0.0, b[i].y); + assertEquals(0.0, b[i].z); + assertEquals(0.0, b[i].w); + } + for (var i = 0; i < c.length; i++) { + assertEquals(0.0, c[i].x); + assertEquals(0.0, c[i].y); + assertEquals(0.0, c[i].z); + assertEquals(0.0, c[i].w); + } + for (var i = 0; i < d.length; i++) { + assertEquals(0.0, d[i].x); + assertEquals(0.0, d[i].y); + assertEquals(0.0, d[i].z); + assertEquals(0.0, d[i].w); + } + for (var i = 0; i < a.length; i++) { + a[i] = i+start; + } + for (var i = 0; i < b.length; i++) { + assertTrue(0.0 != b[i].x); + assertTrue(0.0 != b[i].y); + assertTrue(0.0 != b[i].z); + assertTrue(0.0 != b[i].w); + } + for (var i = 0; i < c.length; i++) { + assertTrue(0.0 != c[i].x); + assertTrue(0.0 != c[i].y); + assertTrue(0.0 != c[i].z); + assertTrue(0.0 != c[i].w); + } + for (var i = 0; i < d.length; i++) { + assertTrue(0.0 != d[i].x); + assertTrue(0.0 != d[i].y); + assertTrue(0.0 != d[i].z); + assertTrue(0.0 != d[i].w); + } + assertEquals(start+0, b[0].x); + assertEquals(start+1, b[0].y); + assertEquals(start+2, b[0].z); + assertEquals(start+3, b[0].w); + assertEquals(start+4, b[1].x); + assertEquals(start+5, b[1].y); + assertEquals(start+6, b[1].z); + assertEquals(start+7, b[1].w); + + assertEquals(start+4, c[0].x); + assertEquals(start+5, c[0].y); + assertEquals(start+6, c[0].z); + assertEquals(start+7, c[0].w); + + assertEquals(start+0, d[0].x); + assertEquals(start+1, d[0].y); + assertEquals(start+2, d[0].z); + assertEquals(start+3, d[0].w); +} + +testFloat32x4ArrayViewValues(); + +function testViewOnFloat32x4Array() { + var a = new Float32x4Array(4); + a[0] = SIMD.float32x4(1, 2, 3, 4); + a[1] = SIMD.float32x4(5, 6, 7, 8); + a[2] = SIMD.float32x4(9, 10, 11, 12); + a[3] = SIMD.float32x4(13, 14, 15, 16); + assertEquals(a[0].x, 1); + assertEquals(a[0].y, 2); + assertEquals(a[0].z, 3); + assertEquals(a[0].w, 4); + + assertEquals(a[1].x, 5); + assertEquals(a[1].y, 6); + assertEquals(a[1].z, 7); + assertEquals(a[1].w, 8); + + assertEquals(a[2].x, 9); + assertEquals(a[2].y, 10); + assertEquals(a[2].z, 11); + assertEquals(a[2].w, 12); + + assertEquals(a[3].x, 13); + assertEquals(a[3].y, 14); + assertEquals(a[3].z, 15); + assertEquals(a[3].w, 16); + + // Create view on a. + var b = new Float32Array(a.buffer); + assertEquals(b.length, 16); + assertEquals(b.byteLength, 64); + b[2] = 99.0; + b[6] = 1.0; + + // Observe changes in "a" + assertEquals(a[0].x, 1); + assertEquals(a[0].y, 2); + assertEquals(a[0].z, 99); + assertEquals(a[0].w, 4); + + assertEquals(a[1].x, 5); + assertEquals(a[1].y, 6); + assertEquals(a[1].z, 1); + assertEquals(a[1].w, 8); + + assertEquals(a[2].x, 9); + assertEquals(a[2].y, 10); + assertEquals(a[2].z, 11); + assertEquals(a[2].w, 12); + + assertEquals(a[3].x, 13); + assertEquals(a[3].y, 14); + assertEquals(a[3].z, 15); + assertEquals(a[3].w, 16); +} + +testViewOnFloat32x4Array(); + +function testArrayOfFloat32x4() { + var a = []; + var a4 = new Float32x4Array(2); + for (var i = 0; i < a4.length; i++) { + a[i] = SIMD.float32x4(i, i + 1, i + 2, i + 3); + a4[i] = SIMD.float32x4(i, i + 1, i + 2, i + 3); + } + + for (var i = 0; i < a4.length; i++) { + assertEquals(a[i].x, a4[i].x); + assertEquals(a[i].y, a4[i].y); + assertEquals(a[i].z, a4[i].z); + assertEquals(a[i].w, a4[i].w); + } +} + +testArrayOfFloat32x4(); + +function testSIMDAnd() { + var m = SIMD.float32x4(1.0, 2.0, 3.0, 4.0); + var n = SIMD.float32x4(~1.0, 2.0, 3.0, 4.0); + o = SIMD.float32x4.and(m,n); // and + assertEquals(0, o.x); + assertEquals(2, o.y); + assertEquals(3, o.z); + assertEquals(4, o.w); +} + +testSIMDAnd(); +testSIMDAnd(); +%OptimizeFunctionOnNextCall(testSIMDAnd); +testSIMDAnd(); + +function testSIMDOr() { + var m = SIMD.float32x4(1.0, 2.0, 3.0, 4.0); + var n = SIMD.float32x4(~1.0, 2.0, 3.0, 4.0); + var o = SIMD.float32x4.or(m,n); // or + assertEquals(-Infinity, o.x); + assertEquals(2.0, o.y); + assertEquals(3.0, o.z); + assertEquals(4.0, o.w); +} + +testSIMDOr(); +testSIMDOr(); +%OptimizeFunctionOnNextCall(testSIMDOr); +testSIMDOr(); + +function testSIMDXor() { + var m = SIMD.float32x4(1.0, 2.0, 3.0, 4.0); + var n = SIMD.float32x4(~1.0, 2.0, 3.0, 4.0); + var o = SIMD.float32x4.xor(m,n); // xor + assertEquals(-Infinity, o.x); + assertEquals(0x0, o.y); + assertEquals(0x0, o.z); + assertEquals(0x0, o.w); +} + +testSIMDXor(); +testSIMDXor(); +%OptimizeFunctionOnNextCall(testSIMDXor); +testSIMDXor(); + +function testSIMDNot() { + var m = SIMD.float32x4(1.0, 2.0, 3.0, 4.0); + m = SIMD.float32x4.not(m); + m = SIMD.float32x4.not(m); + assertEquals(1.0, m.x); + assertEquals(2.0, m.y); + assertEquals(3.0, m.z); + assertEquals(4.0, m.w); +} + +testSIMDNot(); +testSIMDNot(); +%OptimizeFunctionOnNextCall(testSIMDNot); +testSIMDNot(); diff --git a/test/mjsunit/simd/int32x4.js b/test/mjsunit/simd/int32x4.js new file mode 100644 index 00000000000..507672c72f4 --- /dev/null +++ b/test/mjsunit/simd/int32x4.js @@ -0,0 +1,932 @@ +// 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 testConstructor() { + var u4 = SIMD.int32x4(1, 2, 3, 4); + assertEquals(1, u4.x); + assertEquals(2, u4.y); + assertEquals(3, u4.z); + assertEquals(4, u4.w); +} + +testConstructor(); + +function testZeroConstructor() { + var u4 = SIMD.int32x4.zero(); + assertEquals(0, u4.x); + assertEquals(0, u4.y); + assertEquals(0, u4.z); + assertEquals(0, u4.w); +} + +testZeroConstructor(); +testZeroConstructor(); +%OptimizeFunctionOnNextCall(testZeroConstructor); +testZeroConstructor(); + +function testBoolConstructor() { + var u4 = SIMD.int32x4.bool(true, false, true, false); + assertEquals(-1, u4.x); + assertEquals(0, u4.y); + assertEquals(-1, u4.z); + assertEquals(0, u4.w); +} + +testBoolConstructor(); +testBoolConstructor(); +%OptimizeFunctionOnNextCall(testBoolConstructor); +testBoolConstructor(); + +function testSplatConstructor() { + var u4 = SIMD.int32x4.splat(4); + assertEquals(4, u4.x); + assertEquals(4, u4.y); + assertEquals(4, u4.z); + assertEquals(4, u4.w); +} + +testSplatConstructor(); +testSplatConstructor(); +%OptimizeFunctionOnNextCall(testSplatConstructor); +testSplatConstructor(); + +function testTypeof() { + var u4 = SIMD.int32x4(1, 2, 3, 4); + assertEquals(typeof(u4), "int32x4"); + + var new_u4 = new SIMD.int32x4(1, 2, 3, 4); + assertEquals(typeof(new_u4), "object"); + assertEquals(typeof(new_u4.valueOf()), "int32x4"); + assertEquals(Object.prototype.toString.call(new_u4), "[object int32x4]"); +} + +testTypeof(); + +function testSignMaskGetter() { + var a = SIMD.int32x4(0x80000000 - 0xFFFFFFFF - 1, 0x7000000, -1, 0x0); + assertEquals(0x5, a.signMask); + var b = SIMD.int32x4(0x0, 0x0, 0x0, 0x0); + assertEquals(0x0, b.signMask); + var c = SIMD.int32x4(-1, -1, -1, -1); + assertEquals(0xf, c.signMask); +} + +testSignMaskGetter(); +testSignMaskGetter(); +%OptimizeFunctionOnNextCall(testSignMaskGetter); +testSignMaskGetter(); + + +function testSIMDAnd() { + var m = SIMD.int32x4(0xAAAAAAAA - 0xFFFFFFFF - 1, 0xAAAAAAAA - 0xFFFFFFFF - 1, + 0xAAAAAAAA - 0xFFFFFFFF - 1, 0xAAAAAAAA - 0xFFFFFFFF - 1); + var n = SIMD.int32x4(0x55555555, 0x55555555, 0x55555555, 0x55555555); + assertEquals(0xAAAAAAAA - 0xFFFFFFFF - 1, m.x); + assertEquals(0xAAAAAAAA - 0xFFFFFFFF - 1, m.y); + assertEquals(0xAAAAAAAA - 0xFFFFFFFF - 1, m.z); + assertEquals(0xAAAAAAAA - 0xFFFFFFFF - 1, m.w); + assertEquals(0x55555555, n.x); + assertEquals(0x55555555, n.y); + assertEquals(0x55555555, n.z); + assertEquals(0x55555555, n.w); + assertEquals(true, n.flagX); + assertEquals(true, n.flagY); + assertEquals(true, n.flagZ); + assertEquals(true, n.flagW); + o = SIMD.int32x4.and(m,n); // and + assertEquals(0x0, o.x); + assertEquals(0x0, o.y); + assertEquals(0x0, o.z); + assertEquals(0x0, o.w); + assertEquals(false, o.flagX); + assertEquals(false, o.flagY); + assertEquals(false, o.flagZ); + assertEquals(false, o.flagW); +} + +testSIMDAnd(); +testSIMDAnd(); +%OptimizeFunctionOnNextCall(testSIMDAnd); +testSIMDAnd(); + +function testSIMDOr() { + var m = SIMD.int32x4(0xAAAAAAAA - 0xFFFFFFFF - 1, 0xAAAAAAAA - 0xFFFFFFFF - 1, + 0xAAAAAAAA - 0xFFFFFFFF - 1, 0xAAAAAAAA - 0xFFFFFFFF - 1); + var n = SIMD.int32x4(0x55555555, 0x55555555, 0x55555555, 0x55555555); + var o = SIMD.int32x4.or(m,n); // or + assertEquals(-1, o.x); + assertEquals(-1, o.y); + assertEquals(-1, o.z); + assertEquals(-1, o.w); + assertEquals(true, o.flagX); + assertEquals(true, o.flagY); + assertEquals(true, o.flagZ); + assertEquals(true, o.flagW); +} + +testSIMDOr(); +testSIMDOr(); +%OptimizeFunctionOnNextCall(testSIMDOr); +testSIMDOr(); + +function testSIMDInt32x4Or() { + var m = SIMD.int32x4(0xAAAAAAAA - 0xFFFFFFFF - 1, 0xAAAAAAAA - 0xFFFFFFFF - 1, + 0xAAAAAAAA - 0xFFFFFFFF - 1, 0xAAAAAAAA - 0xFFFFFFFF - 1); + var n = SIMD.int32x4(0xAAAAAAAA - 0xFFFFFFFF - 1, 0xAAAAAAAA - 0xFFFFFFFF - 1, + 0xAAAAAAAA - 0xFFFFFFFF - 1, 0xAAAAAAAA - 0xFFFFFFFF - 1); + var o = SIMD.int32x4.xor(m,n); // xor + assertEquals(0x0, o.x); + assertEquals(0x0, o.y); + assertEquals(0x0, o.z); + assertEquals(0x0, o.w); + assertEquals(false, o.flagX); + assertEquals(false, o.flagY); + assertEquals(false, o.flagZ); + assertEquals(false, o.flagW); +} + +testSIMDInt32x4Or(); +testSIMDInt32x4Or(); +%OptimizeFunctionOnNextCall(testSIMDInt32x4Or); +testSIMDInt32x4Or(); + +function testSIMDNot() { + var m = SIMD.int32x4(0xAAAAAAAA - 0xFFFFFFFF - 1, 0xAAAAAAAA - 0xFFFFFFFF - 1, + 0xAAAAAAAA - 0xFFFFFFFF - 1, 0xAAAAAAAA - 0xFFFFFFFF - 1); + var n = SIMD.int32x4(0x55555555, 0x55555555, 0x55555555, 0x55555555); + m = SIMD.int32x4.not(m); + n = SIMD.int32x4.not(n); + assertEquals(0xAAAAAAAA - 0xFFFFFFFF - 1, n.x); + assertEquals(0xAAAAAAAA - 0xFFFFFFFF - 1, n.y); + assertEquals(0xAAAAAAAA - 0xFFFFFFFF - 1, n.z); + assertEquals(0xAAAAAAAA - 0xFFFFFFFF - 1, n.w); + assertEquals(0x55555555, m.x); + assertEquals(0x55555555, m.y); + assertEquals(0x55555555, m.z); + assertEquals(0x55555555, m.w); +} + +testSIMDNot(); +testSIMDNot(); +%OptimizeFunctionOnNextCall(testSIMDNot); +testSIMDNot(); + +function testSIMDNegu32() { + var m = SIMD.int32x4(-1, 1, -1, 1); + m = SIMD.int32x4.neg(m); + assertEquals(1, m.x); + assertEquals(-1, m.y); + assertEquals(1, m.z); + assertEquals(-1, m.w); +} + +testSIMDNegu32(); +testSIMDNegu32(); +%OptimizeFunctionOnNextCall(testSIMDNegu32); +testSIMDNegu32(); + +function testSIMDSelect() { + var m = SIMD.int32x4.bool(true, true, false, false); + var t = SIMD.float32x4(1.0, 2.0, 3.0, 4.0); + var f = SIMD.float32x4(5.0, 6.0, 7.0, 8.0); + var s = SIMD.int32x4.select(m, t, f); + assertEquals(1.0, s.x); + assertEquals(2.0, s.y); + assertEquals(7.0, s.z); + assertEquals(8.0, s.w); +} + +testSIMDSelect(); +testSIMDSelect(); +%OptimizeFunctionOnNextCall(testSIMDSelect); +testSIMDSelect(); + + +function testSIMDWithXu32() { + var a = SIMD.int32x4(1, 2, 3, 4); + var c = SIMD.int32x4.withX(a, 20); + assertEquals(20, c.x); + assertEquals(2, c.y); + assertEquals(3, c.z); + assertEquals(4, c.w); +} + +testSIMDWithXu32(); +testSIMDWithXu32(); +%OptimizeFunctionOnNextCall(testSIMDWithXu32); +testSIMDWithXu32(); + +function testSIMDWithYu32() { + var a = SIMD.int32x4(1, 2, 3, 4); + var c = SIMD.int32x4.withY(a, 20); + assertEquals(1, c.x); + assertEquals(20, c.y); + assertEquals(3, c.z); + assertEquals(4, c.w); +} + +testSIMDWithYu32(); +testSIMDWithYu32(); +%OptimizeFunctionOnNextCall(testSIMDWithYu32); +testSIMDWithYu32(); + +function testSIMDWithZu32() { + var a = SIMD.int32x4(1, 2, 3, 4); + var c = SIMD.int32x4.withZ(a, 20); + assertEquals(1, c.x); + assertEquals(2, c.y); + assertEquals(20, c.z); + assertEquals(4, c.w); +} + +testSIMDWithZu32(); +testSIMDWithZu32(); +%OptimizeFunctionOnNextCall(testSIMDWithZu32); +testSIMDWithZu32(); + +function testSIMDWithWu32() { + var a = SIMD.int32x4(1, 2, 3, 4); + var c = SIMD.int32x4.withW(a, 20); + assertEquals(1, c.x); + assertEquals(2, c.y); + assertEquals(3, c.z); + assertEquals(20, c.w); +} + +testSIMDWithWu32(); +testSIMDWithWu32(); +%OptimizeFunctionOnNextCall(testSIMDWithWu32); +testSIMDWithWu32(); + +function testSIMDWithFlagX() { + var a = SIMD.int32x4.bool(true, false, true, false); + + // boolean + var c = SIMD.int32x4.withFlagX(a, true); + assertEquals(true, c.flagX); + assertEquals(false, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(false, c.flagW); + c = SIMD.int32x4.withFlagX(a, false); + assertEquals(false, c.flagX); + assertEquals(false, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(false, c.flagW); + assertEquals(0x0, c.x); + assertEquals(0x0, c.y); + assertEquals(-1, c.z); + assertEquals(0x0, c.w); + + // smi + c = SIMD.int32x4.withFlagX(a, 2); + assertEquals(true, c.flagX); + assertEquals(false, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(false, c.flagW); + assertEquals(-1, c.x); + assertEquals(0x0, c.y); + assertEquals(-1, c.z); + assertEquals(0x0, c.w); + c = SIMD.int32x4.withFlagX(a, 0); + assertEquals(false, c.flagX); + assertEquals(false, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(false, c.flagW); + assertEquals(0x0, c.x); + assertEquals(0x0, c.y); + assertEquals(-1, c.z); + assertEquals(0x0, c.w); + + // string + c = SIMD.int32x4.withFlagX(a, 'true'); + assertEquals(true, c.flagX); + assertEquals(false, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(false, c.flagW); + assertEquals(-1, c.x); + assertEquals(0x0, c.y); + assertEquals(-1, c.z); + assertEquals(0x0, c.w); + c = SIMD.int32x4.withFlagX(a, ''); + assertEquals(false, c.flagX); + assertEquals(false, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(false, c.flagW); + assertEquals(0x0, c.x); + assertEquals(0x0, c.y); + assertEquals(-1, c.z); + assertEquals(0x0, c.w); + + // heap number + c = SIMD.int32x4.withFlagX(a, 3.14); + assertEquals(true, c.flagX); + assertEquals(false, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(false, c.flagW); + assertEquals(-1, c.x); + assertEquals(0x0, c.y); + assertEquals(-1, c.z); + assertEquals(0x0, c.w); + c = SIMD.int32x4.withFlagX(a, 0.0); + assertEquals(false, c.flagX); + assertEquals(false, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(false, c.flagW); + assertEquals(0x0, c.x); + assertEquals(0x0, c.y); + assertEquals(-1, c.z); + assertEquals(0x0, c.w); + + // JS Array + var array = [1]; + c = SIMD.int32x4.withFlagX(a, array); + assertEquals(true, c.flagX); + assertEquals(false, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(false, c.flagW); + assertEquals(-1, c.x); + assertEquals(0x0, c.y); + assertEquals(-1, c.z); + assertEquals(0x0, c.w); + + c = SIMD.int32x4.withFlagX(a, undefined); + assertEquals(false, c.flagX); + assertEquals(false, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(false, c.flagW); + assertEquals(0x0, c.x); + assertEquals(0x0, c.y); + assertEquals(-1, c.z); + assertEquals(0x0, c.w); +} + +testSIMDWithFlagX(); +testSIMDWithFlagX(); +%OptimizeFunctionOnNextCall(testSIMDWithFlagX); +testSIMDWithFlagX(); + +function testSIMDWithFlagY() { + var a = SIMD.int32x4.bool(true, false, true, false); + var c = SIMD.int32x4.withFlagY(a, true); + assertEquals(true, c.flagX); + assertEquals(true, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(false, c.flagW); + c = SIMD.int32x4.withFlagY(a, false); + assertEquals(true, c.flagX); + assertEquals(false, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(false, c.flagW); + assertEquals(-1, c.x); + assertEquals(0x0, c.y); + assertEquals(-1, c.z); + assertEquals(0x0, c.w); +} + +testSIMDWithFlagY(); +testSIMDWithFlagY(); +%OptimizeFunctionOnNextCall(testSIMDWithFlagY); +testSIMDWithFlagY(); + +function testSIMDWithFlagZ() { + var a = SIMD.int32x4.bool(true, false, true, false); + var c = SIMD.int32x4.withFlagZ(a, true); + assertEquals(true, c.flagX); + assertEquals(false, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(false, c.flagW); + c = SIMD.int32x4.withFlagZ(a, false); + assertEquals(true, c.flagX); + assertEquals(false, c.flagY); + assertEquals(false, c.flagZ); + assertEquals(false, c.flagW); + assertEquals(-1, c.x); + assertEquals(0x0, c.y); + assertEquals(0x0, c.z); + assertEquals(0x0, c.w); +} + +testSIMDWithFlagZ(); +testSIMDWithFlagZ(); +%OptimizeFunctionOnNextCall(testSIMDWithFlagZ); +testSIMDWithFlagZ(); + +function testSIMDWithFlagW() { + var a = SIMD.int32x4.bool(true, false, true, false); + var c = SIMD.int32x4.withFlagW(a, true); + assertEquals(true, c.flagX); + assertEquals(false, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(true, c.flagW); + c = SIMD.int32x4.withFlagW(a, false); + assertEquals(true, c.flagX); + assertEquals(false, c.flagY); + assertEquals(true, c.flagZ); + assertEquals(false, c.flagW); + assertEquals(-1, c.x); + assertEquals(0x0, c.y); + assertEquals(-1, c.z); + assertEquals(0x0, c.w); +} + +testSIMDWithFlagW(); +testSIMDWithFlagW(); +%OptimizeFunctionOnNextCall(testSIMDWithFlagW); +testSIMDWithFlagW(); + +function testSIMDAddu32() { + var a = SIMD.int32x4(-1, -1, 0x7fffffff, 0x0); + var b = SIMD.int32x4(0x1, -1, 0x1, -1); + var c = SIMD.int32x4.add(a, b); + assertEquals(0x0, c.x); + assertEquals(-2, c.y); + assertEquals(0x80000000 - 0xFFFFFFFF - 1, c.z); + assertEquals(-1, c.w); +} + +testSIMDAddu32(); +testSIMDAddu32(); +%OptimizeFunctionOnNextCall(testSIMDAddu32); +testSIMDAddu32(); + +function testSIMDSubu32() { + var a = SIMD.int32x4(-1, -1, 0x80000000 - 0xFFFFFFFF - 1, 0x0); + var b = SIMD.int32x4(0x1, -1, 0x1, -1); + var c = SIMD.int32x4.sub(a, b); + assertEquals(-2, c.x); + assertEquals(0x0, c.y); + assertEquals(0x7FFFFFFF, c.z); + assertEquals(0x1, c.w); +} + +testSIMDSubu32(); +testSIMDSubu32(); +%OptimizeFunctionOnNextCall(testSIMDSubu32); +testSIMDSubu32(); + +function testSIMDMulu32() { + var a = SIMD.int32x4(-1, -1, 0x80000000 - 0xFFFFFFFF - 1, 0x0); + var b = SIMD.int32x4(0x1, -1, 0x80000000 - 0xFFFFFFFF - 1, -1); + var c = SIMD.int32x4.mul(a, b); + assertEquals(-1, c.x); + assertEquals(0x1, c.y); + assertEquals(0x0, c.z); + assertEquals(0x0, c.w); +} + +testSIMDMulu32(); +testSIMDMulu32(); +%OptimizeFunctionOnNextCall(testSIMDMulu32); +testSIMDMulu32(); + +function testSIMDShuffleu32() { + var m = SIMD.int32x4(1, 2, 3, 4); + var xxxx = SIMD.int32x4.shuffle(m, SIMD.XXXX); + assertEquals(1, xxxx.x); + assertEquals(1, xxxx.y); + assertEquals(1, xxxx.z); + assertEquals(1, xxxx.w); + var yyyy = SIMD.int32x4.shuffle(m, SIMD.YYYY); + assertEquals(2, yyyy.x); + assertEquals(2, yyyy.y); + assertEquals(2, yyyy.z); + assertEquals(2, yyyy.w); + var zzzz = SIMD.int32x4.shuffle(m, SIMD.ZZZZ); + assertEquals(3, zzzz.x); + assertEquals(3, zzzz.y); + assertEquals(3, zzzz.z); + assertEquals(3, zzzz.w); + var wwww = SIMD.int32x4.shuffle(m, SIMD.WWWW); + assertEquals(4, wwww.x); + assertEquals(4, wwww.y); + assertEquals(4, wwww.z); + assertEquals(4, wwww.w); + var wzyx = SIMD.int32x4.shuffle(m, SIMD.WZYX); + assertEquals(4, wzyx.x); + assertEquals(3, wzyx.y); + assertEquals(2, wzyx.z); + assertEquals(1, wzyx.w); + var wwzz = SIMD.int32x4.shuffle(m, SIMD.WWZZ); + assertEquals(4, wwzz.x); + assertEquals(4, wwzz.y); + assertEquals(3, wwzz.z); + assertEquals(3, wwzz.w); + var xxyy = SIMD.int32x4.shuffle(m, SIMD.XXYY); + assertEquals(1, xxyy.x); + assertEquals(1, xxyy.y); + assertEquals(2, xxyy.z); + assertEquals(2, xxyy.w); + var yyww = SIMD.int32x4.shuffle(m, SIMD.YYWW); + assertEquals(2, yyww.x); + assertEquals(2, yyww.y); + assertEquals(4, yyww.z); + assertEquals(4, yyww.w); +} + +testSIMDShuffleu32(); +testSIMDShuffleu32(); +%OptimizeFunctionOnNextCall(testSIMDShuffleu32); +testSIMDShuffleu32(); + +function testSIMDComparisons() { + var m = SIMD.int32x4(1, 2, 100, 1); + var n = SIMD.int32x4(2, 2, 1, 100); + var cmp; + cmp = SIMD.int32x4.lessThan(m, n); + assertEquals(-1, cmp.x); + assertEquals(0x0, cmp.y); + assertEquals(0x0, cmp.z); + assertEquals(-1, cmp.w); + + cmp = SIMD.int32x4.equal(m, n); + assertEquals(0x0, cmp.x); + assertEquals(-1, cmp.y); + assertEquals(0x0, cmp.z); + assertEquals(0x0, cmp.w); + + cmp = SIMD.int32x4.greaterThan(m, n); + assertEquals(0x0, cmp.x); + assertEquals(0x0, cmp.y); + assertEquals(-1, cmp.z); + assertEquals(0x0, cmp.w); +} + +testSIMDComparisons(); +testSIMDComparisons(); +%OptimizeFunctionOnNextCall(testSIMDComparisons); +testSIMDComparisons(); + +function testSIMDShift() { + var m = SIMD.int32x4(1, 2, 100, 0); + + var a = SIMD.int32x4.shiftLeft(m, 2); + assertEquals(4, a.x); + assertEquals(8, a.y); + assertEquals(400, a.z); + assertEquals(0, a.w); + + var b = SIMD.int32x4.shiftRight(a, 2); + assertEquals(1, b.x); + assertEquals(2, b.y); + assertEquals(100, b.z); + assertEquals(0, b.w); + + var n = SIMD.int32x4(-8, 2, 1, 100); + + var c = SIMD.int32x4.shiftRightArithmetic(n, 2); + assertEquals(-2, c.x); + assertEquals(0, c.y); + assertEquals(0, c.z); + assertEquals(25, c.w); +} + +testSIMDShift(); +testSIMDShift(); +%OptimizeFunctionOnNextCall(testSIMDShift); +testSIMDShift(); + +function testInt32x4ArrayBasic() { + var a = new Int32x4Array(1); + assertEquals(1, a.length); + assertEquals(16, a.byteLength); + assertEquals(16, a.BYTES_PER_ELEMENT); + assertEquals(16, Int32x4Array.BYTES_PER_ELEMENT); + assertEquals(0, a.byteOffset); + assertTrue(undefined != a.buffer); + var b = new Int32x4Array(4); + assertEquals(4, b.length); + assertEquals(64, b.byteLength); + assertEquals(16, b.BYTES_PER_ELEMENT); + assertEquals(16, Int32x4Array.BYTES_PER_ELEMENT); + assertEquals(0, b.byteOffset); + assertTrue(undefined != b.buffer); +} + +testInt32x4ArrayBasic(); + +function testInt32x4ArrayGetAndSet() { + var a = new Int32x4Array(4); + a[0] = SIMD.int32x4(1, 2, 3, 4); + a[1] = SIMD.int32x4(5, 6, 7, 8); + a[2] = SIMD.int32x4(9, 10, 11, 12); + a[3] = SIMD.int32x4(13, 14, 15, 16); + assertEquals(a[0].x, 1); + assertEquals(a[0].y, 2); + assertEquals(a[0].z, 3); + assertEquals(a[0].w, 4); + + assertEquals(a[1].x, 5); + assertEquals(a[1].y, 6); + assertEquals(a[1].z, 7); + assertEquals(a[1].w, 8); + + assertEquals(a[2].x, 9); + assertEquals(a[2].y, 10); + assertEquals(a[2].z, 11); + assertEquals(a[2].w, 12); + + assertEquals(a[3].x, 13); + assertEquals(a[3].y, 14); + assertEquals(a[3].z, 15); + assertEquals(a[3].w, 16); + + var b = new Int32x4Array(4); + b.setAt(0,SIMD.int32x4(1, 2, 3, 4)); + b.setAt(1,SIMD.int32x4(5, 6, 7, 8)); + b.setAt(2,SIMD.int32x4(9, 10, 11, 12)); + b.setAt(3,SIMD.int32x4(13, 14, 15, 16)); + + assertEquals(b.getAt(0).x, 1); + assertEquals(b.getAt(0).y, 2); + assertEquals(b.getAt(0).z, 3); + assertEquals(b.getAt(0).w, 4); + + assertEquals(b.getAt(1).x, 5); + assertEquals(b.getAt(1).y, 6); + assertEquals(b.getAt(1).z, 7); + assertEquals(b.getAt(1).w, 8); + + assertEquals(b.getAt(2).x, 9); + assertEquals(b.getAt(2).y, 10); + assertEquals(b.getAt(2).z, 11); + assertEquals(b.getAt(2).w, 12); + + assertEquals(b.getAt(3).x, 13); + assertEquals(b.getAt(3).y, 14); + assertEquals(b.getAt(3).z, 15); + assertEquals(b.getAt(3).w, 16); +} + +testInt32x4ArrayGetAndSet(); + +function testInt32x4ArraySwap() { + var a = new Int32x4Array(4); + a[0] = SIMD.int32x4(1, 2, 3, 4); + a[1] = SIMD.int32x4(5, 6, 7, 8); + a[2] = SIMD.int32x4(9, 10, 11, 12); + a[3] = SIMD.int32x4(13, 14, 15, 16); + + // Swap element 0 and element 3 + var t = a[0]; + a[0] = a[3]; + a[3] = t; + + assertEquals(a[3].x, 1); + assertEquals(a[3].y, 2); + assertEquals(a[3].z, 3); + assertEquals(a[3].w, 4); + + assertEquals(a[1].x, 5); + assertEquals(a[1].y, 6); + assertEquals(a[1].z, 7); + assertEquals(a[1].w, 8); + + assertEquals(a[2].x, 9); + assertEquals(a[2].y, 10); + assertEquals(a[2].z, 11); + assertEquals(a[2].w, 12); + + assertEquals(a[0].x, 13); + assertEquals(a[0].y, 14); + assertEquals(a[0].z, 15); + assertEquals(a[0].w, 16); +} + +testInt32x4ArraySwap(); +testInt32x4ArraySwap(); +%OptimizeFunctionOnNextCall(testInt32x4ArraySwap); +testInt32x4ArraySwap(); + +function testInt32x4ArrayCopy() { + var a = new Int32x4Array(4); + a[0] = SIMD.int32x4(1, 2, 3, 4); + a[1] = SIMD.int32x4(5, 6, 7, 8); + a[2] = SIMD.int32x4(9, 10, 11, 12); + a[3] = SIMD.int32x4(13, 14, 15, 16); + var b = new Int32x4Array(a); + assertEquals(a[0].x, b[0].x); + assertEquals(a[0].y, b[0].y); + assertEquals(a[0].z, b[0].z); + assertEquals(a[0].w, b[0].w); + + assertEquals(a[1].x, b[1].x); + assertEquals(a[1].y, b[1].y); + assertEquals(a[1].z, b[1].z); + assertEquals(a[1].w, b[1].w); + + assertEquals(a[2].x, b[2].x); + assertEquals(a[2].y, b[2].y); + assertEquals(a[2].z, b[2].z); + assertEquals(a[2].w, b[2].w); + + assertEquals(a[3].x, b[3].x); + assertEquals(a[3].y, b[3].y); + assertEquals(a[3].z, b[3].z); + assertEquals(a[3].w, b[3].w); + + a[2] = SIMD.int32x4(17, 18, 19, 20); + + assertEquals(a[2].x, 17); + assertEquals(a[2].y, 18); + assertEquals(a[2].z, 19); + assertEquals(a[2].w, 20); + + assertTrue(a[2].x != b[2].x); + assertTrue(a[2].y != b[2].y); + assertTrue(a[2].z != b[2].z); + assertTrue(a[2].w != b[2].w); +} + +testInt32x4ArrayCopy(); + +function testInt32x4ArrayViewBasic() { + var a = new Uint32Array(8); + // view with no offset. + var b = new Int32x4Array(a.buffer, 0); + // view with offset. + var c = new Int32x4Array(a.buffer, 16); + // view with no offset but shorter than original list. + var d = new Int32x4Array(a.buffer, 0, 1); + assertEquals(a.length, 8); + assertEquals(b.length, 2); + assertEquals(c.length, 1); + assertEquals(d.length, 1); + assertEquals(a.byteLength, 32); + assertEquals(b.byteLength, 32); + assertEquals(c.byteLength, 16); + assertEquals(d.byteLength, 16) + assertEquals(a.byteOffset, 0); + assertEquals(b.byteOffset, 0); + assertEquals(c.byteOffset, 16); + assertEquals(d.byteOffset, 0); +} + +testInt32x4ArrayViewBasic(); + +function testInt32x4ArrayViewValues() { + var a = new Uint32Array(8); + var b = new Int32x4Array(a.buffer, 0); + var c = new Int32x4Array(a.buffer, 16); + var d = new Int32x4Array(a.buffer, 0, 1); + var start = 100; + for (var i = 0; i < b.length; i++) { + assertEquals(0, b[i].x); + assertEquals(0, b[i].y); + assertEquals(0, b[i].z); + assertEquals(0, b[i].w); + } + for (var i = 0; i < c.length; i++) { + assertEquals(0, c[i].x); + assertEquals(0, c[i].y); + assertEquals(0, c[i].z); + assertEquals(0, c[i].w); + } + for (var i = 0; i < d.length; i++) { + assertEquals(0, d[i].x); + assertEquals(0, d[i].y); + assertEquals(0, d[i].z); + assertEquals(0, d[i].w); + } + for (var i = 0; i < a.length; i++) { + a[i] = i+start; + } + for (var i = 0; i < b.length; i++) { + assertTrue(0 != b[i].x); + assertTrue(0 != b[i].y); + assertTrue(0 != b[i].z); + assertTrue(0 != b[i].w); + } + for (var i = 0; i < c.length; i++) { + assertTrue(0 != c[i].x); + assertTrue(0 != c[i].y); + assertTrue(0 != c[i].z); + assertTrue(0 != c[i].w); + } + for (var i = 0; i < d.length; i++) { + assertTrue(0 != d[i].x); + assertTrue(0 != d[i].y); + assertTrue(0 != d[i].z); + assertTrue(0 != d[i].w); + } + assertEquals(start+0, b[0].x); + assertEquals(start+1, b[0].y); + assertEquals(start+2, b[0].z); + assertEquals(start+3, b[0].w); + assertEquals(start+4, b[1].x); + assertEquals(start+5, b[1].y); + assertEquals(start+6, b[1].z); + assertEquals(start+7, b[1].w); + + assertEquals(start+4, c[0].x); + assertEquals(start+5, c[0].y); + assertEquals(start+6, c[0].z); + assertEquals(start+7, c[0].w); + + assertEquals(start+0, d[0].x); + assertEquals(start+1, d[0].y); + assertEquals(start+2, d[0].z); + assertEquals(start+3, d[0].w); +} + +testInt32x4ArrayViewValues(); + +function testViewOnInt32x4Array() { + var a = new Int32x4Array(4); + a[0] = SIMD.int32x4(1, 2, 3, 4); + a[1] = SIMD.int32x4(5, 6, 7, 8); + a[2] = SIMD.int32x4(9, 10, 11, 12); + a[3] = SIMD.int32x4(13, 14, 15, 16); + assertEquals(a[0].x, 1); + assertEquals(a[0].y, 2); + assertEquals(a[0].z, 3); + assertEquals(a[0].w, 4); + + assertEquals(a[1].x, 5); + assertEquals(a[1].y, 6); + assertEquals(a[1].z, 7); + assertEquals(a[1].w, 8); + + assertEquals(a[2].x, 9); + assertEquals(a[2].y, 10); + assertEquals(a[2].z, 11); + assertEquals(a[2].w, 12); + + assertEquals(a[3].x, 13); + assertEquals(a[3].y, 14); + assertEquals(a[3].z, 15); + assertEquals(a[3].w, 16); + + // Create view on a. + var b = new Uint32Array(a.buffer); + assertEquals(b.length, 16); + assertEquals(b.byteLength, 64); + b[2] = 99.0; + b[6] = 1.0; + + // Observe changes in "a" + assertEquals(a[0].x, 1); + assertEquals(a[0].y, 2); + assertEquals(a[0].z, 99); + assertEquals(a[0].w, 4); + + assertEquals(a[1].x, 5); + assertEquals(a[1].y, 6); + assertEquals(a[1].z, 1); + assertEquals(a[1].w, 8); + + assertEquals(a[2].x, 9); + assertEquals(a[2].y, 10); + assertEquals(a[2].z, 11); + assertEquals(a[2].w, 12); + + assertEquals(a[3].x, 13); + assertEquals(a[3].y, 14); + assertEquals(a[3].z, 15); + assertEquals(a[3].w, 16); +} + +testViewOnInt32x4Array(); + +function testArrayOfInt32x4() { + var a = []; + var a4 = new Int32x4Array(2); + for (var i = 0; i < a4.length; i++) { + a[i] = SIMD.int32x4(i, i + 1, i + 2, i + 3); + a4[i] = SIMD.int32x4(i, i + 1, i + 2, i + 3); + } + + for (var i = 0; i < a4.length; i++) { + assertEquals(a[i].x, a4[i].x); + assertEquals(a[i].y, a4[i].y); + assertEquals(a[i].z, a4[i].z); + assertEquals(a[i].w, a4[i].w); + } +} + +testArrayOfInt32x4(); diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index d78853789c8..e4a04165859 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -1026,7 +1026,8 @@ '../../src/array-iterator.js', '../../src/harmony-string.js', '../../src/harmony-array.js', - '../../src/harmony-math.js' + '../../src/harmony-math.js', + '../../src/simd128.js', ], }, 'actions': [ diff --git a/tools/js2c.py b/tools/js2c.py index f67d053ad26..e6607c2b76a 100755 --- a/tools/js2c.py +++ b/tools/js2c.py @@ -358,9 +358,9 @@ def JS2C(source, target, env): debugger = filename.endswith('-debugger.js') lines = ReadFile(filename) lines = ExpandConstants(lines, consts) + lines = ExpandInlineMacros(lines, filename) lines = ExpandMacros(lines, macros) lines = RemoveCommentsAndTrailingWhitespace(lines) - lines = ExpandInlineMacros(lines, filename) Validate(lines, filename) lines = minifier.JSMinify(lines) id = (os.path.split(filename)[1])[:-3]