diff options
author | Moonchild <moonchild@palemoon.org> | 2023-09-18 16:57:09 +0200 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2023-09-18 16:57:09 +0200 |
commit | 7003ea7dc4e6164fc2451e4255da0cc1a7b4d22f (patch) | |
tree | 3a098fa1b2914b1c7cd6eea39fc0fc53ce3b9fa1 /js/src | |
parent | 8635073418a294520172bf5b05d886b35e4bcdc3 (diff) | |
download | uxp-7003ea7dc4e6164fc2451e4255da0cc1a7b4d22f.tar.gz |
Issue #2307 - Part 3: Remove SIMD.js support
This gets rid of the SIMD-specific scalar types in JS.
This considerably deviates from Mozilla's work because of our divergent
path.
Diffstat (limited to 'js/src')
157 files changed, 147 insertions, 21186 deletions
diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp deleted file mode 100644 index 93476c5db3..0000000000 --- a/js/src/builtin/SIMD.cpp +++ /dev/null @@ -1,1551 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * JS SIMD pseudo-module. - * Specification matches polyfill: - * https://github.com/johnmccutchan/ecmascript_simd/blob/master/src/ecmascript_simd.js - * The objects float32x4 and int32x4 are installed on the SIMD pseudo-module. - */ - -#include "builtin/SIMD.h" - -#include "mozilla/FloatingPoint.h" -#include "mozilla/IntegerTypeTraits.h" -#include "mozilla/Sprintf.h" - -#include "jsapi.h" -#include "jsfriendapi.h" -#include "jsnum.h" -#include "jsprf.h" - -#include "builtin/TypedObject.h" -#include "jit/InlinableNatives.h" -#include "js/GCAPI.h" -#include "js/Value.h" - -#include "jsobjinlines.h" - -using namespace js; - -using mozilla::ArrayLength; -using mozilla::IsFinite; -using mozilla::IsNaN; -using mozilla::FloorLog2; -using mozilla::NumberIsInt32; - -/////////////////////////////////////////////////////////////////////////// -// SIMD - -static_assert(unsigned(SimdType::Count) == 12, "sync with TypedObjectConstants.h"); - -static bool ArgumentToLaneIndex(JSContext* cx, JS::HandleValue v, unsigned limit, unsigned* lane); - -static bool -CheckVectorObject(HandleValue v, SimdType expectedType) -{ - if (!v.isObject()) - return false; - - JSObject& obj = v.toObject(); - if (!obj.is<TypedObject>()) - return false; - - TypeDescr& typeRepr = obj.as<TypedObject>().typeDescr(); - if (typeRepr.kind() != type::Simd) - return false; - - return typeRepr.as<SimdTypeDescr>().type() == expectedType; -} - -template<class V> -bool -js::IsVectorObject(HandleValue v) -{ - return CheckVectorObject(v, V::type); -} - -#define FOR_EACH_SIMD(macro) \ - macro(Int8x16) \ - macro(Int16x8) \ - macro(Int32x4) \ - macro(Uint8x16) \ - macro(Uint16x8) \ - macro(Uint32x4) \ - macro(Float32x4) \ - macro(Float64x2) \ - macro(Bool8x16) \ - macro(Bool16x8) \ - macro(Bool32x4) \ - macro(Bool64x2) - -#define InstantiateIsVectorObject_(T) \ - template bool js::IsVectorObject<T>(HandleValue v); -FOR_EACH_SIMD(InstantiateIsVectorObject_) -#undef InstantiateIsVectorObject_ - -const char* -js::SimdTypeToString(SimdType type) -{ - switch (type) { -#define RETSTR_(TYPE) case SimdType::TYPE: return #TYPE; - FOR_EACH_SIMD(RETSTR_) -#undef RETSTR_ - case SimdType::Count: break; - } - return "<bad SimdType>"; -} - -PropertyName* -js::SimdTypeToName(const JSAtomState& atoms, SimdType type) -{ - switch (type) { -#define CASE_(TypeName) case SimdType::TypeName: return atoms.TypeName; - FOR_EACH_SIMD(CASE_) -#undef CASE_ - case SimdType::Count: break; - } - MOZ_CRASH("bad SIMD type"); -} - -bool -js::IsSimdTypeName(const JSAtomState& atoms, const PropertyName* name, SimdType* type) -{ -#define CHECK_(TypeName) if (name == atoms.TypeName) { \ - *type = SimdType::TypeName; \ - return true; \ - } - FOR_EACH_SIMD(CHECK_) -#undef CHECK_ - return false; -} - -static inline bool -ErrorBadArgs(JSContext* cx) -{ - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); - return false; -} - -static inline bool -ErrorWrongTypeArg(JSContext* cx, unsigned argIndex, Handle<TypeDescr*> typeDescr) -{ - MOZ_ASSERT(argIndex < 10); - char charArgIndex[2]; - SprintfLiteral(charArgIndex, "%u", argIndex); - - HeapSlot& typeNameSlot = typeDescr->getReservedSlotRef(JS_DESCR_SLOT_STRING_REPR); - char* typeNameStr = JS_EncodeString(cx, typeNameSlot.toString()); - if (!typeNameStr) - return false; - - JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_SIMD_NOT_A_VECTOR, - typeNameStr, charArgIndex); - JS_free(cx, typeNameStr); - return false; -} - -static inline bool -ErrorBadIndex(JSContext* cx) -{ - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX); - return false; -} - -template<typename T> -static SimdTypeDescr* -GetTypeDescr(JSContext* cx) -{ - RootedGlobalObject global(cx, cx->global()); - return GlobalObject::getOrCreateSimdTypeDescr(cx, global, T::type); -} - -template<typename V> -bool -js::ToSimdConstant(JSContext* cx, HandleValue v, jit::SimdConstant* out) -{ - typedef typename V::Elem Elem; - Rooted<TypeDescr*> typeDescr(cx, GetTypeDescr<V>(cx)); - if (!typeDescr) - return false; - if (!IsVectorObject<V>(v)) - return ErrorWrongTypeArg(cx, 1, typeDescr); - - JS::AutoCheckCannotGC nogc(cx); - Elem* mem = reinterpret_cast<Elem*>(v.toObject().as<TypedObject>().typedMem(nogc)); - *out = jit::SimdConstant::CreateSimd128(mem); - return true; -} - -template bool js::ToSimdConstant<Int8x16>(JSContext* cx, HandleValue v, jit::SimdConstant* out); -template bool js::ToSimdConstant<Int16x8>(JSContext* cx, HandleValue v, jit::SimdConstant* out); -template bool js::ToSimdConstant<Int32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out); -template bool js::ToSimdConstant<Float32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out); -template bool js::ToSimdConstant<Bool8x16>(JSContext* cx, HandleValue v, jit::SimdConstant* out); -template bool js::ToSimdConstant<Bool16x8>(JSContext* cx, HandleValue v, jit::SimdConstant* out); -template bool js::ToSimdConstant<Bool32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out); - -template<typename Elem> -static Elem -TypedObjectMemory(HandleValue v, const JS::AutoRequireNoGC& nogc) -{ - TypedObject& obj = v.toObject().as<TypedObject>(); - return reinterpret_cast<Elem>(obj.typedMem(nogc)); -} - -static const ClassOps SimdTypeDescrClassOps = { - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - TypeDescr::finalize, - SimdTypeDescr::call -}; - -const Class SimdTypeDescr::class_ = { - "SIMD", - JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE, - &SimdTypeDescrClassOps -}; - -namespace { - -// Define classes (Int8x16Defn, Int16x8Defn, etc.) to group together various -// properties and so on. -#define DEFINE_DEFN_(TypeName) \ -class TypeName##Defn { \ - public: \ - static const JSFunctionSpec Methods[]; \ -}; - -FOR_EACH_SIMD(DEFINE_DEFN_) -#undef DEFINE_DEFN_ - -} // namespace - -// Shared type descriptor methods for all SIMD types. -static const JSFunctionSpec TypeDescriptorMethods[] = { - JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0), - JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0), - JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0), - JS_FS_END -}; - -// Shared TypedObject methods for all SIMD types. -static const JSFunctionSpec SimdTypedObjectMethods[] = { - JS_SELF_HOSTED_FN("toString", "SimdToString", 0, 0), - JS_SELF_HOSTED_FN("valueOf", "SimdValueOf", 0, 0), - JS_SELF_HOSTED_FN("toSource", "SimdToSource", 0, 0), - JS_FS_END -}; - -// Provide JSJitInfo structs for those types that are supported by Ion. -// The controlling SIMD type is encoded as the InlinableNative primary opcode. -// The SimdOperation within the type is encoded in the .depth field. -// -// The JS_INLINABLE_FN macro refers to js::JitInfo_##native which we provide as -// Simd##Type##_##Operation -// -// /!\ Don't forget to keep this list in sync with the SIMD instrinics used in -// SelfHosting.cpp. - -namespace js { -namespace jit { - -static_assert(uint64_t(SimdOperation::Last) <= UINT16_MAX, "SimdOperation must fit in uint16_t"); - -// See also JitInfo_* in MCallOptimize.cpp. We provide a JSJitInfo for all the -// named functions here. The default JitInfo_SimdInt32x4 etc structs represent the -// SimdOperation::Constructor. -#define DEFN(TYPE, OP) const JSJitInfo JitInfo_Simd##TYPE##_##OP = { \ - /* .getter, unused for inlinable natives. */ \ - { nullptr }, \ - /* .inlinableNative, but we have to init first union member: .protoID. */ \ - { uint16_t(InlinableNative::Simd##TYPE) }, \ - /* .nativeOp. Actually initializing first union member .depth. */ \ - { uint16_t(SimdOperation::Fn_##OP) }, \ - /* .type_ bitfield says this in an inlinable native function. */ \ - JSJitInfo::InlinableNative \ - /* Remaining fields are not used for inlinable natives. They are zero-initialized. */ \ -}; - -// This list of inlinable types should match the one in jit/InlinableNatives.h. -#define TDEFN(Name, Func, Operands) DEFN(Float32x4, Name) -FLOAT32X4_FUNCTION_LIST(TDEFN) -#undef TDEFN - -#define TDEFN(Name, Func, Operands) DEFN(Int8x16, Name) -INT8X16_FUNCTION_LIST(TDEFN) -#undef TDEFN - -#define TDEFN(Name, Func, Operands) DEFN(Uint8x16, Name) -UINT8X16_FUNCTION_LIST(TDEFN) -#undef TDEFN - -#define TDEFN(Name, Func, Operands) DEFN(Int16x8, Name) -INT16X8_FUNCTION_LIST(TDEFN) -#undef TDEFN - -#define TDEFN(Name, Func, Operands) DEFN(Uint16x8, Name) -UINT16X8_FUNCTION_LIST(TDEFN) -#undef TDEFN - -#define TDEFN(Name, Func, Operands) DEFN(Int32x4, Name) -INT32X4_FUNCTION_LIST(TDEFN) -#undef TDEFN - -#define TDEFN(Name, Func, Operands) DEFN(Uint32x4, Name) -UINT32X4_FUNCTION_LIST(TDEFN) -#undef TDEFN - -#define TDEFN(Name, Func, Operands) DEFN(Bool8x16, Name) -BOOL8X16_FUNCTION_LIST(TDEFN) -#undef TDEFN - -#define TDEFN(Name, Func, Operands) DEFN(Bool16x8, Name) -BOOL16X8_FUNCTION_LIST(TDEFN) -#undef TDEFN - -#define TDEFN(Name, Func, Operands) DEFN(Bool32x4, Name) -BOOL32X4_FUNCTION_LIST(TDEFN) -#undef TDEFN - -} // namespace jit -} // namespace js - -const JSFunctionSpec Float32x4Defn::Methods[] = { -#define SIMD_FLOAT32X4_FUNCTION_ITEM(Name, Func, Operands) \ - JS_INLINABLE_FN(#Name, js::simd_float32x4_##Name, Operands, 0, SimdFloat32x4_##Name), - FLOAT32X4_FUNCTION_LIST(SIMD_FLOAT32X4_FUNCTION_ITEM) -#undef SIMD_FLOAT32x4_FUNCTION_ITEM - JS_FS_END -}; - -const JSFunctionSpec Float64x2Defn::Methods[] = { -#define SIMD_FLOAT64X2_FUNCTION_ITEM(Name, Func, Operands) \ - JS_FN(#Name, js::simd_float64x2_##Name, Operands, 0), - FLOAT64X2_FUNCTION_LIST(SIMD_FLOAT64X2_FUNCTION_ITEM) -#undef SIMD_FLOAT64X2_FUNCTION_ITEM - JS_FS_END -}; - -const JSFunctionSpec Int8x16Defn::Methods[] = { -#define SIMD_INT8X16_FUNCTION_ITEM(Name, Func, Operands) \ - JS_INLINABLE_FN(#Name, js::simd_int8x16_##Name, Operands, 0, SimdInt8x16_##Name), - INT8X16_FUNCTION_LIST(SIMD_INT8X16_FUNCTION_ITEM) -#undef SIMD_INT8X16_FUNCTION_ITEM - JS_FS_END -}; - -const JSFunctionSpec Int16x8Defn::Methods[] = { -#define SIMD_INT16X8_FUNCTION_ITEM(Name, Func, Operands) \ - JS_INLINABLE_FN(#Name, js::simd_int16x8_##Name, Operands, 0, SimdInt16x8_##Name), - INT16X8_FUNCTION_LIST(SIMD_INT16X8_FUNCTION_ITEM) -#undef SIMD_INT16X8_FUNCTION_ITEM - JS_FS_END -}; - -const JSFunctionSpec Int32x4Defn::Methods[] = { -#define SIMD_INT32X4_FUNCTION_ITEM(Name, Func, Operands) \ - JS_INLINABLE_FN(#Name, js::simd_int32x4_##Name, Operands, 0, SimdInt32x4_##Name), - INT32X4_FUNCTION_LIST(SIMD_INT32X4_FUNCTION_ITEM) -#undef SIMD_INT32X4_FUNCTION_ITEM - JS_FS_END -}; - -const JSFunctionSpec Uint8x16Defn::Methods[] = { -#define SIMD_UINT8X16_FUNCTION_ITEM(Name, Func, Operands) \ - JS_INLINABLE_FN(#Name, js::simd_uint8x16_##Name, Operands, 0, SimdUint8x16_##Name), - UINT8X16_FUNCTION_LIST(SIMD_UINT8X16_FUNCTION_ITEM) -#undef SIMD_UINT8X16_FUNCTION_ITEM - JS_FS_END -}; - -const JSFunctionSpec Uint16x8Defn::Methods[] = { -#define SIMD_UINT16X8_FUNCTION_ITEM(Name, Func, Operands) \ - JS_INLINABLE_FN(#Name, js::simd_uint16x8_##Name, Operands, 0, SimdUint16x8_##Name), - UINT16X8_FUNCTION_LIST(SIMD_UINT16X8_FUNCTION_ITEM) -#undef SIMD_UINT16X8_FUNCTION_ITEM - JS_FS_END -}; - -const JSFunctionSpec Uint32x4Defn::Methods[] = { -#define SIMD_UINT32X4_FUNCTION_ITEM(Name, Func, Operands) \ - JS_INLINABLE_FN(#Name, js::simd_uint32x4_##Name, Operands, 0, SimdUint32x4_##Name), - UINT32X4_FUNCTION_LIST(SIMD_UINT32X4_FUNCTION_ITEM) -#undef SIMD_UINT32X4_FUNCTION_ITEM - JS_FS_END -}; - -const JSFunctionSpec Bool8x16Defn::Methods[] = { -#define SIMD_BOOL8X16_FUNCTION_ITEM(Name, Func, Operands) \ - JS_INLINABLE_FN(#Name, js::simd_bool8x16_##Name, Operands, 0, SimdBool8x16_##Name), - BOOL8X16_FUNCTION_LIST(SIMD_BOOL8X16_FUNCTION_ITEM) -#undef SIMD_BOOL8X16_FUNCTION_ITEM - JS_FS_END -}; - -const JSFunctionSpec Bool16x8Defn::Methods[] = { -#define SIMD_BOOL16X8_FUNCTION_ITEM(Name, Func, Operands) \ - JS_INLINABLE_FN(#Name, js::simd_bool16x8_##Name, Operands, 0, SimdBool16x8_##Name), - BOOL16X8_FUNCTION_LIST(SIMD_BOOL16X8_FUNCTION_ITEM) -#undef SIMD_BOOL16X8_FUNCTION_ITEM - JS_FS_END -}; - -const JSFunctionSpec Bool32x4Defn::Methods[] = { -#define SIMD_BOOL32X4_FUNCTION_ITEM(Name, Func, Operands) \ - JS_INLINABLE_FN(#Name, js::simd_bool32x4_##Name, Operands, 0, SimdBool32x4_##Name), - BOOL32X4_FUNCTION_LIST(SIMD_BOOL32X4_FUNCTION_ITEM) -#undef SIMD_BOOL32X4_FUNCTION_ITEM - JS_FS_END -}; - -const JSFunctionSpec Bool64x2Defn::Methods[] = { -#define SIMD_BOOL64X2_FUNCTION_ITEM(Name, Func, Operands) \ - JS_FN(#Name, js::simd_bool64x2_##Name, Operands, 0), - BOOL64X2_FUNCTION_LIST(SIMD_BOOL64X2_FUNCTION_ITEM) -#undef SIMD_BOOL64x2_FUNCTION_ITEM - JS_FS_END -}; - -template <typename T> -static bool -FillLanes(JSContext* cx, Handle<TypedObject*> result, const CallArgs& args) -{ - typedef typename T::Elem Elem; - Elem tmp; - for (unsigned i = 0; i < T::lanes; i++) { - if (!T::Cast(cx, args.get(i), &tmp)) - return false; - // Reassure typedMem() that we won't GC while holding onto the returned - // pointer, even though we could GC on every iteration of this loop - // (but it is safe because we re-fetch each time.) - JS::AutoCheckCannotGC nogc(cx); - reinterpret_cast<Elem*>(result->typedMem(nogc))[i] = tmp; - } - args.rval().setObject(*result); - return true; -} - -bool -SimdTypeDescr::call(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - Rooted<SimdTypeDescr*> descr(cx, &args.callee().as<SimdTypeDescr>()); - Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, descr, 0)); - if (!result) - return false; - -#define CASE_CALL_(Type) \ - case SimdType::Type: return FillLanes< ::Type>(cx, result, args); - - switch (descr->type()) { - FOR_EACH_SIMD(CASE_CALL_) - case SimdType::Count: break; - } - -#undef CASE_CALL_ - MOZ_CRASH("unexpected SIMD descriptor"); - return false; -} - -/////////////////////////////////////////////////////////////////////////// -// SIMD class - -static const ClassOps SimdObjectClassOps = { - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - SimdObject::resolve -}; - -const Class SimdObject::class_ = { - "SIMD", - JSCLASS_HAS_RESERVED_SLOTS(uint32_t(SimdType::Count)), - &SimdObjectClassOps -}; - -/* static */ bool -GlobalObject::initSimdObject(JSContext* cx, Handle<GlobalObject*> global) -{ - // SIMD relies on the TypedObject module being initialized. - // In particular, the self-hosted code for array() wants - // to be able to call GetTypedObjectModule(). It is NOT necessary - // to install the TypedObjectModule global, but at the moment - // those two things are not separable. - if (!GlobalObject::getOrCreateTypedObjectModule(cx, global)) - return false; - - RootedObject globalSimdObject(cx); - RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); - if (!objProto) - return false; - - globalSimdObject = NewObjectWithGivenProto(cx, &SimdObject::class_, objProto, SingletonObject); - if (!globalSimdObject) - return false; - - RootedValue globalSimdValue(cx, ObjectValue(*globalSimdObject)); - if (!DefineProperty(cx, global, cx->names().SIMD, globalSimdValue, nullptr, nullptr, - JSPROP_RESOLVING)) - { - return false; - } - - global->setConstructor(JSProto_SIMD, globalSimdValue); - return true; -} - -static bool -CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName stringRepr, - SimdType simdType, const JSFunctionSpec* methods) -{ - RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global)); - if (!funcProto) - return false; - - // Create type constructor itself and initialize its reserved slots. - Rooted<SimdTypeDescr*> typeDescr(cx); - typeDescr = NewObjectWithGivenProto<SimdTypeDescr>(cx, funcProto, SingletonObject); - if (!typeDescr) - return false; - - typeDescr->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(type::Simd)); - typeDescr->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr)); - typeDescr->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(SimdTypeDescr::alignment(simdType))); - typeDescr->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(SimdTypeDescr::size(simdType))); - typeDescr->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(false)); - typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(uint8_t(simdType))); - - if (!CreateUserSizeAndAlignmentProperties(cx, typeDescr)) - return false; - - // Create prototype property, which inherits from Object.prototype. - RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); - if (!objProto) - return false; - Rooted<TypedProto*> proto(cx); - proto = NewObjectWithGivenProto<TypedProto>(cx, objProto, SingletonObject); - if (!proto) - return false; - typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*proto)); - - // Link constructor to prototype and install properties. - if (!JS_DefineFunctions(cx, typeDescr, TypeDescriptorMethods)) - return false; - - if (!LinkConstructorAndPrototype(cx, typeDescr, proto) || - !JS_DefineFunctions(cx, proto, SimdTypedObjectMethods)) - { - return false; - } - - // Bind type descriptor to the global SIMD object - RootedObject globalSimdObject(cx, GlobalObject::getOrCreateSimdGlobalObject(cx, global)); - MOZ_ASSERT(globalSimdObject); - - RootedValue typeValue(cx, ObjectValue(*typeDescr)); - if (!JS_DefineFunctions(cx, typeDescr, methods) || - !DefineProperty(cx, globalSimdObject, stringRepr, typeValue, nullptr, nullptr, - JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_RESOLVING)) - { - return false; - } - - uint32_t slot = uint32_t(typeDescr->type()); - MOZ_ASSERT(globalSimdObject->as<NativeObject>().getReservedSlot(slot).isUndefined()); - globalSimdObject->as<NativeObject>().setReservedSlot(slot, ObjectValue(*typeDescr)); - return !!typeDescr; -} - -/* static */ bool -GlobalObject::initSimdType(JSContext* cx, Handle<GlobalObject*> global, SimdType simdType) -{ -#define CREATE_(Type) \ - case SimdType::Type: \ - return CreateSimdType(cx, global, cx->names().Type, simdType, Type##Defn::Methods); - - switch (simdType) { - FOR_EACH_SIMD(CREATE_) - case SimdType::Count: break; - } - MOZ_CRASH("unexpected simd type"); - -#undef CREATE_ -} - -/* static */ SimdTypeDescr* -GlobalObject::getOrCreateSimdTypeDescr(JSContext* cx, Handle<GlobalObject*> global, - SimdType simdType) -{ - MOZ_ASSERT(unsigned(simdType) < unsigned(SimdType::Count), "Invalid SIMD type"); - - RootedObject globalSimdObject(cx, GlobalObject::getOrCreateSimdGlobalObject(cx, global)); - if (!globalSimdObject) - return nullptr; - - uint32_t typeSlotIndex = uint32_t(simdType); - if (globalSimdObject->as<NativeObject>().getReservedSlot(typeSlotIndex).isUndefined() && - !GlobalObject::initSimdType(cx, global, simdType)) - { - return nullptr; - } - - const Value& slot = globalSimdObject->as<NativeObject>().getReservedSlot(typeSlotIndex); - MOZ_ASSERT(slot.isObject()); - return &slot.toObject().as<SimdTypeDescr>(); -} - -bool -SimdObject::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolved) -{ - *resolved = false; - if (!JSID_IS_ATOM(id)) - return true; - JSAtom* str = JSID_TO_ATOM(id); - Rooted<GlobalObject*> global(cx, cx->global()); -#define TRY_RESOLVE_(Type) \ - if (str == cx->names().Type) { \ - *resolved = CreateSimdType(cx, global, cx->names().Type, \ - SimdType::Type, Type##Defn::Methods); \ - return *resolved; \ - } - FOR_EACH_SIMD(TRY_RESOLVE_) -#undef TRY_RESOLVE_ - return true; -} - -JSObject* -js::InitSimdClass(JSContext* cx, HandleObject obj) -{ - Handle<GlobalObject*> global = obj.as<GlobalObject>(); - return GlobalObject::getOrCreateSimdGlobalObject(cx, global); -} - -template<typename V> -JSObject* -js::CreateSimd(JSContext* cx, const typename V::Elem* data) -{ - typedef typename V::Elem Elem; - Rooted<TypeDescr*> typeDescr(cx, GetTypeDescr<V>(cx)); - if (!typeDescr) - return nullptr; - - Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, typeDescr, 0)); - if (!result) - return nullptr; - - JS::AutoCheckCannotGC nogc(cx); - Elem* resultMem = reinterpret_cast<Elem*>(result->typedMem(nogc)); - memcpy(resultMem, data, sizeof(Elem) * V::lanes); - return result; -} - -#define InstantiateCreateSimd_(Type) \ - template JSObject* js::CreateSimd<Type>(JSContext* cx, const Type::Elem* data); - -FOR_EACH_SIMD(InstantiateCreateSimd_) - -#undef InstantiateCreateSimd_ - -#undef FOR_EACH_SIMD - -namespace js { -// Unary SIMD operators -template<typename T> -struct Identity { - static T apply(T x) { return x; } -}; -template<typename T> -struct Abs { - static T apply(T x) { return mozilla::Abs(x); } -}; -template<typename T> -struct Neg { - static T apply(T x) { return -1 * x; } -}; -template<typename T> -struct Not { - static T apply(T x) { return ~x; } -}; -template<typename T> -struct LogicalNot { - static T apply(T x) { return !x; } -}; -template<typename T> -struct RecApprox { - static T apply(T x) { return 1 / x; } -}; -template<typename T> -struct RecSqrtApprox { - static T apply(T x) { return 1 / sqrt(x); } -}; -template<typename T> -struct Sqrt { - static T apply(T x) { return sqrt(x); } -}; - -// Binary SIMD operators -template<typename T> -struct Add { - static T apply(T l, T r) { return l + r; } -}; -template<typename T> -struct Sub { - static T apply(T l, T r) { return l - r; } -}; -template<typename T> -struct Div { - static T apply(T l, T r) { return l / r; } -}; -template<typename T> -struct Mul { - static T apply(T l, T r) { return l * r; } -}; -template<typename T> -struct Minimum { - static T apply(T l, T r) { return math_min_impl(l, r); } -}; -template<typename T> -struct MinNum { - static T apply(T l, T r) { return IsNaN(l) ? r : (IsNaN(r) ? l : math_min_impl(l, r)); } -}; -template<typename T> -struct Maximum { - static T apply(T l, T r) { return math_max_impl(l, r); } -}; -template<typename T> -struct MaxNum { - static T apply(T l, T r) { return IsNaN(l) ? r : (IsNaN(r) ? l : math_max_impl(l, r)); } -}; -template<typename T> -struct LessThan { - static bool apply(T l, T r) { return l < r; } -}; -template<typename T> -struct LessThanOrEqual { - static bool apply(T l, T r) { return l <= r; } -}; -template<typename T> -struct GreaterThan { - static bool apply(T l, T r) { return l > r; } -}; -template<typename T> -struct GreaterThanOrEqual { - static bool apply(T l, T r) { return l >= r; } -}; -template<typename T> -struct Equal { - static bool apply(T l, T r) { return l == r; } -}; -template<typename T> -struct NotEqual { - static bool apply(T l, T r) { return l != r; } -}; -template<typename T> -struct Xor { - static T apply(T l, T r) { return l ^ r; } -}; -template<typename T> -struct And { - static T apply(T l, T r) { return l & r; } -}; -template<typename T> -struct Or { - static T apply(T l, T r) { return l | r; } -}; - -// For the following three operators, if the value v we're trying to shift is -// such that v << bits can't fit in the int32 range, then we have undefined -// behavior, according to C++11 [expr.shift]p2. However, left-shifting an -// unsigned type is well-defined. -// -// In C++, shifting by an amount outside the range [0;N-1] is undefined -// behavior. SIMD.js reduces the shift amount modulo the number of bits in a -// lane and has defined behavior for all shift amounts. -template<typename T> -struct ShiftLeft { - static T apply(T v, int32_t bits) { - typedef typename mozilla::MakeUnsigned<T>::Type UnsignedT; - uint32_t maskedBits = uint32_t(bits) % (sizeof(T) * 8); - return UnsignedT(v) << maskedBits; - } -}; -template<typename T> -struct ShiftRightArithmetic { - static T apply(T v, int32_t bits) { - typedef typename mozilla::MakeSigned<T>::Type SignedT; - uint32_t maskedBits = uint32_t(bits) % (sizeof(T) * 8); - return SignedT(v) >> maskedBits; - } -}; -template<typename T> -struct ShiftRightLogical { - static T apply(T v, int32_t bits) { - typedef typename mozilla::MakeUnsigned<T>::Type UnsignedT; - uint32_t maskedBits = uint32_t(bits) % (sizeof(T) * 8); - return UnsignedT(v) >> maskedBits; - } -}; - -// Saturating arithmetic is only defined on types smaller than int. -// Clamp `x` into the range supported by the integral type T. -template<typename T> -static T -Saturate(int x) -{ - static_assert(mozilla::IsIntegral<T>::value, "Only integer saturation supported"); - static_assert(sizeof(T) < sizeof(int), "Saturating int-sized arithmetic is not safe"); - const T lower = mozilla::MinValue<T>::value; - const T upper = mozilla::MaxValue<T>::value; - if (x > int(upper)) - return upper; - if (x < int(lower)) - return lower; - return T(x); -} - -// Since signed integer overflow is undefined behavior in C++, it would be -// wildly irresponsible to attempt something as dangerous as adding two numbers -// coming from user code. However, in this case we know that T is smaller than -// int, so there is no way these operations can cause overflow. The -// static_assert in Saturate() enforces this for us. -template<typename T> -struct AddSaturate { - static T apply(T l, T r) { return Saturate<T>(l + r); } -}; -template<typename T> -struct SubSaturate { - static T apply(T l, T r) { return Saturate<T>(l - r); } -}; - -} // namespace js - -template<typename Out> -static bool -StoreResult(JSContext* cx, CallArgs& args, typename Out::Elem* result) -{ - RootedObject obj(cx, CreateSimd<Out>(cx, result)); - if (!obj) - return false; - args.rval().setObject(*obj); - return true; -} - -// StoreResult can GC, and it is commonly used after pulling something out of a -// TypedObject: -// -// Elem result = op(TypedObjectMemory<Elem>(args[0])); -// StoreResult<Out>(..., result); -// -// The pointer extracted from the typed object in args[0] in the above example -// could be an interior pointer, and therefore be invalidated by GC. -// TypedObjectMemory() requires an assertion token to be passed in to prove -// that we won't GC, but the scope of eg an AutoCheckCannotGC RAII object -// extends to the end of its containing scope -- which would include the call -// to StoreResult, resulting in a rooting hazard. -// -// TypedObjectElemArray fixes this by wrapping the problematic pointer in a -// type, and the analysis is able to see that it is dead before calling -// StoreResult. (But if another GC called is made before the pointer is dead, -// it will correctly report a hazard.) -// -template <typename Elem> -class TypedObjectElemArray { - Elem* elements; - public: - explicit TypedObjectElemArray(HandleValue objVal) { - JS::AutoCheckCannotGC nogc; - elements = TypedObjectMemory<Elem*>(objVal, nogc); - } - Elem& operator[](int i) { return elements[i]; } -} JS_HAZ_GC_POINTER; - -// Coerces the inputs of type In to the type Coercion, apply the operator Op -// and converts the result to the type Out. -template<typename In, typename Coercion, template<typename C> class Op, typename Out> -static bool -CoercedUnaryFunc(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename Coercion::Elem CoercionElem; - typedef typename Out::Elem RetElem; - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() != 1 || !IsVectorObject<In>(args[0])) - return ErrorBadArgs(cx); - - CoercionElem result[Coercion::lanes]; - TypedObjectElemArray<CoercionElem> val(args[0]); - for (unsigned i = 0; i < Coercion::lanes; i++) - result[i] = Op<CoercionElem>::apply(val[i]); - return StoreResult<Out>(cx, args, (RetElem*) result); -} - -// Coerces the inputs of type In to the type Coercion, apply the operator Op -// and converts the result to the type Out. -template<typename In, typename Coercion, template<typename C> class Op, typename Out> -static bool -CoercedBinaryFunc(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename Coercion::Elem CoercionElem; - typedef typename Out::Elem RetElem; - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() != 2 || !IsVectorObject<In>(args[0]) || !IsVectorObject<In>(args[1])) - return ErrorBadArgs(cx); - - CoercionElem result[Coercion::lanes]; - TypedObjectElemArray<CoercionElem> left(args[0]); - TypedObjectElemArray<CoercionElem> right(args[1]); - for (unsigned i = 0; i < Coercion::lanes; i++) - result[i] = Op<CoercionElem>::apply(left[i], right[i]); - return StoreResult<Out>(cx, args, (RetElem*) result); -} - -// Same as above, with no coercion, i.e. Coercion == In. -template<typename In, template<typename C> class Op, typename Out> -static bool -UnaryFunc(JSContext* cx, unsigned argc, Value* vp) -{ - return CoercedUnaryFunc<In, Out, Op, Out>(cx, argc, vp); -} - -template<typename In, template<typename C> class Op, typename Out> -static bool -BinaryFunc(JSContext* cx, unsigned argc, Value* vp) -{ - return CoercedBinaryFunc<In, Out, Op, Out>(cx, argc, vp); -} - -template<typename V> -static bool -ExtractLane(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename V::Elem Elem; - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() < 2 || !IsVectorObject<V>(args[0])) - return ErrorBadArgs(cx); - - unsigned lane; - if (!ArgumentToLaneIndex(cx, args[1], V::lanes, &lane)) - return false; - - JS::AutoCheckCannotGC nogc(cx); - Elem* vec = TypedObjectMemory<Elem*>(args[0], nogc); - Elem val = vec[lane]; - args.rval().set(V::ToValue(val)); - return true; -} - -template<typename V> -static bool -AllTrue(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename V::Elem Elem; - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() < 1 || !IsVectorObject<V>(args[0])) - return ErrorBadArgs(cx); - - JS::AutoCheckCannotGC nogc(cx); - Elem* vec = TypedObjectMemory<Elem*>(args[0], nogc); - bool allTrue = true; - for (unsigned i = 0; allTrue && i < V::lanes; i++) - allTrue = vec[i]; - - args.rval().setBoolean(allTrue); - return true; -} - -template<typename V> -static bool -AnyTrue(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename V::Elem Elem; - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() < 1 || !IsVectorObject<V>(args[0])) - return ErrorBadArgs(cx); - - JS::AutoCheckCannotGC nogc(cx); - Elem* vec = TypedObjectMemory<Elem*>(args[0], nogc); - bool anyTrue = false; - for (unsigned i = 0; !anyTrue && i < V::lanes; i++) - anyTrue = vec[i]; - - args.rval().setBoolean(anyTrue); - return true; -} - -template<typename V> -static bool -ReplaceLane(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename V::Elem Elem; - - CallArgs args = CallArgsFromVp(argc, vp); - // Only the first and second arguments are mandatory - if (args.length() < 2 || !IsVectorObject<V>(args[0])) - return ErrorBadArgs(cx); - - unsigned lane; - if (!ArgumentToLaneIndex(cx, args[1], V::lanes, &lane)) - return false; - - Elem value; - if (!V::Cast(cx, args.get(2), &value)) - return false; - - TypedObjectElemArray<Elem> vec(args[0]); - Elem result[V::lanes]; - for (unsigned i = 0; i < V::lanes; i++) - result[i] = i == lane ? value : vec[i]; - - return StoreResult<V>(cx, args, result); -} - -template<typename V> -static bool -Swizzle(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename V::Elem Elem; - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() != (V::lanes + 1) || !IsVectorObject<V>(args[0])) - return ErrorBadArgs(cx); - - unsigned lanes[V::lanes]; - for (unsigned i = 0; i < V::lanes; i++) { - if (!ArgumentToLaneIndex(cx, args[i + 1], V::lanes, &lanes[i])) - return false; - } - - TypedObjectElemArray<Elem> val(args[0]); - Elem result[V::lanes]; - for (unsigned i = 0; i < V::lanes; i++) - result[i] = val[lanes[i]]; - - return StoreResult<V>(cx, args, result); -} - -template<typename V> -static bool -Shuffle(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename V::Elem Elem; - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() != (V::lanes + 2) || !IsVectorObject<V>(args[0]) || !IsVectorObject<V>(args[1])) - return ErrorBadArgs(cx); - - unsigned lanes[V::lanes]; - for (unsigned i = 0; i < V::lanes; i++) { - if (!ArgumentToLaneIndex(cx, args[i + 2], 2 * V::lanes, &lanes[i])) - return false; - } - - Elem result[V::lanes]; - { - JS::AutoCheckCannotGC nogc(cx); - Elem* lhs = TypedObjectMemory<Elem*>(args[0], nogc); - Elem* rhs = TypedObjectMemory<Elem*>(args[1], nogc); - - for (unsigned i = 0; i < V::lanes; i++) { - Elem* selectedInput = lanes[i] < V::lanes ? lhs : rhs; - result[i] = selectedInput[lanes[i] % V::lanes]; - } - } - - return StoreResult<V>(cx, args, result); -} - -template<typename V, template<typename T> class Op> -static bool -BinaryScalar(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename V::Elem Elem; - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() != 2) - return ErrorBadArgs(cx); - - if (!IsVectorObject<V>(args[0])) - return ErrorBadArgs(cx); - - int32_t bits; - if (!ToInt32(cx, args[1], &bits)) - return false; - - TypedObjectElemArray<Elem> val(args[0]); - Elem result[V::lanes]; - for (unsigned i = 0; i < V::lanes; i++) - result[i] = Op<Elem>::apply(val[i], bits); - - return StoreResult<V>(cx, args, result); -} - -template<typename In, template<typename C> class Op, typename Out> -static bool -CompareFunc(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename In::Elem InElem; - typedef typename Out::Elem OutElem; - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() != 2 || !IsVectorObject<In>(args[0]) || !IsVectorObject<In>(args[1])) - return ErrorBadArgs(cx); - - OutElem result[Out::lanes]; - TypedObjectElemArray<InElem> left(args[0]); - TypedObjectElemArray<InElem> right(args[1]); - for (unsigned i = 0; i < Out::lanes; i++) { - unsigned j = (i * In::lanes) / Out::lanes; - result[i] = Op<InElem>::apply(left[j], right[j]) ? -1 : 0; - } - - return StoreResult<Out>(cx, args, result); -} - -// This struct defines whether we should throw during a conversion attempt, -// when trying to convert a value of type from From to the type To. This -// happens whenever a C++ conversion would have undefined behavior (and perhaps -// be platform-dependent). -template<typename From, typename To> -struct ThrowOnConvert; - -struct NeverThrow -{ - static bool value(int32_t v) { - return false; - } -}; - -// While int32 to float conversions can be lossy, these conversions have -// defined behavior in C++, so we don't need to care about them here. In practice, -// this means round to nearest, tie with even (zero bit in significand). -template<> -struct ThrowOnConvert<int32_t, float> : public NeverThrow {}; - -template<> -struct ThrowOnConvert<uint32_t, float> : public NeverThrow {}; - -// All int32 can be safely converted to doubles. -template<> -struct ThrowOnConvert<int32_t, double> : public NeverThrow {}; - -template<> -struct ThrowOnConvert<uint32_t, double> : public NeverThrow {}; - -// All floats can be safely converted to doubles. -template<> -struct ThrowOnConvert<float, double> : public NeverThrow {}; - -// Double to float conversion for inputs which aren't in the float range are -// undefined behavior in C++, but they're defined in IEEE754. -template<> -struct ThrowOnConvert<double, float> : public NeverThrow {}; - -// Float to integer conversions have undefined behavior if the float value -// is out of the representable integer range (on x86, will yield the undefined -// value pattern, namely 0x80000000; on arm, will clamp the input value), so -// check this here. -template<typename From, typename IntegerType> -struct ThrowIfNotInRange -{ - static_assert(mozilla::IsIntegral<IntegerType>::value, "bad destination type"); - - static bool value(From v) { - // Truncate to integer value before the range check. - double d = trunc(double(v)); - // Arrange relations so NaN returns true (i.e., it throws a RangeError). - return !(d >= double(mozilla::MinValue<IntegerType>::value) && - d <= double(mozilla::MaxValue<IntegerType>::value)); - } -}; - -template<> -struct ThrowOnConvert<double, int32_t> : public ThrowIfNotInRange<double, int32_t> {}; - -template<> -struct ThrowOnConvert<double, uint32_t> : public ThrowIfNotInRange<double, uint32_t> {}; - -template<> -struct ThrowOnConvert<float, int32_t> : public ThrowIfNotInRange<float, int32_t> {}; - -template<> -struct ThrowOnConvert<float, uint32_t> : public ThrowIfNotInRange<float, uint32_t> {}; - -template<typename V, typename Vret> -static bool -FuncConvert(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename V::Elem Elem; - typedef typename Vret::Elem RetElem; - - static_assert(!mozilla::IsSame<V,Vret>::value, "Can't convert SIMD type to itself"); - static_assert(V::lanes == Vret::lanes, "Can only convert from same number of lanes"); - static_assert(!mozilla::IsIntegral<Elem>::value || !mozilla::IsIntegral<RetElem>::value, - "Cannot convert between integer SIMD types"); - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() != 1 || !IsVectorObject<V>(args[0])) - return ErrorBadArgs(cx); - - TypedObjectElemArray<Elem> val(args[0]); - RetElem result[Vret::lanes]; - for (unsigned i = 0; i < V::lanes; i++) { - if (ThrowOnConvert<Elem, RetElem>::value(val[i])) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SIMD_FAILED_CONVERSION); - return false; - } - result[i] = ConvertScalar<RetElem>(val[i]); - } - - return StoreResult<Vret>(cx, args, result); -} - -template<typename V, typename Vret> -static bool -FuncConvertBits(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename V::Elem Elem; - typedef typename Vret::Elem RetElem; - - static_assert(!mozilla::IsSame<V, Vret>::value, "Can't convert SIMD type to itself"); - static_assert(V::lanes * sizeof(Elem) == Vret::lanes * sizeof(RetElem), - "Can only bitcast from the same number of bits"); - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() != 1 || !IsVectorObject<V>(args[0])) - return ErrorBadArgs(cx); - - // While we could just pass the typedMem of args[0] as StoreResults' last - // argument, a GC could move the pointer to its memory in the meanwhile. - // For consistency with other SIMD functions, simply copy the input in a - // temporary array. - RetElem copy[Vret::lanes]; - { - JS::AutoCheckCannotGC nogc(cx); - memcpy(copy, TypedObjectMemory<RetElem*>(args[0], nogc), Vret::lanes * sizeof(RetElem)); - } - return StoreResult<Vret>(cx, args, copy); -} - -template<typename Vret> -static bool -FuncSplat(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename Vret::Elem RetElem; - - CallArgs args = CallArgsFromVp(argc, vp); - RetElem arg; - if (!Vret::Cast(cx, args.get(0), &arg)) - return false; - - RetElem result[Vret::lanes]; - for (unsigned i = 0; i < Vret::lanes; i++) - result[i] = arg; - return StoreResult<Vret>(cx, args, result); -} - -template<typename V> -static bool -Bool(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename V::Elem Elem; - - CallArgs args = CallArgsFromVp(argc, vp); - - Elem result[V::lanes]; - for (unsigned i = 0; i < V::lanes; i++) - result[i] = ToBoolean(args.get(i)) ? -1 : 0; - return StoreResult<V>(cx, args, result); -} - -template<typename V, typename MaskType> -static bool -SelectBits(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename V::Elem Elem; - typedef typename MaskType::Elem MaskTypeElem; - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() != 3 || !IsVectorObject<MaskType>(args[0]) || - !IsVectorObject<V>(args[1]) || !IsVectorObject<V>(args[2])) - { - return ErrorBadArgs(cx); - } - - TypedObjectElemArray<MaskTypeElem> val(args[0]); - TypedObjectElemArray<MaskTypeElem> tv(args[1]); - TypedObjectElemArray<MaskTypeElem> fv(args[2]); - - MaskTypeElem tr[MaskType::lanes]; - for (unsigned i = 0; i < MaskType::lanes; i++) - tr[i] = And<MaskTypeElem>::apply(val[i], tv[i]); - - MaskTypeElem fr[MaskType::lanes]; - for (unsigned i = 0; i < MaskType::lanes; i++) - fr[i] = And<MaskTypeElem>::apply(Not<MaskTypeElem>::apply(val[i]), fv[i]); - - MaskTypeElem orInt[MaskType::lanes]; - for (unsigned i = 0; i < MaskType::lanes; i++) - orInt[i] = Or<MaskTypeElem>::apply(tr[i], fr[i]); - - Elem* result = reinterpret_cast<Elem*>(orInt); - return StoreResult<V>(cx, args, result); -} - -template<typename V, typename MaskType> -static bool -Select(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename V::Elem Elem; - typedef typename MaskType::Elem MaskTypeElem; - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() != 3 || !IsVectorObject<MaskType>(args[0]) || - !IsVectorObject<V>(args[1]) || !IsVectorObject<V>(args[2])) - { - return ErrorBadArgs(cx); - } - - TypedObjectElemArray<MaskTypeElem> mask(args[0]); - TypedObjectElemArray<Elem> tv(args[1]); - TypedObjectElemArray<Elem> fv(args[2]); - - Elem result[V::lanes]; - for (unsigned i = 0; i < V::lanes; i++) - result[i] = mask[i] ? tv[i] : fv[i]; - - return StoreResult<V>(cx, args, result); -} - -// Extract an integer lane index from a function argument. -// -// Register an exception and return false if the argument is not suitable. -static bool -ArgumentToLaneIndex(JSContext* cx, JS::HandleValue v, unsigned limit, unsigned* lane) -{ - uint64_t arg; - if (!ToIntegerIndex(cx, v, &arg)) - return false; - if (arg >= limit) - return ErrorBadIndex(cx); - - *lane = unsigned(arg); - return true; -} - -// Look for arguments (ta, idx) where ta is a TypedArray and idx is a -// non-negative integer. -// Check that accessBytes can be accessed starting from index idx in the array. -// Return the array handle in typedArray and idx converted to a byte offset in byteStart. -static bool -TypedArrayFromArgs(JSContext* cx, const CallArgs& args, uint32_t accessBytes, - MutableHandleObject typedArray, size_t* byteStart) -{ - if (!args[0].isObject()) - return ErrorBadArgs(cx); - - JSObject& argobj = args[0].toObject(); - if (!argobj.is<TypedArrayObject>()) - return ErrorBadArgs(cx); - - typedArray.set(&argobj); - - uint64_t index; - if (!ToIntegerIndex(cx, args[1], &index)) - return false; - - // Do the range check in 64 bits even when size_t is 32 bits. - // This can't overflow because index <= 2^53. - uint64_t bytes = index * typedArray->as<TypedArrayObject>().bytesPerElement(); - // Keep in sync with AsmJS OnOutOfBounds function. - if ((bytes + accessBytes) > typedArray->as<TypedArrayObject>().byteLength()) - return ErrorBadIndex(cx); - - *byteStart = bytes; - - return true; -} - -template<class V, unsigned NumElem> -static bool -Load(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename V::Elem Elem; - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() != 2) - return ErrorBadArgs(cx); - - size_t byteStart; - RootedObject typedArray(cx); - if (!TypedArrayFromArgs(cx, args, sizeof(Elem) * NumElem, &typedArray, &byteStart)) - return false; - - Rooted<TypeDescr*> typeDescr(cx, GetTypeDescr<V>(cx)); - if (!typeDescr) - return false; - - Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, typeDescr, 0)); - if (!result) - return false; - - JS::AutoCheckCannotGC nogc(cx); - SharedMem<Elem*> src = - typedArray->as<TypedArrayObject>().viewDataEither().addBytes(byteStart).cast<Elem*>(); - Elem* dst = reinterpret_cast<Elem*>(result->typedMem(nogc)); - jit::AtomicOperations::podCopySafeWhenRacy(SharedMem<Elem*>::unshared(dst), src, NumElem); - - args.rval().setObject(*result); - return true; -} - -template<class V, unsigned NumElem> -static bool -Store(JSContext* cx, unsigned argc, Value* vp) -{ - typedef typename V::Elem Elem; - - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() != 3) - return ErrorBadArgs(cx); - - size_t byteStart; - RootedObject typedArray(cx); - if (!TypedArrayFromArgs(cx, args, sizeof(Elem) * NumElem, &typedArray, &byteStart)) - return false; - - if (!IsVectorObject<V>(args[2])) - return ErrorBadArgs(cx); - - JS::AutoCheckCannotGC nogc(cx); - Elem* src = TypedObjectMemory<Elem*>(args[2], nogc); - SharedMem<Elem*> dst = - typedArray->as<TypedArrayObject>().viewDataEither().addBytes(byteStart).cast<Elem*>(); - js::jit::AtomicOperations::podCopySafeWhenRacy(dst, SharedMem<Elem*>::unshared(src), NumElem); - - args.rval().setObject(args[2].toObject()); - return true; -} - -#define DEFINE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands) \ -bool \ -js::simd_float32x4_##Name(JSContext* cx, unsigned argc, Value* vp) \ -{ \ - return Func(cx, argc, vp); \ -} -FLOAT32X4_FUNCTION_LIST(DEFINE_SIMD_FLOAT32X4_FUNCTION) -#undef DEFINE_SIMD_FLOAT32X4_FUNCTION - -#define DEFINE_SIMD_FLOAT64X2_FUNCTION(Name, Func, Operands) \ -bool \ -js::simd_float64x2_##Name(JSContext* cx, unsigned argc, Value* vp) \ -{ \ - return Func(cx, argc, vp); \ -} -FLOAT64X2_FUNCTION_LIST(DEFINE_SIMD_FLOAT64X2_FUNCTION) -#undef DEFINE_SIMD_FLOAT64X2_FUNCTION - -#define DEFINE_SIMD_INT8X16_FUNCTION(Name, Func, Operands) \ -bool \ -js::simd_int8x16_##Name(JSContext* cx, unsigned argc, Value* vp) \ -{ \ - return Func(cx, argc, vp); \ -} -INT8X16_FUNCTION_LIST(DEFINE_SIMD_INT8X16_FUNCTION) -#undef DEFINE_SIMD_INT8X16_FUNCTION - -#define DEFINE_SIMD_INT16X8_FUNCTION(Name, Func, Operands) \ -bool \ -js::simd_int16x8_##Name(JSContext* cx, unsigned argc, Value* vp) \ -{ \ - return Func(cx, argc, vp); \ -} -INT16X8_FUNCTION_LIST(DEFINE_SIMD_INT16X8_FUNCTION) -#undef DEFINE_SIMD_INT16X8_FUNCTION - -#define DEFINE_SIMD_INT32X4_FUNCTION(Name, Func, Operands) \ -bool \ -js::simd_int32x4_##Name(JSContext* cx, unsigned argc, Value* vp) \ -{ \ - return Func(cx, argc, vp); \ -} -INT32X4_FUNCTION_LIST(DEFINE_SIMD_INT32X4_FUNCTION) -#undef DEFINE_SIMD_INT32X4_FUNCTION - -#define DEFINE_SIMD_UINT8X16_FUNCTION(Name, Func, Operands) \ -bool \ -js::simd_uint8x16_##Name(JSContext* cx, unsigned argc, Value* vp) \ -{ \ - return Func(cx, argc, vp); \ -} -UINT8X16_FUNCTION_LIST(DEFINE_SIMD_UINT8X16_FUNCTION) -#undef DEFINE_SIMD_UINT8X16_FUNCTION - -#define DEFINE_SIMD_UINT16X8_FUNCTION(Name, Func, Operands) \ -bool \ -js::simd_uint16x8_##Name(JSContext* cx, unsigned argc, Value* vp) \ -{ \ - return Func(cx, argc, vp); \ -} -UINT16X8_FUNCTION_LIST(DEFINE_SIMD_UINT16X8_FUNCTION) -#undef DEFINE_SIMD_UINT16X8_FUNCTION - -#define DEFINE_SIMD_UINT32X4_FUNCTION(Name, Func, Operands) \ -bool \ -js::simd_uint32x4_##Name(JSContext* cx, unsigned argc, Value* vp) \ -{ \ - return Func(cx, argc, vp); \ -} -UINT32X4_FUNCTION_LIST(DEFINE_SIMD_UINT32X4_FUNCTION) -#undef DEFINE_SIMD_UINT32X4_FUNCTION - -#define DEFINE_SIMD_BOOL8X16_FUNCTION(Name, Func, Operands) \ -bool \ -js::simd_bool8x16_##Name(JSContext* cx, unsigned argc, Value* vp) \ -{ \ - return Func(cx, argc, vp); \ -} - -BOOL8X16_FUNCTION_LIST(DEFINE_SIMD_BOOL8X16_FUNCTION) -#undef DEFINE_SIMD_BOOL8X16_FUNCTION - -#define DEFINE_SIMD_BOOL16X8_FUNCTION(Name, Func, Operands) \ -bool \ -js::simd_bool16x8_##Name(JSContext* cx, unsigned argc, Value* vp) \ -{ \ - return Func(cx, argc, vp); \ -} -BOOL16X8_FUNCTION_LIST(DEFINE_SIMD_BOOL16X8_FUNCTION) -#undef DEFINE_SIMD_BOOL16X8_FUNCTION - -#define DEFINE_SIMD_BOOL32X4_FUNCTION(Name, Func, Operands) \ -bool \ -js::simd_bool32x4_##Name(JSContext* cx, unsigned argc, Value* vp) \ -{ \ - return Func(cx, argc, vp); \ -} -BOOL32X4_FUNCTION_LIST(DEFINE_SIMD_BOOL32X4_FUNCTION) -#undef DEFINE_SIMD_BOOL32X4_FUNCTION - -#define DEFINE_SIMD_BOOL64X2_FUNCTION(Name, Func, Operands) \ -bool \ -js::simd_bool64x2_##Name(JSContext* cx, unsigned argc, Value* vp) \ -{ \ - return Func(cx, argc, vp); \ -} -BOOL64X2_FUNCTION_LIST(DEFINE_SIMD_BOOL64X2_FUNCTION) -#undef DEFINE_SIMD_BOOL64X2_FUNCTION diff --git a/js/src/builtin/SIMD.h b/js/src/builtin/SIMD.h deleted file mode 100644 index 8d8b226416..0000000000 --- a/js/src/builtin/SIMD.h +++ /dev/null @@ -1,1218 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef builtin_SIMD_h -#define builtin_SIMD_h - -#include "jsapi.h" -#include "NamespaceImports.h" - -#include "builtin/TypedObjectConstants.h" -#include "jit/IonTypes.h" -#include "js/Conversions.h" - -/* - * JS SIMD functions. - * Spec matching polyfill: - * https://github.com/tc39/ecmascript_simd/blob/master/src/ecmascript_simd.js - */ - -// Bool8x16. -#define BOOL8X16_UNARY_FUNCTION_LIST(V) \ - V(not, (UnaryFunc<Bool8x16, LogicalNot, Bool8x16>), 1) \ - V(check, (UnaryFunc<Bool8x16, Identity, Bool8x16>), 1) \ - V(splat, (FuncSplat<Bool8x16>), 1) \ - V(allTrue, (AllTrue<Bool8x16>), 1) \ - V(anyTrue, (AnyTrue<Bool8x16>), 1) - -#define BOOL8X16_BINARY_FUNCTION_LIST(V) \ - V(extractLane, (ExtractLane<Bool8x16>), 2) \ - V(and, (BinaryFunc<Bool8x16, And, Bool8x16>), 2) \ - V(or, (BinaryFunc<Bool8x16, Or, Bool8x16>), 2) \ - V(xor, (BinaryFunc<Bool8x16, Xor, Bool8x16>), 2) \ - -#define BOOL8X16_TERNARY_FUNCTION_LIST(V) \ - V(replaceLane, (ReplaceLane<Bool8x16>), 3) - -#define BOOL8X16_FUNCTION_LIST(V) \ - BOOL8X16_UNARY_FUNCTION_LIST(V) \ - BOOL8X16_BINARY_FUNCTION_LIST(V) \ - BOOL8X16_TERNARY_FUNCTION_LIST(V) - -// Bool 16x8. -#define BOOL16X8_UNARY_FUNCTION_LIST(V) \ - V(not, (UnaryFunc<Bool16x8, LogicalNot, Bool16x8>), 1) \ - V(check, (UnaryFunc<Bool16x8, Identity, Bool16x8>), 1) \ - V(splat, (FuncSplat<Bool16x8>), 1) \ - V(allTrue, (AllTrue<Bool16x8>), 1) \ - V(anyTrue, (AnyTrue<Bool16x8>), 1) - -#define BOOL16X8_BINARY_FUNCTION_LIST(V) \ - V(extractLane, (ExtractLane<Bool16x8>), 2) \ - V(and, (BinaryFunc<Bool16x8, And, Bool16x8>), 2) \ - V(or, (BinaryFunc<Bool16x8, Or, Bool16x8>), 2) \ - V(xor, (BinaryFunc<Bool16x8, Xor, Bool16x8>), 2) \ - -#define BOOL16X8_TERNARY_FUNCTION_LIST(V) \ - V(replaceLane, (ReplaceLane<Bool16x8>), 3) - -#define BOOL16X8_FUNCTION_LIST(V) \ - BOOL16X8_UNARY_FUNCTION_LIST(V) \ - BOOL16X8_BINARY_FUNCTION_LIST(V) \ - BOOL16X8_TERNARY_FUNCTION_LIST(V) - -// Bool32x4. -#define BOOL32X4_UNARY_FUNCTION_LIST(V) \ - V(not, (UnaryFunc<Bool32x4, LogicalNot, Bool32x4>), 1) \ - V(check, (UnaryFunc<Bool32x4, Identity, Bool32x4>), 1) \ - V(splat, (FuncSplat<Bool32x4>), 1) \ - V(allTrue, (AllTrue<Bool32x4>), 1) \ - V(anyTrue, (AnyTrue<Bool32x4>), 1) - -#define BOOL32X4_BINARY_FUNCTION_LIST(V) \ - V(extractLane, (ExtractLane<Bool32x4>), 2) \ - V(and, (BinaryFunc<Bool32x4, And, Bool32x4>), 2) \ - V(or, (BinaryFunc<Bool32x4, Or, Bool32x4>), 2) \ - V(xor, (BinaryFunc<Bool32x4, Xor, Bool32x4>), 2) \ - -#define BOOL32X4_TERNARY_FUNCTION_LIST(V) \ - V(replaceLane, (ReplaceLane<Bool32x4>), 3) - -#define BOOL32X4_FUNCTION_LIST(V) \ - BOOL32X4_UNARY_FUNCTION_LIST(V) \ - BOOL32X4_BINARY_FUNCTION_LIST(V) \ - BOOL32X4_TERNARY_FUNCTION_LIST(V) - -// Bool64x2. -#define BOOL64X2_UNARY_FUNCTION_LIST(V) \ - V(not, (UnaryFunc<Bool64x2, LogicalNot, Bool64x2>), 1) \ - V(check, (UnaryFunc<Bool64x2, Identity, Bool64x2>), 1) \ - V(splat, (FuncSplat<Bool64x2>), 1) \ - V(allTrue, (AllTrue<Bool64x2>), 1) \ - V(anyTrue, (AnyTrue<Bool64x2>), 1) - -#define BOOL64X2_BINARY_FUNCTION_LIST(V) \ - V(extractLane, (ExtractLane<Bool64x2>), 2) \ - V(and, (BinaryFunc<Bool64x2, And, Bool64x2>), 2) \ - V(or, (BinaryFunc<Bool64x2, Or, Bool64x2>), 2) \ - V(xor, (BinaryFunc<Bool64x2, Xor, Bool64x2>), 2) \ - -#define BOOL64X2_TERNARY_FUNCTION_LIST(V) \ - V(replaceLane, (ReplaceLane<Bool64x2>), 3) - -#define BOOL64X2_FUNCTION_LIST(V) \ - BOOL64X2_UNARY_FUNCTION_LIST(V) \ - BOOL64X2_BINARY_FUNCTION_LIST(V) \ - BOOL64X2_TERNARY_FUNCTION_LIST(V) - -// Float32x4. -#define FLOAT32X4_UNARY_FUNCTION_LIST(V) \ - V(abs, (UnaryFunc<Float32x4, Abs, Float32x4>), 1) \ - V(check, (UnaryFunc<Float32x4, Identity, Float32x4>), 1) \ - V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Float32x4>), 1) \ - V(fromInt8x16Bits, (FuncConvertBits<Int8x16, Float32x4>), 1) \ - V(fromInt16x8Bits, (FuncConvertBits<Int16x8, Float32x4>), 1) \ - V(fromInt32x4, (FuncConvert<Int32x4, Float32x4>), 1) \ - V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Float32x4>), 1) \ - V(fromUint8x16Bits, (FuncConvertBits<Uint8x16, Float32x4>), 1) \ - V(fromUint16x8Bits, (FuncConvertBits<Uint16x8, Float32x4>), 1) \ - V(fromUint32x4, (FuncConvert<Uint32x4, Float32x4>), 1) \ - V(fromUint32x4Bits, (FuncConvertBits<Uint32x4, Float32x4>), 1) \ - V(neg, (UnaryFunc<Float32x4, Neg, Float32x4>), 1) \ - V(reciprocalApproximation, (UnaryFunc<Float32x4, RecApprox, Float32x4>), 1) \ - V(reciprocalSqrtApproximation, (UnaryFunc<Float32x4, RecSqrtApprox, Float32x4>), 1) \ - V(splat, (FuncSplat<Float32x4>), 1) \ - V(sqrt, (UnaryFunc<Float32x4, Sqrt, Float32x4>), 1) - -#define FLOAT32X4_BINARY_FUNCTION_LIST(V) \ - V(add, (BinaryFunc<Float32x4, Add, Float32x4>), 2) \ - V(div, (BinaryFunc<Float32x4, Div, Float32x4>), 2) \ - V(equal, (CompareFunc<Float32x4, Equal, Bool32x4>), 2) \ - V(extractLane, (ExtractLane<Float32x4>), 2) \ - V(greaterThan, (CompareFunc<Float32x4, GreaterThan, Bool32x4>), 2) \ - V(greaterThanOrEqual, (CompareFunc<Float32x4, GreaterThanOrEqual, Bool32x4>), 2) \ - V(lessThan, (CompareFunc<Float32x4, LessThan, Bool32x4>), 2) \ - V(lessThanOrEqual, (CompareFunc<Float32x4, LessThanOrEqual, Bool32x4>), 2) \ - V(load, (Load<Float32x4, 4>), 2) \ - V(load3, (Load<Float32x4, 3>), 2) \ - V(load2, (Load<Float32x4, 2>), 2) \ - V(load1, (Load<Float32x4, 1>), 2) \ - V(max, (BinaryFunc<Float32x4, Maximum, Float32x4>), 2) \ - V(maxNum, (BinaryFunc<Float32x4, MaxNum, Float32x4>), 2) \ - V(min, (BinaryFunc<Float32x4, Minimum, Float32x4>), 2) \ - V(minNum, (BinaryFunc<Float32x4, MinNum, Float32x4>), 2) \ - V(mul, (BinaryFunc<Float32x4, Mul, Float32x4>), 2) \ - V(notEqual, (CompareFunc<Float32x4, NotEqual, Bool32x4>), 2) \ - V(sub, (BinaryFunc<Float32x4, Sub, Float32x4>), 2) - -#define FLOAT32X4_TERNARY_FUNCTION_LIST(V) \ - V(replaceLane, (ReplaceLane<Float32x4>), 3) \ - V(select, (Select<Float32x4, Bool32x4>), 3) \ - V(store, (Store<Float32x4, 4>), 3) \ - V(store3, (Store<Float32x4, 3>), 3) \ - V(store2, (Store<Float32x4, 2>), 3) \ - V(store1, (Store<Float32x4, 1>), 3) - -#define FLOAT32X4_SHUFFLE_FUNCTION_LIST(V) \ - V(swizzle, Swizzle<Float32x4>, 5) \ - V(shuffle, Shuffle<Float32x4>, 6) - -#define FLOAT32X4_FUNCTION_LIST(V) \ - FLOAT32X4_UNARY_FUNCTION_LIST(V) \ - FLOAT32X4_BINARY_FUNCTION_LIST(V) \ - FLOAT32X4_TERNARY_FUNCTION_LIST(V) \ - FLOAT32X4_SHUFFLE_FUNCTION_LIST(V) - -// Float64x2. -#define FLOAT64X2_UNARY_FUNCTION_LIST(V) \ - V(abs, (UnaryFunc<Float64x2, Abs, Float64x2>), 1) \ - V(check, (UnaryFunc<Float64x2, Identity, Float64x2>), 1) \ - V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Float64x2>), 1) \ - V(fromInt8x16Bits, (FuncConvertBits<Int8x16, Float64x2>), 1) \ - V(fromInt16x8Bits, (FuncConvertBits<Int16x8, Float64x2>), 1) \ - V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Float64x2>), 1) \ - V(fromUint8x16Bits, (FuncConvertBits<Uint8x16, Float64x2>), 1) \ - V(fromUint16x8Bits, (FuncConvertBits<Uint16x8, Float64x2>), 1) \ - V(fromUint32x4Bits, (FuncConvertBits<Uint32x4, Float64x2>), 1) \ - V(neg, (UnaryFunc<Float64x2, Neg, Float64x2>), 1) \ - V(reciprocalApproximation, (UnaryFunc<Float64x2, RecApprox, Float64x2>), 1) \ - V(reciprocalSqrtApproximation, (UnaryFunc<Float64x2, RecSqrtApprox, Float64x2>), 1) \ - V(splat, (FuncSplat<Float64x2>), 1) \ - V(sqrt, (UnaryFunc<Float64x2, Sqrt, Float64x2>), 1) - -#define FLOAT64X2_BINARY_FUNCTION_LIST(V) \ - V(add, (BinaryFunc<Float64x2, Add, Float64x2>), 2) \ - V(div, (BinaryFunc<Float64x2, Div, Float64x2>), 2) \ - V(equal, (CompareFunc<Float64x2, Equal, Bool64x2>), 2) \ - V(extractLane, (ExtractLane<Float64x2>), 2) \ - V(greaterThan, (CompareFunc<Float64x2, GreaterThan, Bool64x2>), 2) \ - V(greaterThanOrEqual, (CompareFunc<Float64x2, GreaterThanOrEqual, Bool64x2>), 2) \ - V(lessThan, (CompareFunc<Float64x2, LessThan, Bool64x2>), 2) \ - V(lessThanOrEqual, (CompareFunc<Float64x2, LessThanOrEqual, Bool64x2>), 2) \ - V(load, (Load<Float64x2, 2>), 2) \ - V(load1, (Load<Float64x2, 1>), 2) \ - V(max, (BinaryFunc<Float64x2, Maximum, Float64x2>), 2) \ - V(maxNum, (BinaryFunc<Float64x2, MaxNum, Float64x2>), 2) \ - V(min, (BinaryFunc<Float64x2, Minimum, Float64x2>), 2) \ - V(minNum, (BinaryFunc<Float64x2, MinNum, Float64x2>), 2) \ - V(mul, (BinaryFunc<Float64x2, Mul, Float64x2>), 2) \ - V(notEqual, (CompareFunc<Float64x2, NotEqual, Bool64x2>), 2) \ - V(sub, (BinaryFunc<Float64x2, Sub, Float64x2>), 2) - -#define FLOAT64X2_TERNARY_FUNCTION_LIST(V) \ - V(replaceLane, (ReplaceLane<Float64x2>), 3) \ - V(select, (Select<Float64x2, Bool64x2>), 3) \ - V(store, (Store<Float64x2, 2>), 3) \ - V(store1, (Store<Float64x2, 1>), 3) - -#define FLOAT64X2_SHUFFLE_FUNCTION_LIST(V) \ - V(swizzle, Swizzle<Float64x2>, 3) \ - V(shuffle, Shuffle<Float64x2>, 4) - -#define FLOAT64X2_FUNCTION_LIST(V) \ - FLOAT64X2_UNARY_FUNCTION_LIST(V) \ - FLOAT64X2_BINARY_FUNCTION_LIST(V) \ - FLOAT64X2_TERNARY_FUNCTION_LIST(V) \ - FLOAT64X2_SHUFFLE_FUNCTION_LIST(V) - -// Int8x16. -#define INT8X16_UNARY_FUNCTION_LIST(V) \ - V(check, (UnaryFunc<Int8x16, Identity, Int8x16>), 1) \ - V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int8x16>), 1) \ - V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int8x16>), 1) \ - V(fromInt16x8Bits, (FuncConvertBits<Int16x8, Int8x16>), 1) \ - V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Int8x16>), 1) \ - V(fromUint8x16Bits, (FuncConvertBits<Uint8x16, Int8x16>), 1) \ - V(fromUint16x8Bits, (FuncConvertBits<Uint16x8, Int8x16>), 1) \ - V(fromUint32x4Bits, (FuncConvertBits<Uint32x4, Int8x16>), 1) \ - V(neg, (UnaryFunc<Int8x16, Neg, Int8x16>), 1) \ - V(not, (UnaryFunc<Int8x16, Not, Int8x16>), 1) \ - V(splat, (FuncSplat<Int8x16>), 1) - -#define INT8X16_BINARY_FUNCTION_LIST(V) \ - V(add, (BinaryFunc<Int8x16, Add, Int8x16>), 2) \ - V(addSaturate, (BinaryFunc<Int8x16, AddSaturate, Int8x16>), 2) \ - V(and, (BinaryFunc<Int8x16, And, Int8x16>), 2) \ - V(equal, (CompareFunc<Int8x16, Equal, Bool8x16>), 2) \ - V(extractLane, (ExtractLane<Int8x16>), 2) \ - V(greaterThan, (CompareFunc<Int8x16, GreaterThan, Bool8x16>), 2) \ - V(greaterThanOrEqual, (CompareFunc<Int8x16, GreaterThanOrEqual, Bool8x16>), 2) \ - V(lessThan, (CompareFunc<Int8x16, LessThan, Bool8x16>), 2) \ - V(lessThanOrEqual, (CompareFunc<Int8x16, LessThanOrEqual, Bool8x16>), 2) \ - V(load, (Load<Int8x16, 16>), 2) \ - V(mul, (BinaryFunc<Int8x16, Mul, Int8x16>), 2) \ - V(notEqual, (CompareFunc<Int8x16, NotEqual, Bool8x16>), 2) \ - V(or, (BinaryFunc<Int8x16, Or, Int8x16>), 2) \ - V(sub, (BinaryFunc<Int8x16, Sub, Int8x16>), 2) \ - V(subSaturate, (BinaryFunc<Int8x16, SubSaturate, Int8x16>), 2) \ - V(shiftLeftByScalar, (BinaryScalar<Int8x16, ShiftLeft>), 2) \ - V(shiftRightByScalar, (BinaryScalar<Int8x16, ShiftRightArithmetic>), 2) \ - V(xor, (BinaryFunc<Int8x16, Xor, Int8x16>), 2) - -#define INT8X16_TERNARY_FUNCTION_LIST(V) \ - V(replaceLane, (ReplaceLane<Int8x16>), 3) \ - V(select, (Select<Int8x16, Bool8x16>), 3) \ - V(store, (Store<Int8x16, 16>), 3) - -#define INT8X16_SHUFFLE_FUNCTION_LIST(V) \ - V(swizzle, Swizzle<Int8x16>, 17) \ - V(shuffle, Shuffle<Int8x16>, 18) - -#define INT8X16_FUNCTION_LIST(V) \ - INT8X16_UNARY_FUNCTION_LIST(V) \ - INT8X16_BINARY_FUNCTION_LIST(V) \ - INT8X16_TERNARY_FUNCTION_LIST(V) \ - INT8X16_SHUFFLE_FUNCTION_LIST(V) - -// Uint8x16. -#define UINT8X16_UNARY_FUNCTION_LIST(V) \ - V(check, (UnaryFunc<Uint8x16, Identity, Uint8x16>), 1) \ - V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Uint8x16>), 1) \ - V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Uint8x16>), 1) \ - V(fromInt8x16Bits, (FuncConvertBits<Int8x16, Uint8x16>), 1) \ - V(fromInt16x8Bits, (FuncConvertBits<Int16x8, Uint8x16>), 1) \ - V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Uint8x16>), 1) \ - V(fromUint16x8Bits, (FuncConvertBits<Uint16x8, Uint8x16>), 1) \ - V(fromUint32x4Bits, (FuncConvertBits<Uint32x4, Uint8x16>), 1) \ - V(neg, (UnaryFunc<Uint8x16, Neg, Uint8x16>), 1) \ - V(not, (UnaryFunc<Uint8x16, Not, Uint8x16>), 1) \ - V(splat, (FuncSplat<Uint8x16>), 1) - -#define UINT8X16_BINARY_FUNCTION_LIST(V) \ - V(add, (BinaryFunc<Uint8x16, Add, Uint8x16>), 2) \ - V(addSaturate, (BinaryFunc<Uint8x16, AddSaturate, Uint8x16>), 2) \ - V(and, (BinaryFunc<Uint8x16, And, Uint8x16>), 2) \ - V(equal, (CompareFunc<Uint8x16, Equal, Bool8x16>), 2) \ - V(extractLane, (ExtractLane<Uint8x16>), 2) \ - V(greaterThan, (CompareFunc<Uint8x16, GreaterThan, Bool8x16>), 2) \ - V(greaterThanOrEqual, (CompareFunc<Uint8x16, GreaterThanOrEqual, Bool8x16>), 2) \ - V(lessThan, (CompareFunc<Uint8x16, LessThan, Bool8x16>), 2) \ - V(lessThanOrEqual, (CompareFunc<Uint8x16, LessThanOrEqual, Bool8x16>), 2) \ - V(load, (Load<Uint8x16, 16>), 2) \ - V(mul, (BinaryFunc<Uint8x16, Mul, Uint8x16>), 2) \ - V(notEqual, (CompareFunc<Uint8x16, NotEqual, Bool8x16>), 2) \ - V(or, (BinaryFunc<Uint8x16, Or, Uint8x16>), 2) \ - V(sub, (BinaryFunc<Uint8x16, Sub, Uint8x16>), 2) \ - V(subSaturate, (BinaryFunc<Uint8x16, SubSaturate, Uint8x16>), 2) \ - V(shiftLeftByScalar, (BinaryScalar<Uint8x16, ShiftLeft>), 2) \ - V(shiftRightByScalar, (BinaryScalar<Uint8x16, ShiftRightLogical>), 2) \ - V(xor, (BinaryFunc<Uint8x16, Xor, Uint8x16>), 2) - -#define UINT8X16_TERNARY_FUNCTION_LIST(V) \ - V(replaceLane, (ReplaceLane<Uint8x16>), 3) \ - V(select, (Select<Uint8x16, Bool8x16>), 3) \ - V(store, (Store<Uint8x16, 16>), 3) - -#define UINT8X16_SHUFFLE_FUNCTION_LIST(V) \ - V(swizzle, Swizzle<Uint8x16>, 17) \ - V(shuffle, Shuffle<Uint8x16>, 18) - -#define UINT8X16_FUNCTION_LIST(V) \ - UINT8X16_UNARY_FUNCTION_LIST(V) \ - UINT8X16_BINARY_FUNCTION_LIST(V) \ - UINT8X16_TERNARY_FUNCTION_LIST(V) \ - UINT8X16_SHUFFLE_FUNCTION_LIST(V) - -// Int16x8. -#define INT16X8_UNARY_FUNCTION_LIST(V) \ - V(check, (UnaryFunc<Int16x8, Identity, Int16x8>), 1) \ - V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int16x8>), 1) \ - V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int16x8>), 1) \ - V(fromInt8x16Bits, (FuncConvertBits<Int8x16, Int16x8>), 1) \ - V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Int16x8>), 1) \ - V(fromUint8x16Bits, (FuncConvertBits<Uint8x16, Int16x8>), 1) \ - V(fromUint16x8Bits, (FuncConvertBits<Uint16x8, Int16x8>), 1) \ - V(fromUint32x4Bits, (FuncConvertBits<Uint32x4, Int16x8>), 1) \ - V(neg, (UnaryFunc<Int16x8, Neg, Int16x8>), 1) \ - V(not, (UnaryFunc<Int16x8, Not, Int16x8>), 1) \ - V(splat, (FuncSplat<Int16x8>), 1) - -#define INT16X8_BINARY_FUNCTION_LIST(V) \ - V(add, (BinaryFunc<Int16x8, Add, Int16x8>), 2) \ - V(addSaturate, (BinaryFunc<Int16x8, AddSaturate, Int16x8>), 2) \ - V(and, (BinaryFunc<Int16x8, And, Int16x8>), 2) \ - V(equal, (CompareFunc<Int16x8, Equal, Bool16x8>), 2) \ - V(extractLane, (ExtractLane<Int16x8>), 2) \ - V(greaterThan, (CompareFunc<Int16x8, GreaterThan, Bool16x8>), 2) \ - V(greaterThanOrEqual, (CompareFunc<Int16x8, GreaterThanOrEqual, Bool16x8>), 2) \ - V(lessThan, (CompareFunc<Int16x8, LessThan, Bool16x8>), 2) \ - V(lessThanOrEqual, (CompareFunc<Int16x8, LessThanOrEqual, Bool16x8>), 2) \ - V(load, (Load<Int16x8, 8>), 2) \ - V(mul, (BinaryFunc<Int16x8, Mul, Int16x8>), 2) \ - V(notEqual, (CompareFunc<Int16x8, NotEqual, Bool16x8>), 2) \ - V(or, (BinaryFunc<Int16x8, Or, Int16x8>), 2) \ - V(sub, (BinaryFunc<Int16x8, Sub, Int16x8>), 2) \ - V(subSaturate, (BinaryFunc<Int16x8, SubSaturate, Int16x8>), 2) \ - V(shiftLeftByScalar, (BinaryScalar<Int16x8, ShiftLeft>), 2) \ - V(shiftRightByScalar, (BinaryScalar<Int16x8, ShiftRightArithmetic>), 2) \ - V(xor, (BinaryFunc<Int16x8, Xor, Int16x8>), 2) - -#define INT16X8_TERNARY_FUNCTION_LIST(V) \ - V(replaceLane, (ReplaceLane<Int16x8>), 3) \ - V(select, (Select<Int16x8, Bool16x8>), 3) \ - V(store, (Store<Int16x8, 8>), 3) - -#define INT16X8_SHUFFLE_FUNCTION_LIST(V) \ - V(swizzle, Swizzle<Int16x8>, 9) \ - V(shuffle, Shuffle<Int16x8>, 10) - -#define INT16X8_FUNCTION_LIST(V) \ - INT16X8_UNARY_FUNCTION_LIST(V) \ - INT16X8_BINARY_FUNCTION_LIST(V) \ - INT16X8_TERNARY_FUNCTION_LIST(V) \ - INT16X8_SHUFFLE_FUNCTION_LIST(V) - -// Uint16x8. -#define UINT16X8_UNARY_FUNCTION_LIST(V) \ - V(check, (UnaryFunc<Uint16x8, Identity, Uint16x8>), 1) \ - V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Uint16x8>), 1) \ - V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Uint16x8>), 1) \ - V(fromInt8x16Bits, (FuncConvertBits<Int8x16, Uint16x8>), 1) \ - V(fromInt16x8Bits, (FuncConvertBits<Int16x8, Uint16x8>), 1) \ - V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Uint16x8>), 1) \ - V(fromUint8x16Bits, (FuncConvertBits<Uint8x16, Uint16x8>), 1) \ - V(fromUint32x4Bits, (FuncConvertBits<Uint32x4, Uint16x8>), 1) \ - V(neg, (UnaryFunc<Uint16x8, Neg, Uint16x8>), 1) \ - V(not, (UnaryFunc<Uint16x8, Not, Uint16x8>), 1) \ - V(splat, (FuncSplat<Uint16x8>), 1) - -#define UINT16X8_BINARY_FUNCTION_LIST(V) \ - V(add, (BinaryFunc<Uint16x8, Add, Uint16x8>), 2) \ - V(addSaturate, (BinaryFunc<Uint16x8, AddSaturate, Uint16x8>), 2) \ - V(and, (BinaryFunc<Uint16x8, And, Uint16x8>), 2) \ - V(equal, (CompareFunc<Uint16x8, Equal, Bool16x8>), 2) \ - V(extractLane, (ExtractLane<Uint16x8>), 2) \ - V(greaterThan, (CompareFunc<Uint16x8, GreaterThan, Bool16x8>), 2) \ - V(greaterThanOrEqual, (CompareFunc<Uint16x8, GreaterThanOrEqual, Bool16x8>), 2) \ - V(lessThan, (CompareFunc<Uint16x8, LessThan, Bool16x8>), 2) \ - V(lessThanOrEqual, (CompareFunc<Uint16x8, LessThanOrEqual, Bool16x8>), 2) \ - V(load, (Load<Uint16x8, 8>), 2) \ - V(mul, (BinaryFunc<Uint16x8, Mul, Uint16x8>), 2) \ - V(notEqual, (CompareFunc<Uint16x8, NotEqual, Bool16x8>), 2) \ - V(or, (BinaryFunc<Uint16x8, Or, Uint16x8>), 2) \ - V(sub, (BinaryFunc<Uint16x8, Sub, Uint16x8>), 2) \ - V(subSaturate, (BinaryFunc<Uint16x8, SubSaturate, Uint16x8>), 2) \ - V(shiftLeftByScalar, (BinaryScalar<Uint16x8, ShiftLeft>), 2) \ - V(shiftRightByScalar, (BinaryScalar<Uint16x8, ShiftRightLogical>), 2) \ - V(xor, (BinaryFunc<Uint16x8, Xor, Uint16x8>), 2) - -#define UINT16X8_TERNARY_FUNCTION_LIST(V) \ - V(replaceLane, (ReplaceLane<Uint16x8>), 3) \ - V(select, (Select<Uint16x8, Bool16x8>), 3) \ - V(store, (Store<Uint16x8, 8>), 3) - -#define UINT16X8_SHUFFLE_FUNCTION_LIST(V) \ - V(swizzle, Swizzle<Uint16x8>, 9) \ - V(shuffle, Shuffle<Uint16x8>, 10) - -#define UINT16X8_FUNCTION_LIST(V) \ - UINT16X8_UNARY_FUNCTION_LIST(V) \ - UINT16X8_BINARY_FUNCTION_LIST(V) \ - UINT16X8_TERNARY_FUNCTION_LIST(V) \ - UINT16X8_SHUFFLE_FUNCTION_LIST(V) - -// Int32x4. -#define INT32X4_UNARY_FUNCTION_LIST(V) \ - V(check, (UnaryFunc<Int32x4, Identity, Int32x4>), 1) \ - V(fromFloat32x4, (FuncConvert<Float32x4, Int32x4>), 1) \ - V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int32x4>), 1) \ - V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int32x4>), 1) \ - V(fromInt8x16Bits, (FuncConvertBits<Int8x16, Int32x4>), 1) \ - V(fromInt16x8Bits, (FuncConvertBits<Int16x8, Int32x4>), 1) \ - V(fromUint8x16Bits, (FuncConvertBits<Uint8x16, Int32x4>), 1) \ - V(fromUint16x8Bits, (FuncConvertBits<Uint16x8, Int32x4>), 1) \ - V(fromUint32x4Bits, (FuncConvertBits<Uint32x4, Int32x4>), 1) \ - V(neg, (UnaryFunc<Int32x4, Neg, Int32x4>), 1) \ - V(not, (UnaryFunc<Int32x4, Not, Int32x4>), 1) \ - V(splat, (FuncSplat<Int32x4>), 0) - -#define INT32X4_BINARY_FUNCTION_LIST(V) \ - V(add, (BinaryFunc<Int32x4, Add, Int32x4>), 2) \ - V(and, (BinaryFunc<Int32x4, And, Int32x4>), 2) \ - V(equal, (CompareFunc<Int32x4, Equal, Bool32x4>), 2) \ - V(extractLane, (ExtractLane<Int32x4>), 2) \ - V(greaterThan, (CompareFunc<Int32x4, GreaterThan, Bool32x4>), 2) \ - V(greaterThanOrEqual, (CompareFunc<Int32x4, GreaterThanOrEqual, Bool32x4>), 2) \ - V(lessThan, (CompareFunc<Int32x4, LessThan, Bool32x4>), 2) \ - V(lessThanOrEqual, (CompareFunc<Int32x4, LessThanOrEqual, Bool32x4>), 2) \ - V(load, (Load<Int32x4, 4>), 2) \ - V(load3, (Load<Int32x4, 3>), 2) \ - V(load2, (Load<Int32x4, 2>), 2) \ - V(load1, (Load<Int32x4, 1>), 2) \ - V(mul, (BinaryFunc<Int32x4, Mul, Int32x4>), 2) \ - V(notEqual, (CompareFunc<Int32x4, NotEqual, Bool32x4>), 2) \ - V(or, (BinaryFunc<Int32x4, Or, Int32x4>), 2) \ - V(sub, (BinaryFunc<Int32x4, Sub, Int32x4>), 2) \ - V(shiftLeftByScalar, (BinaryScalar<Int32x4, ShiftLeft>), 2) \ - V(shiftRightByScalar, (BinaryScalar<Int32x4, ShiftRightArithmetic>), 2) \ - V(xor, (BinaryFunc<Int32x4, Xor, Int32x4>), 2) - -#define INT32X4_TERNARY_FUNCTION_LIST(V) \ - V(replaceLane, (ReplaceLane<Int32x4>), 3) \ - V(select, (Select<Int32x4, Bool32x4>), 3) \ - V(store, (Store<Int32x4, 4>), 3) \ - V(store3, (Store<Int32x4, 3>), 3) \ - V(store2, (Store<Int32x4, 2>), 3) \ - V(store1, (Store<Int32x4, 1>), 3) - -#define INT32X4_SHUFFLE_FUNCTION_LIST(V) \ - V(swizzle, Swizzle<Int32x4>, 5) \ - V(shuffle, Shuffle<Int32x4>, 6) - -#define INT32X4_FUNCTION_LIST(V) \ - INT32X4_UNARY_FUNCTION_LIST(V) \ - INT32X4_BINARY_FUNCTION_LIST(V) \ - INT32X4_TERNARY_FUNCTION_LIST(V) \ - INT32X4_SHUFFLE_FUNCTION_LIST(V) - -// Uint32x4. -#define UINT32X4_UNARY_FUNCTION_LIST(V) \ - V(check, (UnaryFunc<Uint32x4, Identity, Uint32x4>), 1) \ - V(fromFloat32x4, (FuncConvert<Float32x4, Uint32x4>), 1) \ - V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Uint32x4>), 1) \ - V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Uint32x4>), 1) \ - V(fromInt8x16Bits, (FuncConvertBits<Int8x16, Uint32x4>), 1) \ - V(fromInt16x8Bits, (FuncConvertBits<Int16x8, Uint32x4>), 1) \ - V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Uint32x4>), 1) \ - V(fromUint8x16Bits, (FuncConvertBits<Uint8x16, Uint32x4>), 1) \ - V(fromUint16x8Bits, (FuncConvertBits<Uint16x8, Uint32x4>), 1) \ - V(neg, (UnaryFunc<Uint32x4, Neg, Uint32x4>), 1) \ - V(not, (UnaryFunc<Uint32x4, Not, Uint32x4>), 1) \ - V(splat, (FuncSplat<Uint32x4>), 0) - -#define UINT32X4_BINARY_FUNCTION_LIST(V) \ - V(add, (BinaryFunc<Uint32x4, Add, Uint32x4>), 2) \ - V(and, (BinaryFunc<Uint32x4, And, Uint32x4>), 2) \ - V(equal, (CompareFunc<Uint32x4, Equal, Bool32x4>), 2) \ - V(extractLane, (ExtractLane<Uint32x4>), 2) \ - V(greaterThan, (CompareFunc<Uint32x4, GreaterThan, Bool32x4>), 2) \ - V(greaterThanOrEqual, (CompareFunc<Uint32x4, GreaterThanOrEqual, Bool32x4>), 2) \ - V(lessThan, (CompareFunc<Uint32x4, LessThan, Bool32x4>), 2) \ - V(lessThanOrEqual, (CompareFunc<Uint32x4, LessThanOrEqual, Bool32x4>), 2) \ - V(load, (Load<Uint32x4, 4>), 2) \ - V(load3, (Load<Uint32x4, 3>), 2) \ - V(load2, (Load<Uint32x4, 2>), 2) \ - V(load1, (Load<Uint32x4, 1>), 2) \ - V(mul, (BinaryFunc<Uint32x4, Mul, Uint32x4>), 2) \ - V(notEqual, (CompareFunc<Uint32x4, NotEqual, Bool32x4>), 2) \ - V(or, (BinaryFunc<Uint32x4, Or, Uint32x4>), 2) \ - V(sub, (BinaryFunc<Uint32x4, Sub, Uint32x4>), 2) \ - V(shiftLeftByScalar, (BinaryScalar<Uint32x4, ShiftLeft>), 2) \ - V(shiftRightByScalar, (BinaryScalar<Uint32x4, ShiftRightLogical>), 2) \ - V(xor, (BinaryFunc<Uint32x4, Xor, Uint32x4>), 2) - -#define UINT32X4_TERNARY_FUNCTION_LIST(V) \ - V(replaceLane, (ReplaceLane<Uint32x4>), 3) \ - V(select, (Select<Uint32x4, Bool32x4>), 3) \ - V(store, (Store<Uint32x4, 4>), 3) \ - V(store3, (Store<Uint32x4, 3>), 3) \ - V(store2, (Store<Uint32x4, 2>), 3) \ - V(store1, (Store<Uint32x4, 1>), 3) - -#define UINT32X4_SHUFFLE_FUNCTION_LIST(V) \ - V(swizzle, Swizzle<Uint32x4>, 5) \ - V(shuffle, Shuffle<Uint32x4>, 6) - -#define UINT32X4_FUNCTION_LIST(V) \ - UINT32X4_UNARY_FUNCTION_LIST(V) \ - UINT32X4_BINARY_FUNCTION_LIST(V) \ - UINT32X4_TERNARY_FUNCTION_LIST(V) \ - UINT32X4_SHUFFLE_FUNCTION_LIST(V) - -/* - * The FOREACH macros below partition all of the SIMD operations into disjoint - * sets. - */ - -// Operations available on all SIMD types. Mixed arity. -#define FOREACH_COMMON_SIMD_OP(_) \ - _(extractLane) \ - _(replaceLane) \ - _(check) \ - _(splat) - -// Lanewise operations available on numeric SIMD types. -// Include lane-wise select here since it is not arithmetic and defined on -// numeric types too. -#define FOREACH_LANE_SIMD_OP(_) \ - _(select) \ - _(swizzle) \ - _(shuffle) - -// Memory operations available on numeric SIMD types. -#define FOREACH_MEMORY_SIMD_OP(_) \ - _(load) \ - _(store) - -// Memory operations available on numeric X4 SIMD types. -#define FOREACH_MEMORY_X4_SIMD_OP(_) \ - _(load1) \ - _(load2) \ - _(load3) \ - _(store1) \ - _(store2) \ - _(store3) - -// Unary operations on Bool vectors. -#define FOREACH_BOOL_SIMD_UNOP(_) \ - _(allTrue) \ - _(anyTrue) - -// Unary bitwise SIMD operators defined on all integer and boolean SIMD types. -#define FOREACH_BITWISE_SIMD_UNOP(_) \ - _(not) - -// Binary bitwise SIMD operators defined on all integer and boolean SIMD types. -#define FOREACH_BITWISE_SIMD_BINOP(_) \ - _(and) \ - _(or) \ - _(xor) - -// Bitwise shifts defined on integer SIMD types. -#define FOREACH_SHIFT_SIMD_OP(_) \ - _(shiftLeftByScalar) \ - _(shiftRightByScalar) - -// Unary arithmetic operators defined on numeric SIMD types. -#define FOREACH_NUMERIC_SIMD_UNOP(_) \ - _(neg) - -// Binary arithmetic operators defined on numeric SIMD types. -#define FOREACH_NUMERIC_SIMD_BINOP(_) \ - _(add) \ - _(sub) \ - _(mul) - -// Unary arithmetic operators defined on floating point SIMD types. -#define FOREACH_FLOAT_SIMD_UNOP(_) \ - _(abs) \ - _(sqrt) \ - _(reciprocalApproximation) \ - _(reciprocalSqrtApproximation) - -// Binary arithmetic operators defined on floating point SIMD types. -#define FOREACH_FLOAT_SIMD_BINOP(_) \ - _(div) \ - _(max) \ - _(min) \ - _(maxNum) \ - _(minNum) - -// Binary operations on small integer (< 32 bits) vectors. -#define FOREACH_SMINT_SIMD_BINOP(_) \ - _(addSaturate) \ - _(subSaturate) - -// Comparison operators defined on numeric SIMD types. -#define FOREACH_COMP_SIMD_OP(_) \ - _(lessThan) \ - _(lessThanOrEqual) \ - _(equal) \ - _(notEqual) \ - _(greaterThan) \ - _(greaterThanOrEqual) - -/* - * All SIMD operations, excluding casts. - */ -#define FORALL_SIMD_NONCAST_OP(_) \ - FOREACH_COMMON_SIMD_OP(_) \ - FOREACH_LANE_SIMD_OP(_) \ - FOREACH_MEMORY_SIMD_OP(_) \ - FOREACH_MEMORY_X4_SIMD_OP(_) \ - FOREACH_BOOL_SIMD_UNOP(_) \ - FOREACH_BITWISE_SIMD_UNOP(_) \ - FOREACH_BITWISE_SIMD_BINOP(_) \ - FOREACH_SHIFT_SIMD_OP(_) \ - FOREACH_NUMERIC_SIMD_UNOP(_) \ - FOREACH_NUMERIC_SIMD_BINOP(_) \ - FOREACH_FLOAT_SIMD_UNOP(_) \ - FOREACH_FLOAT_SIMD_BINOP(_) \ - FOREACH_SMINT_SIMD_BINOP(_) \ - FOREACH_COMP_SIMD_OP(_) - -/* - * All operations on integer SIMD types, excluding casts and - * FOREACH_MEMORY_X4_OP. - */ -#define FORALL_INT_SIMD_OP(_) \ - FOREACH_COMMON_SIMD_OP(_) \ - FOREACH_LANE_SIMD_OP(_) \ - FOREACH_MEMORY_SIMD_OP(_) \ - FOREACH_BITWISE_SIMD_UNOP(_) \ - FOREACH_BITWISE_SIMD_BINOP(_) \ - FOREACH_SHIFT_SIMD_OP(_) \ - FOREACH_NUMERIC_SIMD_UNOP(_) \ - FOREACH_NUMERIC_SIMD_BINOP(_) \ - FOREACH_COMP_SIMD_OP(_) - -/* - * All operations on floating point SIMD types, excluding casts and - * FOREACH_MEMORY_X4_OP. - */ -#define FORALL_FLOAT_SIMD_OP(_) \ - FOREACH_COMMON_SIMD_OP(_) \ - FOREACH_LANE_SIMD_OP(_) \ - FOREACH_MEMORY_SIMD_OP(_) \ - FOREACH_NUMERIC_SIMD_UNOP(_) \ - FOREACH_NUMERIC_SIMD_BINOP(_) \ - FOREACH_FLOAT_SIMD_UNOP(_) \ - FOREACH_FLOAT_SIMD_BINOP(_) \ - FOREACH_COMP_SIMD_OP(_) - -/* - * All operations on Bool SIMD types. - * - * These types don't have casts, so no need to specialize. - */ -#define FORALL_BOOL_SIMD_OP(_) \ - FOREACH_COMMON_SIMD_OP(_) \ - FOREACH_BOOL_SIMD_UNOP(_) \ - FOREACH_BITWISE_SIMD_UNOP(_) \ - FOREACH_BITWISE_SIMD_BINOP(_) - -/* - * The sets of cast operations are listed per type below. - * - * These sets are not disjoint. - */ - -#define FOREACH_INT8X16_SIMD_CAST(_) \ - _(fromFloat32x4Bits) \ - _(fromFloat64x2Bits) \ - _(fromInt16x8Bits) \ - _(fromInt32x4Bits) - -#define FOREACH_INT16X8_SIMD_CAST(_) \ - _(fromFloat32x4Bits) \ - _(fromFloat64x2Bits) \ - _(fromInt8x16Bits) \ - _(fromInt32x4Bits) - -#define FOREACH_INT32X4_SIMD_CAST(_) \ - _(fromFloat32x4) \ - _(fromFloat32x4Bits) \ - _(fromFloat64x2Bits) \ - _(fromInt8x16Bits) \ - _(fromInt16x8Bits) - -#define FOREACH_FLOAT32X4_SIMD_CAST(_)\ - _(fromFloat64x2Bits) \ - _(fromInt8x16Bits) \ - _(fromInt16x8Bits) \ - _(fromInt32x4) \ - _(fromInt32x4Bits) - -#define FOREACH_FLOAT64X2_SIMD_CAST(_)\ - _(fromFloat32x4Bits) \ - _(fromInt8x16Bits) \ - _(fromInt16x8Bits) \ - _(fromInt32x4Bits) - -// All operations on Int32x4. -#define FORALL_INT32X4_SIMD_OP(_) \ - FORALL_INT_SIMD_OP(_) \ - FOREACH_MEMORY_X4_SIMD_OP(_) \ - FOREACH_INT32X4_SIMD_CAST(_) - -// All operations on Float32X4 -#define FORALL_FLOAT32X4_SIMD_OP(_) \ - FORALL_FLOAT_SIMD_OP(_) \ - FOREACH_MEMORY_X4_SIMD_OP(_) \ - FOREACH_FLOAT32X4_SIMD_CAST(_) - -/* - * All SIMD operations assuming only 32x4 types exist. - * This is used in the current asm.js impl. - */ -#define FORALL_SIMD_ASMJS_OP(_) \ - FORALL_SIMD_NONCAST_OP(_) \ - _(fromFloat32x4) \ - _(fromFloat32x4Bits) \ - _(fromInt8x16Bits) \ - _(fromInt16x8Bits) \ - _(fromInt32x4) \ - _(fromInt32x4Bits) \ - _(fromUint8x16Bits) \ - _(fromUint16x8Bits) \ - _(fromUint32x4) \ - _(fromUint32x4Bits) - -// All operations on Int8x16 or Uint8x16 in the asm.js world. -// Note: this does not include conversions and casts to/from Uint8x16 because -// this list is shared between Int8x16 and Uint8x16. -#define FORALL_INT8X16_ASMJS_OP(_) \ - FORALL_INT_SIMD_OP(_) \ - FOREACH_SMINT_SIMD_BINOP(_) \ - _(fromInt16x8Bits) \ - _(fromInt32x4Bits) \ - _(fromFloat32x4Bits) - -// All operations on Int16x8 or Uint16x8 in the asm.js world. -// Note: this does not include conversions and casts to/from Uint16x8 because -// this list is shared between Int16x8 and Uint16x8. -#define FORALL_INT16X8_ASMJS_OP(_) \ - FORALL_INT_SIMD_OP(_) \ - FOREACH_SMINT_SIMD_BINOP(_) \ - _(fromInt8x16Bits) \ - _(fromInt32x4Bits) \ - _(fromFloat32x4Bits) - -// All operations on Int32x4 or Uint32x4 in the asm.js world. -// Note: this does not include conversions and casts to/from Uint32x4 because -// this list is shared between Int32x4 and Uint32x4. -#define FORALL_INT32X4_ASMJS_OP(_) \ - FORALL_INT_SIMD_OP(_) \ - FOREACH_MEMORY_X4_SIMD_OP(_) \ - _(fromInt8x16Bits) \ - _(fromInt16x8Bits) \ - _(fromFloat32x4) \ - _(fromFloat32x4Bits) - -// All operations on Float32X4 in the asm.js world. -#define FORALL_FLOAT32X4_ASMJS_OP(_) \ - FORALL_FLOAT_SIMD_OP(_) \ - FOREACH_MEMORY_X4_SIMD_OP(_) \ - _(fromInt8x16Bits) \ - _(fromInt16x8Bits) \ - _(fromInt32x4Bits) \ - _(fromInt32x4) \ - _(fromUint32x4) - -namespace js { - -// Complete set of SIMD types. -// It must be kept in sync with the enumeration of values in -// TypedObjectConstants.h; in particular we need to ensure that Count is -// appropriately set with respect to the number of actual types. -enum class SimdType { - Int8x16 = JS_SIMDTYPEREPR_INT8X16, - Int16x8 = JS_SIMDTYPEREPR_INT16X8, - Int32x4 = JS_SIMDTYPEREPR_INT32X4, - Uint8x16 = JS_SIMDTYPEREPR_UINT8X16, - Uint16x8 = JS_SIMDTYPEREPR_UINT16X8, - Uint32x4 = JS_SIMDTYPEREPR_UINT32X4, - Float32x4 = JS_SIMDTYPEREPR_FLOAT32X4, - Float64x2 = JS_SIMDTYPEREPR_FLOAT64X2, - Bool8x16 = JS_SIMDTYPEREPR_BOOL8X16, - Bool16x8 = JS_SIMDTYPEREPR_BOOL16X8, - Bool32x4 = JS_SIMDTYPEREPR_BOOL32X4, - Bool64x2 = JS_SIMDTYPEREPR_BOOL64X2, - Count -}; - -// The integer SIMD types have a lot of operations that do the exact same thing -// for signed and unsigned integer types. Sometimes it is simpler to treat -// signed and unsigned integer SIMD types as the same type, using a SimdSign to -// distinguish the few cases where there is a difference. -enum class SimdSign { - // Signedness is not applicable to this type. (i.e., Float or Bool). - NotApplicable, - // Treat as an unsigned integer with a range 0 .. 2^N-1. - Unsigned, - // Treat as a signed integer in two's complement encoding. - Signed, -}; - -// Get the signedness of a SIMD type. -inline SimdSign -GetSimdSign(SimdType t) -{ - switch(t) { - case SimdType::Int8x16: - case SimdType::Int16x8: - case SimdType::Int32x4: - return SimdSign::Signed; - - case SimdType::Uint8x16: - case SimdType::Uint16x8: - case SimdType::Uint32x4: - return SimdSign::Unsigned; - - default: - return SimdSign::NotApplicable; - } -} - -inline bool -IsSignedIntSimdType(SimdType type) -{ - return GetSimdSign(type) == SimdSign::Signed; -} - -// Get the boolean SIMD type with the same shape as t. -// -// This is the result type of a comparison operation, and it can also be used to -// identify the geometry of a SIMD type. -inline SimdType -GetBooleanSimdType(SimdType t) -{ - switch(t) { - case SimdType::Int8x16: - case SimdType::Uint8x16: - case SimdType::Bool8x16: - return SimdType::Bool8x16; - - case SimdType::Int16x8: - case SimdType::Uint16x8: - case SimdType::Bool16x8: - return SimdType::Bool16x8; - - case SimdType::Int32x4: - case SimdType::Uint32x4: - case SimdType::Float32x4: - case SimdType::Bool32x4: - return SimdType::Bool32x4; - - case SimdType::Float64x2: - case SimdType::Bool64x2: - return SimdType::Bool64x2; - - case SimdType::Count: - break; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad SIMD type"); -} - -// Get the number of lanes in a SIMD type. -inline unsigned -GetSimdLanes(SimdType t) -{ - switch(t) { - case SimdType::Int8x16: - case SimdType::Uint8x16: - case SimdType::Bool8x16: - return 16; - - case SimdType::Int16x8: - case SimdType::Uint16x8: - case SimdType::Bool16x8: - return 8; - - case SimdType::Int32x4: - case SimdType::Uint32x4: - case SimdType::Float32x4: - case SimdType::Bool32x4: - return 4; - - case SimdType::Float64x2: - case SimdType::Bool64x2: - return 2; - - case SimdType::Count: - break; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad SIMD type"); -} - -// Complete set of SIMD operations. -// -// No SIMD types implement all of these operations. -// -// C++ defines keywords and/or/xor/not, so prepend Fn_ to all named functions to -// avoid clashes. -// -// Note: because of a gcc < v4.8's compiler bug, uint8_t can't be used as the -// storage class here. See bug 1243810. See also -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64037 . -enum class SimdOperation { - // The constructor call. No Fn_ prefix here. - Constructor, - - // All the operations, except for casts. -#define DEFOP(x) Fn_##x, - FORALL_SIMD_NONCAST_OP(DEFOP) -#undef DEFOP - - // Int <-> Float conversions. - Fn_fromInt32x4, - Fn_fromUint32x4, - Fn_fromFloat32x4, - - // Bitcasts. One for each type with a memory representation. - Fn_fromInt8x16Bits, - Fn_fromInt16x8Bits, - Fn_fromInt32x4Bits, - Fn_fromUint8x16Bits, - Fn_fromUint16x8Bits, - Fn_fromUint32x4Bits, - Fn_fromFloat32x4Bits, - Fn_fromFloat64x2Bits, - - Last = Fn_fromFloat64x2Bits -}; - -// These classes implement the concept containing the following constraints: -// - requires typename Elem: this is the scalar lane type, stored in each lane -// of the SIMD vector. -// - requires static const unsigned lanes: this is the number of lanes (length) -// of the SIMD vector. -// - requires static const SimdType type: this is the SimdType enum value -// corresponding to the SIMD type. -// - requires static bool Cast(JSContext*, JS::HandleValue, Elem*): casts a -// given Value to the current scalar lane type and saves it in the Elem -// out-param. -// - requires static Value ToValue(Elem): returns a Value of the right type -// containing the given value. -// -// This concept is used in the templates above to define the functions -// associated to a given type and in their implementations, to avoid code -// redundancy. - -struct Float32x4 { - typedef float Elem; - static const unsigned lanes = 4; - static const SimdType type = SimdType::Float32x4; - static MOZ_MUST_USE bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { - double d; - if (!ToNumber(cx, v, &d)) - return false; - *out = float(d); - return true; - } - static Value ToValue(Elem value) { - return DoubleValue(JS::CanonicalizeNaN(value)); - } -}; - -struct Float64x2 { - typedef double Elem; - static const unsigned lanes = 2; - static const SimdType type = SimdType::Float64x2; - static MOZ_MUST_USE bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { - return ToNumber(cx, v, out); - } - static Value ToValue(Elem value) { - return DoubleValue(JS::CanonicalizeNaN(value)); - } -}; - -struct Int8x16 { - typedef int8_t Elem; - static const unsigned lanes = 16; - static const SimdType type = SimdType::Int8x16; - static MOZ_MUST_USE bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { - return ToInt8(cx, v, out); - } - static Value ToValue(Elem value) { - return NumberValue(value); - } -}; - -struct Int16x8 { - typedef int16_t Elem; - static const unsigned lanes = 8; - static const SimdType type = SimdType::Int16x8; - static MOZ_MUST_USE bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { - return ToInt16(cx, v, out); - } - static Value ToValue(Elem value) { - return NumberValue(value); - } -}; - -struct Int32x4 { - typedef int32_t Elem; - static const unsigned lanes = 4; - static const SimdType type = SimdType::Int32x4; - static MOZ_MUST_USE bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { - return ToInt32(cx, v, out); - } - static Value ToValue(Elem value) { - return NumberValue(value); - } -}; - -struct Uint8x16 { - typedef uint8_t Elem; - static const unsigned lanes = 16; - static const SimdType type = SimdType::Uint8x16; - static MOZ_MUST_USE bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { - return ToUint8(cx, v, out); - } - static Value ToValue(Elem value) { - return NumberValue(value); - } -}; - -struct Uint16x8 { - typedef uint16_t Elem; - static const unsigned lanes = 8; - static const SimdType type = SimdType::Uint16x8; - static MOZ_MUST_USE bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { - return ToUint16(cx, v, out); - } - static Value ToValue(Elem value) { - return NumberValue(value); - } -}; - -struct Uint32x4 { - typedef uint32_t Elem; - static const unsigned lanes = 4; - static const SimdType type = SimdType::Uint32x4; - static MOZ_MUST_USE bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { - return ToUint32(cx, v, out); - } - static Value ToValue(Elem value) { - return NumberValue(value); - } -}; - -struct Bool8x16 { - typedef int8_t Elem; - static const unsigned lanes = 16; - static const SimdType type = SimdType::Bool8x16; - static MOZ_MUST_USE bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { - *out = ToBoolean(v) ? -1 : 0; - return true; - } - static Value ToValue(Elem value) { - return BooleanValue(value); - } -}; - -struct Bool16x8 { - typedef int16_t Elem; - static const unsigned lanes = 8; - static const SimdType type = SimdType::Bool16x8; - static MOZ_MUST_USE bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { - *out = ToBoolean(v) ? -1 : 0; - return true; - } - static Value ToValue(Elem value) { - return BooleanValue(value); - } -}; - -struct Bool32x4 { - typedef int32_t Elem; - static const unsigned lanes = 4; - static const SimdType type = SimdType::Bool32x4; - static MOZ_MUST_USE bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { - *out = ToBoolean(v) ? -1 : 0; - return true; - } - static Value ToValue(Elem value) { - return BooleanValue(value); - } -}; - -struct Bool64x2 { - typedef int64_t Elem; - static const unsigned lanes = 2; - static const SimdType type = SimdType::Bool64x2; - static MOZ_MUST_USE bool Cast(JSContext* cx, JS::HandleValue v, Elem* out) { - *out = ToBoolean(v) ? -1 : 0; - return true; - } - static Value ToValue(Elem value) { - return BooleanValue(value); - } -}; - -// Get the well known name of the SIMD.* object corresponding to type. -PropertyName* SimdTypeToName(const JSAtomState& atoms, SimdType type); - -// Check if name is the well known name of a SIMD type. -// Returns true and sets *type iff name is known. -bool IsSimdTypeName(const JSAtomState& atoms, const PropertyName* name, SimdType* type); - -const char* SimdTypeToString(SimdType type); - -template<typename V> -JSObject* CreateSimd(JSContext* cx, const typename V::Elem* data); - -template<typename V> -bool IsVectorObject(HandleValue v); - -template<typename V> -MOZ_MUST_USE bool ToSimdConstant(JSContext* cx, HandleValue v, jit::SimdConstant* out); - -JSObject* -InitSimdClass(JSContext* cx, HandleObject obj); - -namespace jit { - -extern const JSJitInfo JitInfo_SimdInt32x4_extractLane; -extern const JSJitInfo JitInfo_SimdFloat32x4_extractLane; - -} // namespace jit - -#define DECLARE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands) \ -extern MOZ_MUST_USE bool \ -simd_float32x4_##Name(JSContext* cx, unsigned argc, Value* vp); -FLOAT32X4_FUNCTION_LIST(DECLARE_SIMD_FLOAT32X4_FUNCTION) -#undef DECLARE_SIMD_FLOAT32X4_FUNCTION - -#define DECLARE_SIMD_FLOAT64X2_FUNCTION(Name, Func, Operands) \ -extern MOZ_MUST_USE bool \ -simd_float64x2_##Name(JSContext* cx, unsigned argc, Value* vp); -FLOAT64X2_FUNCTION_LIST(DECLARE_SIMD_FLOAT64X2_FUNCTION) -#undef DECLARE_SIMD_FLOAT64X2_FUNCTION - -#define DECLARE_SIMD_INT8X16_FUNCTION(Name, Func, Operands) \ -extern MOZ_MUST_USE bool \ -simd_int8x16_##Name(JSContext* cx, unsigned argc, Value* vp); -INT8X16_FUNCTION_LIST(DECLARE_SIMD_INT8X16_FUNCTION) -#undef DECLARE_SIMD_INT8X16_FUNCTION - -#define DECLARE_SIMD_INT16X8_FUNCTION(Name, Func, Operands) \ -extern MOZ_MUST_USE bool \ -simd_int16x8_##Name(JSContext* cx, unsigned argc, Value* vp); -INT16X8_FUNCTION_LIST(DECLARE_SIMD_INT16X8_FUNCTION) -#undef DECLARE_SIMD_INT16X8_FUNCTION - -#define DECLARE_SIMD_INT32X4_FUNCTION(Name, Func, Operands) \ -extern MOZ_MUST_USE bool \ -simd_int32x4_##Name(JSContext* cx, unsigned argc, Value* vp); -INT32X4_FUNCTION_LIST(DECLARE_SIMD_INT32X4_FUNCTION) -#undef DECLARE_SIMD_INT32X4_FUNCTION - -#define DECLARE_SIMD_UINT8X16_FUNCTION(Name, Func, Operands) \ -extern MOZ_MUST_USE bool \ -simd_uint8x16_##Name(JSContext* cx, unsigned argc, Value* vp); -UINT8X16_FUNCTION_LIST(DECLARE_SIMD_UINT8X16_FUNCTION) -#undef DECLARE_SIMD_UINT8X16_FUNCTION - -#define DECLARE_SIMD_UINT16X8_FUNCTION(Name, Func, Operands) \ -extern MOZ_MUST_USE bool \ -simd_uint16x8_##Name(JSContext* cx, unsigned argc, Value* vp); -UINT16X8_FUNCTION_LIST(DECLARE_SIMD_UINT16X8_FUNCTION) -#undef DECLARE_SIMD_UINT16X8_FUNCTION - -#define DECLARE_SIMD_UINT32X4_FUNCTION(Name, Func, Operands) \ -extern MOZ_MUST_USE bool \ -simd_uint32x4_##Name(JSContext* cx, unsigned argc, Value* vp); -UINT32X4_FUNCTION_LIST(DECLARE_SIMD_UINT32X4_FUNCTION) -#undef DECLARE_SIMD_UINT32X4_FUNCTION - -#define DECLARE_SIMD_BOOL8X16_FUNCTION(Name, Func, Operands) \ -extern MOZ_MUST_USE bool \ -simd_bool8x16_##Name(JSContext* cx, unsigned argc, Value* vp); -BOOL8X16_FUNCTION_LIST(DECLARE_SIMD_BOOL8X16_FUNCTION) -#undef DECLARE_SIMD_BOOL8X16_FUNCTION - -#define DECLARE_SIMD_BOOL16X8_FUNCTION(Name, Func, Operands) \ -extern MOZ_MUST_USE bool \ -simd_bool16x8_##Name(JSContext* cx, unsigned argc, Value* vp); -BOOL16X8_FUNCTION_LIST(DECLARE_SIMD_BOOL16X8_FUNCTION) -#undef DECLARE_SIMD_BOOL16X8_FUNCTION - -#define DECLARE_SIMD_BOOL32X4_FUNCTION(Name, Func, Operands) \ -extern MOZ_MUST_USE bool \ -simd_bool32x4_##Name(JSContext* cx, unsigned argc, Value* vp); -BOOL32X4_FUNCTION_LIST(DECLARE_SIMD_BOOL32X4_FUNCTION) -#undef DECLARE_SIMD_BOOL32X4_FUNCTION - -#define DECLARE_SIMD_BOOL64X2_FUNCTION(Name, Func, Operands) \ -extern MOZ_MUST_USE bool \ -simd_bool64x2_##Name(JSContext* cx, unsigned argc, Value* vp); -BOOL64X2_FUNCTION_LIST(DECLARE_SIMD_BOOL64X2_FUNCTION) -#undef DECLARE_SIMD_BOOL64X2_FUNCTION - -} /* namespace js */ - -#endif /* builtin_SIMD_h */ diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 997695aecb..2608733853 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -3114,7 +3114,7 @@ static bool IsSimdAvailable(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); -#if defined(JS_CODEGEN_NONE) || !defined(ENABLE_SIMD) +#if defined(JS_CODEGEN_NONE) bool available = false; #else bool available = cx->jitSupportsSimd(); diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 2796848c02..10ae8902dd 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -12,7 +12,6 @@ #include "jsfun.h" #include "jsutil.h" -#include "builtin/SIMD.h" #include "gc/Marking.h" #include "js/Vector.h" #include "vm/GlobalObject.h" @@ -255,10 +254,6 @@ ScalarTypeDescr::typeName(Type type) JS_FOR_EACH_SCALAR_TYPE_REPR(NUMERIC_TYPE_TO_STRING) #undef NUMERIC_TYPE_TO_STRING case Scalar::Int64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: case Scalar::MaxTypedArrayViewType: break; } @@ -296,10 +291,6 @@ ScalarTypeDescr::call(JSContext* cx, unsigned argc, Value* vp) JS_FOR_EACH_SCALAR_TYPE_REPR(SCALARTYPE_CALL) #undef SCALARTYPE_CALL case Scalar::Int64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: case Scalar::MaxTypedArrayViewType: MOZ_CRASH(); } @@ -414,50 +405,6 @@ js::ReferenceTypeDescr::call(JSContext* cx, unsigned argc, Value* vp) } /*************************************************************************** - * SIMD type objects - * - * Note: these are partially defined in SIMD.cpp - */ - -SimdType -SimdTypeDescr::type() const { - uint32_t t = uint32_t(getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32()); - MOZ_ASSERT(t < uint32_t(SimdType::Count)); - return SimdType(t); -} - -uint32_t -SimdTypeDescr::size(SimdType t) -{ - MOZ_ASSERT(unsigned(t) < unsigned(SimdType::Count)); - switch (t) { - case SimdType::Int8x16: - case SimdType::Int16x8: - case SimdType::Int32x4: - case SimdType::Uint8x16: - case SimdType::Uint16x8: - case SimdType::Uint32x4: - case SimdType::Float32x4: - case SimdType::Float64x2: - case SimdType::Bool8x16: - case SimdType::Bool16x8: - case SimdType::Bool32x4: - case SimdType::Bool64x2: - return 16; - case SimdType::Count: - break; - } - MOZ_CRASH("unexpected SIMD type"); -} - -uint32_t -SimdTypeDescr::alignment(SimdType t) -{ - MOZ_ASSERT(unsigned(t) < unsigned(SimdType::Count)); - return size(t); -} - -/*************************************************************************** * ArrayMetaTypeDescr class */ @@ -1525,7 +1472,6 @@ TypedObjLengthFromType(TypeDescr& descr) case type::Scalar: case type::Reference: case type::Struct: - case type::Simd: return 0; case type::Array: @@ -1650,7 +1596,6 @@ TypeDescr::hasProperty(const JSAtomState& names, jsid id) switch (kind()) { case type::Scalar: case type::Reference: - case type::Simd: return false; case type::Array: @@ -1723,7 +1668,6 @@ TypedObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* switch (typedObj->typeDescr().kind()) { case type::Scalar: case type::Reference: - case type::Simd: break; case type::Array: { @@ -1775,9 +1719,6 @@ TypedObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiv case type::Reference: break; - case type::Simd: - break; - case type::Array: if (JSID_IS_ATOM(id, cx->names().length)) { if (!typedObj->isAttached()) { @@ -1824,7 +1765,6 @@ TypedObject::obj_getElement(JSContext* cx, HandleObject obj, HandleValue receive switch (descr->kind()) { case type::Scalar: case type::Reference: - case type::Simd: case type::Struct: break; @@ -1870,9 +1810,6 @@ TypedObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, Handl case type::Reference: break; - case type::Simd: - break; - case type::Array: { if (JSID_IS_ATOM(id, cx->names().length)) { if (receiver.isObject() && obj == &receiver.toObject()) { @@ -1940,7 +1877,6 @@ TypedObject::obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, Handl switch (descr->kind()) { case type::Scalar: case type::Reference: - case type::Simd: break; case type::Array: @@ -1994,7 +1930,6 @@ IsOwnId(JSContext* cx, HandleObject obj, HandleId id) switch (typedObj->typeDescr().kind()) { case type::Scalar: case type::Reference: - case type::Simd: return false; case type::Array: @@ -2033,8 +1968,7 @@ TypedObject::obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& proper RootedId id(cx); switch (descr->kind()) { case type::Scalar: - case type::Reference: - case type::Simd: { + case type::Reference: { // Nothing to enumerate. break; } @@ -2257,7 +2191,6 @@ LengthForType(TypeDescr& descr) case type::Scalar: case type::Reference: case type::Struct: - case type::Simd: return 0; case type::Array: @@ -2555,22 +2488,6 @@ js::GetTypedObjectModule(JSContext* cx, unsigned argc, Value* vp) return true; } -bool -js::GetSimdTypeDescr(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - MOZ_ASSERT(args.length() == 1); - MOZ_ASSERT(args[0].isInt32()); - // One of the JS_SIMDTYPEREPR_* constants / a SimdType enum value. - // getOrCreateSimdTypeDescr() will do the range check. - int32_t simdTypeRepr = args[0].toInt32(); - Rooted<GlobalObject*> global(cx, cx->global()); - MOZ_ASSERT(global); - auto* obj = GlobalObject::getOrCreateSimdTypeDescr(cx, global, SimdType(simdTypeRepr)); - args.rval().setObject(*obj); - return true; -} - #define JS_STORE_SCALAR_CLASS_IMPL(_constant, T, _name) \ bool \ js::StoreScalar##T::Func(JSContext* cx, unsigned argc, Value* vp) \ @@ -2761,7 +2678,6 @@ visitReferences(TypeDescr& descr, switch (descr.kind()) { case type::Scalar: - case type::Simd: return; case type::Reference: diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h index 9318a0f795..cceff0c638 100644 --- a/js/src/builtin/TypedObject.h +++ b/js/src/builtin/TypedObject.h @@ -117,7 +117,6 @@ namespace type { enum Kind { Scalar = JS_TYPEREPR_SCALAR_KIND, Reference = JS_TYPEREPR_REFERENCE_KIND, - Simd = JS_TYPEREPR_SIMD_KIND, Struct = JS_TYPEREPR_STRUCT_KIND, Array = JS_TYPEREPR_ARRAY_KIND }; @@ -129,7 +128,6 @@ enum Kind { class SimpleTypeDescr; class ComplexTypeDescr; -class SimdTypeDescr; class StructTypeDescr; class TypedProto; @@ -255,14 +253,6 @@ class ScalarTypeDescr : public SimpleTypeDescr "TypedObjectConstants.h must be consistent with Scalar::Type"); static_assert(Scalar::Uint8Clamped == JS_SCALARTYPEREPR_UINT8_CLAMPED, "TypedObjectConstants.h must be consistent with Scalar::Type"); - static_assert(Scalar::Float32x4 == JS_SCALARTYPEREPR_FLOAT32X4, - "TypedObjectConstants.h must be consistent with Scalar::Type"); - static_assert(Scalar::Int8x16 == JS_SCALARTYPEREPR_INT8X16, - "TypedObjectConstants.h must be consistent with Scalar::Type"); - static_assert(Scalar::Int16x8 == JS_SCALARTYPEREPR_INT16X8, - "TypedObjectConstants.h must be consistent with Scalar::Type"); - static_assert(Scalar::Int32x4 == JS_SCALARTYPEREPR_INT32X4, - "TypedObjectConstants.h must be consistent with Scalar::Type"); return Type(getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32()); } @@ -340,25 +330,6 @@ class ComplexTypeDescr : public TypeDescr } }; -enum class SimdType; - -/* - * SIMD Type descriptors. - */ -class SimdTypeDescr : public ComplexTypeDescr -{ - public: - static const type::Kind Kind = type::Simd; - static const bool Opaque = false; - static const Class class_; - static uint32_t size(SimdType t); - static uint32_t alignment(SimdType t); - static MOZ_MUST_USE bool call(JSContext* cx, unsigned argc, Value* vp); - static bool is(const Value& v); - - SimdType type() const; -}; - bool IsTypedObjectClass(const Class* clasp); // Defined below bool IsTypedObjectArray(JSObject& obj); @@ -757,16 +728,6 @@ class InlineOpaqueTypedObject : public InlineTypedObject static const Class class_; }; -// Class for the global SIMD object. -class SimdObject : public JSObject -{ - public: - static const Class class_; - static MOZ_MUST_USE bool toString(JSContext* cx, unsigned int argc, Value* vp); - static MOZ_MUST_USE bool resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId, - bool* resolved); -}; - /* * Usage: NewOpaqueTypedObject(typeObj) * @@ -865,16 +826,6 @@ MOZ_MUST_USE bool ClampToUint8(JSContext* cx, unsigned argc, Value* vp); MOZ_MUST_USE bool GetTypedObjectModule(JSContext* cx, unsigned argc, Value* vp); /* - * Usage: GetSimdTypeDescr(simdTypeRepr) - * - * Returns one of the SIMD type objects, identified by `simdTypeRepr` which must - * be one of the JS_SIMDTYPEREPR_* constants. - * - * The SIMD pseudo-module must have been initialized for this to be safe. - */ -MOZ_MUST_USE bool GetSimdTypeDescr(JSContext* cx, unsigned argc, Value* vp); - -/* * Usage: Store_int8(targetDatum, targetOffset, value) * ... * Store_uint8(targetDatum, targetOffset, value) @@ -1008,8 +959,7 @@ inline bool IsComplexTypeDescrClass(const Class* clasp) { return clasp == &StructTypeDescr::class_ || - clasp == &ArrayTypeDescr::class_ || - clasp == &SimdTypeDescr::class_; + clasp == &ArrayTypeDescr::class_; } inline bool diff --git a/js/src/builtin/TypedObject.js b/js/src/builtin/TypedObject.js index c4ddee486b..31ece2712f 100644 --- a/js/src/builtin/TypedObject.js +++ b/js/src/builtin/TypedObject.js @@ -58,9 +58,6 @@ function TypedObjectGet(descr, typedObj, offset) { case JS_TYPEREPR_REFERENCE_KIND: return TypedObjectGetReference(descr, typedObj, offset); - case JS_TYPEREPR_SIMD_KIND: - return TypedObjectGetSimd(descr, typedObj, offset); - case JS_TYPEREPR_ARRAY_KIND: case JS_TYPEREPR_STRUCT_KIND: return TypedObjectGetDerived(descr, typedObj, offset); @@ -142,144 +139,6 @@ function TypedObjectGetReference(descr, typedObj, offset) { return undefined; } -function TypedObjectGetSimd(descr, typedObj, offset) { - var type = DESCR_TYPE(descr); - var simdTypeDescr = GetSimdTypeDescr(type); - switch (type) { - case JS_SIMDTYPEREPR_FLOAT32X4: - var x = Load_float32(typedObj, offset + 0); - var y = Load_float32(typedObj, offset + 4); - var z = Load_float32(typedObj, offset + 8); - var w = Load_float32(typedObj, offset + 12); - return simdTypeDescr(x, y, z, w); - - case JS_SIMDTYPEREPR_FLOAT64X2: - var x = Load_float64(typedObj, offset + 0); - var y = Load_float64(typedObj, offset + 8); - return simdTypeDescr(x, y); - - case JS_SIMDTYPEREPR_INT8X16: - var s0 = Load_int8(typedObj, offset + 0); - var s1 = Load_int8(typedObj, offset + 1); - var s2 = Load_int8(typedObj, offset + 2); - var s3 = Load_int8(typedObj, offset + 3); - var s4 = Load_int8(typedObj, offset + 4); - var s5 = Load_int8(typedObj, offset + 5); - var s6 = Load_int8(typedObj, offset + 6); - var s7 = Load_int8(typedObj, offset + 7); - var s8 = Load_int8(typedObj, offset + 8); - var s9 = Load_int8(typedObj, offset + 9); - var s10 = Load_int8(typedObj, offset + 10); - var s11 = Load_int8(typedObj, offset + 11); - var s12 = Load_int8(typedObj, offset + 12); - var s13 = Load_int8(typedObj, offset + 13); - var s14 = Load_int8(typedObj, offset + 14); - var s15 = Load_int8(typedObj, offset + 15); - return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15); - - case JS_SIMDTYPEREPR_INT16X8: - var s0 = Load_int16(typedObj, offset + 0); - var s1 = Load_int16(typedObj, offset + 2); - var s2 = Load_int16(typedObj, offset + 4); - var s3 = Load_int16(typedObj, offset + 6); - var s4 = Load_int16(typedObj, offset + 8); - var s5 = Load_int16(typedObj, offset + 10); - var s6 = Load_int16(typedObj, offset + 12); - var s7 = Load_int16(typedObj, offset + 14); - return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7); - - case JS_SIMDTYPEREPR_INT32X4: - var x = Load_int32(typedObj, offset + 0); - var y = Load_int32(typedObj, offset + 4); - var z = Load_int32(typedObj, offset + 8); - var w = Load_int32(typedObj, offset + 12); - return simdTypeDescr(x, y, z, w); - - case JS_SIMDTYPEREPR_UINT8X16: - var s0 = Load_uint8(typedObj, offset + 0); - var s1 = Load_uint8(typedObj, offset + 1); - var s2 = Load_uint8(typedObj, offset + 2); - var s3 = Load_uint8(typedObj, offset + 3); - var s4 = Load_uint8(typedObj, offset + 4); - var s5 = Load_uint8(typedObj, offset + 5); - var s6 = Load_uint8(typedObj, offset + 6); - var s7 = Load_uint8(typedObj, offset + 7); - var s8 = Load_uint8(typedObj, offset + 8); - var s9 = Load_uint8(typedObj, offset + 9); - var s10 = Load_uint8(typedObj, offset + 10); - var s11 = Load_uint8(typedObj, offset + 11); - var s12 = Load_uint8(typedObj, offset + 12); - var s13 = Load_uint8(typedObj, offset + 13); - var s14 = Load_uint8(typedObj, offset + 14); - var s15 = Load_uint8(typedObj, offset + 15); - return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15); - - case JS_SIMDTYPEREPR_UINT16X8: - var s0 = Load_uint16(typedObj, offset + 0); - var s1 = Load_uint16(typedObj, offset + 2); - var s2 = Load_uint16(typedObj, offset + 4); - var s3 = Load_uint16(typedObj, offset + 6); - var s4 = Load_uint16(typedObj, offset + 8); - var s5 = Load_uint16(typedObj, offset + 10); - var s6 = Load_uint16(typedObj, offset + 12); - var s7 = Load_uint16(typedObj, offset + 14); - return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7); - - case JS_SIMDTYPEREPR_UINT32X4: - var x = Load_uint32(typedObj, offset + 0); - var y = Load_uint32(typedObj, offset + 4); - var z = Load_uint32(typedObj, offset + 8); - var w = Load_uint32(typedObj, offset + 12); - return simdTypeDescr(x, y, z, w); - - case JS_SIMDTYPEREPR_BOOL8X16: - var s0 = Load_int8(typedObj, offset + 0); - var s1 = Load_int8(typedObj, offset + 1); - var s2 = Load_int8(typedObj, offset + 2); - var s3 = Load_int8(typedObj, offset + 3); - var s4 = Load_int8(typedObj, offset + 4); - var s5 = Load_int8(typedObj, offset + 5); - var s6 = Load_int8(typedObj, offset + 6); - var s7 = Load_int8(typedObj, offset + 7); - var s8 = Load_int8(typedObj, offset + 8); - var s9 = Load_int8(typedObj, offset + 9); - var s10 = Load_int8(typedObj, offset + 10); - var s11 = Load_int8(typedObj, offset + 11); - var s12 = Load_int8(typedObj, offset + 12); - var s13 = Load_int8(typedObj, offset + 13); - var s14 = Load_int8(typedObj, offset + 14); - var s15 = Load_int8(typedObj, offset + 15); - return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15); - - case JS_SIMDTYPEREPR_BOOL16X8: - var s0 = Load_int16(typedObj, offset + 0); - var s1 = Load_int16(typedObj, offset + 2); - var s2 = Load_int16(typedObj, offset + 4); - var s3 = Load_int16(typedObj, offset + 6); - var s4 = Load_int16(typedObj, offset + 8); - var s5 = Load_int16(typedObj, offset + 10); - var s6 = Load_int16(typedObj, offset + 12); - var s7 = Load_int16(typedObj, offset + 14); - return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7); - - case JS_SIMDTYPEREPR_BOOL32X4: - var x = Load_int32(typedObj, offset + 0); - var y = Load_int32(typedObj, offset + 4); - var z = Load_int32(typedObj, offset + 8); - var w = Load_int32(typedObj, offset + 12); - return simdTypeDescr(x, y, z, w); - - case JS_SIMDTYPEREPR_BOOL64X2: - var x = Load_int32(typedObj, offset + 0); - var y = Load_int32(typedObj, offset + 8); - return simdTypeDescr(x, y); - - } - - assert(false, "Unhandled SIMD type: " + type); - return undefined; -} - /////////////////////////////////////////////////////////////////////////// // Setting values // @@ -301,10 +160,6 @@ function TypedObjectSet(descr, typedObj, offset, name, fromValue) { TypedObjectSetReference(descr, typedObj, offset, name, fromValue); return; - case JS_TYPEREPR_SIMD_KIND: - TypedObjectSetSimd(descr, typedObj, offset, fromValue); - return; - case JS_TYPEREPR_ARRAY_KIND: var length = DESCR_ARRAY_LENGTH(descr); if (TypedObjectSetArray(descr, length, typedObj, offset, fromValue)) @@ -418,107 +273,6 @@ function TypedObjectSetReference(descr, typedObj, offset, name, fromValue) { return undefined; } -// Sets `fromValue` to `this` assuming that `this` is a scalar type. -function TypedObjectSetSimd(descr, typedObj, offset, fromValue) { - if (!IsObject(fromValue) || !ObjectIsTypedObject(fromValue)) - ThrowTypeError(JSMSG_CANT_CONVERT_TO, - typeof(fromValue), - DESCR_STRING_REPR(descr)); - - if (!DescrsEquiv(descr, TypedObjectTypeDescr(fromValue))) - ThrowTypeError(JSMSG_CANT_CONVERT_TO, - typeof(fromValue), - DESCR_STRING_REPR(descr)); - - var type = DESCR_TYPE(descr); - switch (type) { - case JS_SIMDTYPEREPR_FLOAT32X4: - Store_float32(typedObj, offset + 0, Load_float32(fromValue, 0)); - Store_float32(typedObj, offset + 4, Load_float32(fromValue, 4)); - Store_float32(typedObj, offset + 8, Load_float32(fromValue, 8)); - Store_float32(typedObj, offset + 12, Load_float32(fromValue, 12)); - break; - case JS_SIMDTYPEREPR_FLOAT64X2: - Store_float64(typedObj, offset + 0, Load_float64(fromValue, 0)); - Store_float64(typedObj, offset + 8, Load_float64(fromValue, 8)); - break; - case JS_SIMDTYPEREPR_INT8X16: - case JS_SIMDTYPEREPR_BOOL8X16: - Store_int8(typedObj, offset + 0, Load_int8(fromValue, 0)); - Store_int8(typedObj, offset + 1, Load_int8(fromValue, 1)); - Store_int8(typedObj, offset + 2, Load_int8(fromValue, 2)); - Store_int8(typedObj, offset + 3, Load_int8(fromValue, 3)); - Store_int8(typedObj, offset + 4, Load_int8(fromValue, 4)); - Store_int8(typedObj, offset + 5, Load_int8(fromValue, 5)); - Store_int8(typedObj, offset + 6, Load_int8(fromValue, 6)); - Store_int8(typedObj, offset + 7, Load_int8(fromValue, 7)); - Store_int8(typedObj, offset + 8, Load_int8(fromValue, 8)); - Store_int8(typedObj, offset + 9, Load_int8(fromValue, 9)); - Store_int8(typedObj, offset + 10, Load_int8(fromValue, 10)); - Store_int8(typedObj, offset + 11, Load_int8(fromValue, 11)); - Store_int8(typedObj, offset + 12, Load_int8(fromValue, 12)); - Store_int8(typedObj, offset + 13, Load_int8(fromValue, 13)); - Store_int8(typedObj, offset + 14, Load_int8(fromValue, 14)); - Store_int8(typedObj, offset + 15, Load_int8(fromValue, 15)); - break; - case JS_SIMDTYPEREPR_INT16X8: - case JS_SIMDTYPEREPR_BOOL16X8: - Store_int16(typedObj, offset + 0, Load_int16(fromValue, 0)); - Store_int16(typedObj, offset + 2, Load_int16(fromValue, 2)); - Store_int16(typedObj, offset + 4, Load_int16(fromValue, 4)); - Store_int16(typedObj, offset + 6, Load_int16(fromValue, 6)); - Store_int16(typedObj, offset + 8, Load_int16(fromValue, 8)); - Store_int16(typedObj, offset + 10, Load_int16(fromValue, 10)); - Store_int16(typedObj, offset + 12, Load_int16(fromValue, 12)); - Store_int16(typedObj, offset + 14, Load_int16(fromValue, 14)); - break; - case JS_SIMDTYPEREPR_INT32X4: - case JS_SIMDTYPEREPR_BOOL32X4: - case JS_SIMDTYPEREPR_BOOL64X2: - Store_int32(typedObj, offset + 0, Load_int32(fromValue, 0)); - Store_int32(typedObj, offset + 4, Load_int32(fromValue, 4)); - Store_int32(typedObj, offset + 8, Load_int32(fromValue, 8)); - Store_int32(typedObj, offset + 12, Load_int32(fromValue, 12)); - break; - case JS_SIMDTYPEREPR_UINT8X16: - Store_uint8(typedObj, offset + 0, Load_uint8(fromValue, 0)); - Store_uint8(typedObj, offset + 1, Load_uint8(fromValue, 1)); - Store_uint8(typedObj, offset + 2, Load_uint8(fromValue, 2)); - Store_uint8(typedObj, offset + 3, Load_uint8(fromValue, 3)); - Store_uint8(typedObj, offset + 4, Load_uint8(fromValue, 4)); - Store_uint8(typedObj, offset + 5, Load_uint8(fromValue, 5)); - Store_uint8(typedObj, offset + 6, Load_uint8(fromValue, 6)); - Store_uint8(typedObj, offset + 7, Load_uint8(fromValue, 7)); - Store_uint8(typedObj, offset + 8, Load_uint8(fromValue, 8)); - Store_uint8(typedObj, offset + 9, Load_uint8(fromValue, 9)); - Store_uint8(typedObj, offset + 10, Load_uint8(fromValue, 10)); - Store_uint8(typedObj, offset + 11, Load_uint8(fromValue, 11)); - Store_uint8(typedObj, offset + 12, Load_uint8(fromValue, 12)); - Store_uint8(typedObj, offset + 13, Load_uint8(fromValue, 13)); - Store_uint8(typedObj, offset + 14, Load_uint8(fromValue, 14)); - Store_uint8(typedObj, offset + 15, Load_uint8(fromValue, 15)); - break; - case JS_SIMDTYPEREPR_UINT16X8: - Store_uint16(typedObj, offset + 0, Load_uint16(fromValue, 0)); - Store_uint16(typedObj, offset + 2, Load_uint16(fromValue, 2)); - Store_uint16(typedObj, offset + 4, Load_uint16(fromValue, 4)); - Store_uint16(typedObj, offset + 6, Load_uint16(fromValue, 6)); - Store_uint16(typedObj, offset + 8, Load_uint16(fromValue, 8)); - Store_uint16(typedObj, offset + 10, Load_uint16(fromValue, 10)); - Store_uint16(typedObj, offset + 12, Load_uint16(fromValue, 12)); - Store_uint16(typedObj, offset + 14, Load_uint16(fromValue, 14)); - break; - case JS_SIMDTYPEREPR_UINT32X4: - Store_uint32(typedObj, offset + 0, Load_uint32(fromValue, 0)); - Store_uint32(typedObj, offset + 4, Load_uint32(fromValue, 4)); - Store_uint32(typedObj, offset + 8, Load_uint32(fromValue, 8)); - Store_uint32(typedObj, offset + 12, Load_uint32(fromValue, 12)); - break; - default: - assert(false, "Unhandled Simd type: " + type); - } -} - /////////////////////////////////////////////////////////////////////////// // C++ Wrappers // @@ -635,241 +389,6 @@ function TypedObjectArrayRedimension(newArrayType) { } /////////////////////////////////////////////////////////////////////////// -// SIMD - -function SimdProtoString(type) { - switch (type) { - case JS_SIMDTYPEREPR_INT8X16: - return "Int8x16"; - case JS_SIMDTYPEREPR_INT16X8: - return "Int16x8"; - case JS_SIMDTYPEREPR_INT32X4: - return "Int32x4"; - case JS_SIMDTYPEREPR_UINT8X16: - return "Uint8x16"; - case JS_SIMDTYPEREPR_UINT16X8: - return "Uint16x8"; - case JS_SIMDTYPEREPR_UINT32X4: - return "Uint32x4"; - case JS_SIMDTYPEREPR_FLOAT32X4: - return "Float32x4"; - case JS_SIMDTYPEREPR_FLOAT64X2: - return "Float64x2"; - case JS_SIMDTYPEREPR_BOOL8X16: - return "Bool8x16"; - case JS_SIMDTYPEREPR_BOOL16X8: - return "Bool16x8"; - case JS_SIMDTYPEREPR_BOOL32X4: - return "Bool32x4"; - case JS_SIMDTYPEREPR_BOOL64X2: - return "Bool64x2"; - } - - assert(false, "Unhandled type constant"); - return undefined; -} - -function SimdTypeToLength(type) { - switch (type) { - case JS_SIMDTYPEREPR_INT8X16: - case JS_SIMDTYPEREPR_BOOL8X16: - return 16; - case JS_SIMDTYPEREPR_INT16X8: - case JS_SIMDTYPEREPR_BOOL16X8: - return 8; - case JS_SIMDTYPEREPR_INT32X4: - case JS_SIMDTYPEREPR_FLOAT32X4: - case JS_SIMDTYPEREPR_BOOL32X4: - return 4; - case JS_SIMDTYPEREPR_FLOAT64X2: - case JS_SIMDTYPEREPR_BOOL64X2: - return 2; - } - - assert(false, "Unhandled type constant"); - return undefined; -} - -// This implements SIMD.*.prototype.valueOf(). -// Once we have proper value semantics for SIMD types, this function should just -// perform a type check and return this. -// For now, throw a TypeError unconditionally since valueOf() was probably -// called from ToNumber() which is supposed to throw when attempting to convert -// a SIMD value to a number. -function SimdValueOf() { - if (!IsObject(this) || !ObjectIsTypedObject(this)) - ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "SIMD", "valueOf", typeof this); - - var descr = TypedObjectTypeDescr(this); - - if (DESCR_KIND(descr) != JS_TYPEREPR_SIMD_KIND) - ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "SIMD", "valueOf", typeof this); - - ThrowTypeError(JSMSG_SIMD_TO_NUMBER); -} - -function SimdToSource() { - if (!IsObject(this) || !ObjectIsTypedObject(this)) - ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "SIMD.*", "toSource", typeof this); - - var descr = TypedObjectTypeDescr(this); - - if (DESCR_KIND(descr) != JS_TYPEREPR_SIMD_KIND) - ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "SIMD.*", "toSource", typeof this); - - return SimdFormatString(descr, this); -} - -function SimdToString() { - if (!IsObject(this) || !ObjectIsTypedObject(this)) - ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "SIMD.*", "toString", typeof this); - - var descr = TypedObjectTypeDescr(this); - - if (DESCR_KIND(descr) != JS_TYPEREPR_SIMD_KIND) - ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "SIMD.*", "toString", typeof this); - - return SimdFormatString(descr, this); -} - -function SimdFormatString(descr, typedObj) { - var typerepr = DESCR_TYPE(descr); - var protoString = SimdProtoString(typerepr); - switch (typerepr) { - case JS_SIMDTYPEREPR_INT8X16: { - var s1 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 0); - var s2 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 1); - var s3 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 2); - var s4 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 3); - var s5 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 4); - var s6 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 5); - var s7 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 6); - var s8 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 7); - var s9 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 8); - var s10 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 9); - var s11 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 10); - var s12 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 11); - var s13 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 12); - var s14 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 13); - var s15 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 14); - var s16 = callFunction(std_SIMD_Int8x16_extractLane, null, typedObj, 15); - return `SIMD.${protoString}(${s1}, ${s2}, ${s3}, ${s4}, ${s5}, ${s6}, ${s7}, ${s8}, ${s9}, ${s10}, ${s11}, ${s12}, ${s13}, ${s14}, ${s15}, ${s16})`; - } - case JS_SIMDTYPEREPR_INT16X8: { - var s1 = callFunction(std_SIMD_Int16x8_extractLane, null, typedObj, 0); - var s2 = callFunction(std_SIMD_Int16x8_extractLane, null, typedObj, 1); - var s3 = callFunction(std_SIMD_Int16x8_extractLane, null, typedObj, 2); - var s4 = callFunction(std_SIMD_Int16x8_extractLane, null, typedObj, 3); - var s5 = callFunction(std_SIMD_Int16x8_extractLane, null, typedObj, 4); - var s6 = callFunction(std_SIMD_Int16x8_extractLane, null, typedObj, 5); - var s7 = callFunction(std_SIMD_Int16x8_extractLane, null, typedObj, 6); - var s8 = callFunction(std_SIMD_Int16x8_extractLane, null, typedObj, 7); - return `SIMD.${protoString}(${s1}, ${s2}, ${s3}, ${s4}, ${s5}, ${s6}, ${s7}, ${s8})`; - } - case JS_SIMDTYPEREPR_INT32X4: { - var x = callFunction(std_SIMD_Int32x4_extractLane, null, typedObj, 0); - var y = callFunction(std_SIMD_Int32x4_extractLane, null, typedObj, 1); - var z = callFunction(std_SIMD_Int32x4_extractLane, null, typedObj, 2); - var w = callFunction(std_SIMD_Int32x4_extractLane, null, typedObj, 3); - return `SIMD.${protoString}(${x}, ${y}, ${z}, ${w})`; - } - case JS_SIMDTYPEREPR_UINT8X16: { - var s1 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 0); - var s2 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 1); - var s3 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 2); - var s4 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 3); - var s5 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 4); - var s6 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 5); - var s7 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 6); - var s8 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 7); - var s9 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 8); - var s10 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 9); - var s11 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 10); - var s12 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 11); - var s13 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 12); - var s14 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 13); - var s15 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 14); - var s16 = callFunction(std_SIMD_Uint8x16_extractLane, null, typedObj, 15); - return `SIMD.${protoString}(${s1}, ${s2}, ${s3}, ${s4}, ${s5}, ${s6}, ${s7}, ${s8}, ${s9}, ${s10}, ${s11}, ${s12}, ${s13}, ${s14}, ${s15}, ${s16})`; - } - case JS_SIMDTYPEREPR_UINT16X8: { - var s1 = callFunction(std_SIMD_Uint16x8_extractLane, null, typedObj, 0); - var s2 = callFunction(std_SIMD_Uint16x8_extractLane, null, typedObj, 1); - var s3 = callFunction(std_SIMD_Uint16x8_extractLane, null, typedObj, 2); - var s4 = callFunction(std_SIMD_Uint16x8_extractLane, null, typedObj, 3); - var s5 = callFunction(std_SIMD_Uint16x8_extractLane, null, typedObj, 4); - var s6 = callFunction(std_SIMD_Uint16x8_extractLane, null, typedObj, 5); - var s7 = callFunction(std_SIMD_Uint16x8_extractLane, null, typedObj, 6); - var s8 = callFunction(std_SIMD_Uint16x8_extractLane, null, typedObj, 7); - return `SIMD.${protoString}(${s1}, ${s2}, ${s3}, ${s4}, ${s5}, ${s6}, ${s7}, ${s8})`; - } - case JS_SIMDTYPEREPR_UINT32X4: { - var x = callFunction(std_SIMD_Uint32x4_extractLane, null, typedObj, 0); - var y = callFunction(std_SIMD_Uint32x4_extractLane, null, typedObj, 1); - var z = callFunction(std_SIMD_Uint32x4_extractLane, null, typedObj, 2); - var w = callFunction(std_SIMD_Uint32x4_extractLane, null, typedObj, 3); - return `SIMD.${protoString}(${x}, ${y}, ${z}, ${w})`; - } - case JS_SIMDTYPEREPR_FLOAT32X4: { - var x = callFunction(std_SIMD_Float32x4_extractLane, null, typedObj, 0); - var y = callFunction(std_SIMD_Float32x4_extractLane, null, typedObj, 1); - var z = callFunction(std_SIMD_Float32x4_extractLane, null, typedObj, 2); - var w = callFunction(std_SIMD_Float32x4_extractLane, null, typedObj, 3); - return `SIMD.${protoString}(${x}, ${y}, ${z}, ${w})`; - } - case JS_SIMDTYPEREPR_FLOAT64X2: { - var x = callFunction(std_SIMD_Float64x2_extractLane, null, typedObj, 0); - var y = callFunction(std_SIMD_Float64x2_extractLane, null, typedObj, 1); - return `SIMD.${protoString}(${x}, ${y})`; - } - case JS_SIMDTYPEREPR_BOOL8X16: { - var s1 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 0); - var s2 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 1); - var s3 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 2); - var s4 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 3); - var s5 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 4); - var s6 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 5); - var s7 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 6); - var s8 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 7); - var s9 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 8); - var s10 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 9); - var s11 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 10); - var s12 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 11); - var s13 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 12); - var s14 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 13); - var s15 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 14); - var s16 = callFunction(std_SIMD_Bool8x16_extractLane, null, typedObj, 15); - return `SIMD.${protoString}(${s1}, ${s2}, ${s3}, ${s4}, ${s5}, ${s6}, ${s7}, ${s8}, ${s9}, ${s10}, ${s11}, ${s12}, ${s13}, ${s14}, ${s15}, ${s16})`; - } - case JS_SIMDTYPEREPR_BOOL16X8: { - var s1 = callFunction(std_SIMD_Bool16x8_extractLane, null, typedObj, 0); - var s2 = callFunction(std_SIMD_Bool16x8_extractLane, null, typedObj, 1); - var s3 = callFunction(std_SIMD_Bool16x8_extractLane, null, typedObj, 2); - var s4 = callFunction(std_SIMD_Bool16x8_extractLane, null, typedObj, 3); - var s5 = callFunction(std_SIMD_Bool16x8_extractLane, null, typedObj, 4); - var s6 = callFunction(std_SIMD_Bool16x8_extractLane, null, typedObj, 5); - var s7 = callFunction(std_SIMD_Bool16x8_extractLane, null, typedObj, 6); - var s8 = callFunction(std_SIMD_Bool16x8_extractLane, null, typedObj, 7); - return `SIMD.${protoString}(${s1}, ${s2}, ${s3}, ${s4}, ${s5}, ${s6}, ${s7}, ${s8})`; - } - case JS_SIMDTYPEREPR_BOOL32X4: { - var x = callFunction(std_SIMD_Bool32x4_extractLane, null, typedObj, 0); - var y = callFunction(std_SIMD_Bool32x4_extractLane, null, typedObj, 1); - var z = callFunction(std_SIMD_Bool32x4_extractLane, null, typedObj, 2); - var w = callFunction(std_SIMD_Bool32x4_extractLane, null, typedObj, 3); - return `SIMD.${protoString}(${x}, ${y}, ${z}, ${w})`; - } - case JS_SIMDTYPEREPR_BOOL64X2: { - var x = callFunction(std_SIMD_Bool64x2_extractLane, null, typedObj, 0); - var y = callFunction(std_SIMD_Bool64x2_extractLane, null, typedObj, 1); - return `SIMD.${protoString}(${x}, ${y})`; - } - } - assert(false, "unexpected SIMD kind"); - return '?'; -} - -/////////////////////////////////////////////////////////////////////////// // Miscellaneous function DescrsEquiv(descr1, descr2) { diff --git a/js/src/builtin/TypedObjectConstants.h b/js/src/builtin/TypedObjectConstants.h index aa930d29bb..5900d131fe 100644 --- a/js/src/builtin/TypedObjectConstants.h +++ b/js/src/builtin/TypedObjectConstants.h @@ -52,7 +52,7 @@ #define JS_DESCR_SLOT_ARRAYPROTO 6 // Lazily created prototype for arrays #define JS_DESCR_SLOT_TRACE_LIST 7 // List of references for use in tracing -// Slots on scalars, references, and SIMD objects +// Slots on scalars and references #define JS_DESCR_SLOT_TYPE 8 // Type code // Slots on array descriptors @@ -74,7 +74,6 @@ #define JS_TYPEREPR_REFERENCE_KIND 2 #define JS_TYPEREPR_STRUCT_KIND 3 #define JS_TYPEREPR_ARRAY_KIND 4 -#define JS_TYPEREPR_SIMD_KIND 5 // These constants are for use exclusively in JS code. In C++ code, // prefer Scalar::Int8 etc, which allows you to write a switch which will @@ -90,10 +89,6 @@ #define JS_SCALARTYPEREPR_UINT8_CLAMPED 8 #define JS_SCALARTYPEREPR_BIGINT64 9 #define JS_SCALARTYPEREPR_BIGUINT64 10 -#define JS_SCALARTYPEREPR_FLOAT32X4 13 -#define JS_SCALARTYPEREPR_INT8X16 14 -#define JS_SCALARTYPEREPR_INT16X8 15 -#define JS_SCALARTYPEREPR_INT32X4 16 // These constants are for use exclusively in JS code. In C++ code, // prefer ReferenceTypeRepresentation::TYPE_ANY etc, which allows @@ -103,20 +98,4 @@ #define JS_REFERENCETYPEREPR_OBJECT 1 #define JS_REFERENCETYPEREPR_STRING 2 -// These constants are for use exclusively in JS code. In C++ code, prefer -// SimdType::Int32x4 etc, since that allows you to write a switch which will -// receive a warning if you omit a case. -#define JS_SIMDTYPEREPR_INT8X16 0 -#define JS_SIMDTYPEREPR_INT16X8 1 -#define JS_SIMDTYPEREPR_INT32X4 2 -#define JS_SIMDTYPEREPR_UINT8X16 3 -#define JS_SIMDTYPEREPR_UINT16X8 4 -#define JS_SIMDTYPEREPR_UINT32X4 5 -#define JS_SIMDTYPEREPR_FLOAT32X4 6 -#define JS_SIMDTYPEREPR_FLOAT64X2 7 -#define JS_SIMDTYPEREPR_BOOL8X16 8 -#define JS_SIMDTYPEREPR_BOOL16X8 9 -#define JS_SIMDTYPEREPR_BOOL32X4 10 -#define JS_SIMDTYPEREPR_BOOL64X2 11 - #endif diff --git a/js/src/devtools/automation/cgc-jittest-timeouts.txt b/js/src/devtools/automation/cgc-jittest-timeouts.txt index 84e29f8931..dcb37d660d 100644 --- a/js/src/devtools/automation/cgc-jittest-timeouts.txt +++ b/js/src/devtools/automation/cgc-jittest-timeouts.txt @@ -1,4 +1,3 @@ -SIMD/nursery-overflow.js asm.js/testParallelCompile.js auto-regress/bug653395.js auto-regress/bug654392.js diff --git a/js/src/doc/JITOptimizations/Outcomes.md b/js/src/doc/JITOptimizations/Outcomes.md index b0eb9c43af..471c794174 100644 --- a/js/src/doc/JITOptimizations/Outcomes.md +++ b/js/src/doc/JITOptimizations/Outcomes.md @@ -152,11 +152,6 @@ Failed to do range check of element access on a typed object. ### AccessNotDense -### AccessNotSimdObject - -The observed type of the target of the property access doesn't guarantee -that it is a SIMD object. - ### AccessNotTypedObject The observed type of the target of the property access doesn't guarantee @@ -218,15 +213,6 @@ the keys have never been observed to be a String, Symbol, or Int32. IonMonkey only generates inline caches for element accesses which are either on dense objects (e.g. dense Arrays), or Typed Arrays. -### NoSimdJitSupport - -Optimization failed because SIMD JIT support was not enabled. - -### SimdTypeNotOptimized - -The type observed as being retrieved from this property access did not -match an optimizable type. - ### HasCommonInliningPath Inlining was abandoned because the inlining call path was repeated. A diff --git a/js/src/jit-test/lib/simd.js b/js/src/jit-test/lib/simd.js deleted file mode 100644 index f275c6f081..0000000000 --- a/js/src/jit-test/lib/simd.js +++ /dev/null @@ -1,109 +0,0 @@ -if (!this.hasOwnProperty("SIMD")) - quit(); - -function booleanBinaryX4(op, v, w) { - var arr = []; - var [varr, warr] = [simdToArray(v), simdToArray(w)]; - for (var i = 0; i < 4; i++) - arr[i] = op(varr[i], warr[i]); - return arr; -} - -function binaryX(op, v, w) { - var arr = []; - var [varr, warr] = [simdToArray(v), simdToArray(w)]; - [varr, warr] = [varr.map(Math.fround), warr.map(Math.fround)]; - for (var i = 0; i < varr.length; i++) - arr[i] = op(varr[i], warr[i]); - return arr.map(Math.fround); -} - -function unaryX4(op, v, coerceFunc) { - var arr = []; - var varr = simdToArray(v).map(coerceFunc); - for (var i = 0; i < 4; i++) - arr[i] = op(varr[i]); - return arr.map(coerceFunc); -} - -function assertNear(a, b) { - assertEq((a != a && b != b) || Math.abs(a - b) < 0.001, true); -} - -function GetType(v) { - var pt = Object.getPrototypeOf(v); - switch (pt) { - case SIMD.Int8x16.prototype: return SIMD.Int8x16; - case SIMD.Int16x8.prototype: return SIMD.Int16x8; - case SIMD.Int32x4.prototype: return SIMD.Int32x4; - case SIMD.Uint8x16.prototype: return SIMD.Uint8x16; - case SIMD.Uint16x8.prototype: return SIMD.Uint16x8; - case SIMD.Uint32x4.prototype: return SIMD.Uint32x4; - case SIMD.Float32x4.prototype: return SIMD.Float32x4; - case SIMD.Bool8x16.prototype: return SIMD.Bool8x16; - case SIMD.Bool16x8.prototype: return SIMD.Bool16x8; - case SIMD.Bool32x4.prototype: return SIMD.Bool32x4; - } - throw "unexpected SIMD type"; -} - -function GetLength(t) { - switch (t) { - case SIMD.Int8x16: return 16; - case SIMD.Int16x8: return 8; - case SIMD.Int32x4: return 4; - case SIMD.Uint8x16: return 16; - case SIMD.Uint16x8: return 8; - case SIMD.Uint32x4: return 4; - case SIMD.Float32x4: return 4; - case SIMD.Bool8x16: return 16; - case SIMD.Bool16x8: return 8; - case SIMD.Bool32x4: return 4; - } - throw "unexpected SIMD type"; -} - -function assertEqVec(v, w) { - var typeV = GetType(v); - var lengthV = GetLength(typeV); - var ext = typeV.extractLane; - assertEq(GetType(w), typeV); - for (var i = 0; i < lengthV; i++) - assertEq(ext(v, i), ext(w, i)); -} - -function assertEqVecArr(v, w) { - var typeV = GetType(v); - var lengthV = GetLength(typeV); - var ext = typeV.extractLane; - assertEq(w.length, lengthV); - - for (var i = 0; i < lengthV; i++) - assertEq(ext(v, i), w[i]); -} - -function assertEqX4(vec, arr, ...opts) { - - var assertFunc; - if (opts.length == 1 && typeof opts[0] !== 'undefined') { - assertFunc = opts[0]; - } else { - assertFunc = assertEq; - } - - var Type = GetType(vec); - - assertFunc(Type.extractLane(vec, 0), arr[0]); - assertFunc(Type.extractLane(vec, 1), arr[1]); - assertFunc(Type.extractLane(vec, 2), arr[2]); - assertFunc(Type.extractLane(vec, 3), arr[3]); -} - -function simdToArray(vec) { - var Type = GetType(vec); - var Length = GetLength(Type); - var a = []; - for (var i = 0; i < Length; i++) - a.push(Type.extractLane(vec, i)); - return a; -} diff --git a/js/src/jit-test/tests/SIMD/binary-arith.js b/js/src/jit-test/tests/SIMD/binary-arith.js deleted file mode 100644 index 74211d46db..0000000000 --- a/js/src/jit-test/tests/SIMD/binary-arith.js +++ /dev/null @@ -1,30 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 50); - -function f() { - var i1 = SIMD.Int32x4(1, 2, 3, 4); - var i2 = SIMD.Int32x4(4, 3, 2, 1); - - var f1 = SIMD.Float32x4(1, 2, 3, 4); - var f2 = SIMD.Float32x4(4, 3, 2, 1); - - var i8_1 = SIMD.Int8x16(1, 2, 3, 4, 20, 30, 40, 50, 100, 115, 120, 125); - var i8_2 = SIMD.Int8x16(4, 3, 2, 1, 8, 7, 6, 5, 12, 11, 10, 9); - - for (var i = 0; i < 150; i++) { - assertEqX4(SIMD.Float32x4.add(f1, f2), binaryX((x, y) => x + y, f1, f2)); - assertEqX4(SIMD.Float32x4.sub(f1, f2), binaryX((x, y) => x - y, f1, f2)); - assertEqX4(SIMD.Float32x4.mul(f1, f2), binaryX((x, y) => x * y, f1, f2)); - - assertEqX4(SIMD.Int32x4.add(i1, i2), binaryX((x, y) => x + y, i1, i2)); - assertEqX4(SIMD.Int32x4.sub(i1, i2), binaryX((x, y) => x - y, i1, i2)); - assertEqX4(SIMD.Int32x4.mul(i1, i2), binaryX((x, y) => x * y, i1, i2)); - - assertEqX4(SIMD.Int8x16.add(i8_1, i8_2), binaryX((x, y) => (x + y) << 24 >> 24, i8_1, i8_2)); - assertEqX4(SIMD.Int8x16.sub(i8_1, i8_2), binaryX((x, y) => (x - y) << 24 >> 24, i8_1, i8_2)); - assertEqX4(SIMD.Int8x16.mul(i8_1, i8_2), binaryX((x, y) => (x * y) << 24 >> 24, i8_1, i8_2)); - } -} - -f(); diff --git a/js/src/jit-test/tests/SIMD/bool32x4-arith.js b/js/src/jit-test/tests/SIMD/bool32x4-arith.js deleted file mode 100644 index bafceefa9e..0000000000 --- a/js/src/jit-test/tests/SIMD/bool32x4-arith.js +++ /dev/null @@ -1,15 +0,0 @@ -load(libdir + "simd.js"); - -setJitCompilerOption("ion.warmup.trigger", 50); - -function f() { - var b1 = SIMD.Bool32x4(true, false, true, false); - var b2 = SIMD.Bool32x4(true, true, true, true); - do { - assertEqX4(SIMD.Bool32x4.and(b1, b2), booleanBinaryX4((x, y) => x && y, b1, b2)); - assertEqX4(SIMD.Bool32x4.or(b1, b2), booleanBinaryX4((x, y) => x || y, b1, b2)); - assertEqX4(SIMD.Bool32x4.xor(b1, b2), booleanBinaryX4((x, y) => x != y, b1, b2)); - } while (!inIon()); -} - -f(); diff --git a/js/src/jit-test/tests/SIMD/bool32x4-const.js b/js/src/jit-test/tests/SIMD/bool32x4-const.js deleted file mode 100644 index 54bada215b..0000000000 --- a/js/src/jit-test/tests/SIMD/bool32x4-const.js +++ /dev/null @@ -1,65 +0,0 @@ -load(libdir + "simd.js"); - -setJitCompilerOption("ion.warmup.trigger", 50); - -// Test constant folding into the Bool32x4 constructor. -// Verify that we get the truthiness right, c.f. the ECMA ToBoolean() function. -function f1() { - var B = SIMD.Bool32x4; - var S = SIMD.Bool32x4.splat; - return [ - B(false, false, false, true), - B(true), - B(undefined, null, "", "x"), - B({}, 0, 1, -0.0), - B(NaN, -NaN, Symbol(), objectEmulatingUndefined()), - - S(false), - S(true), - S(undefined), - S(null), - - S(""), - S("x"), - S(0), - S(1), - - S({}), - S(-0.0), - S(NaN), - S(Symbol()), - - S(objectEmulatingUndefined()) - ]; -} - -function f() { - for (var i = 0; i < 100; i++) { - var a = f1() - assertEqX4(a[0], [false, false, false, true]); - assertEqX4(a[1], [true, false, false, false]); - assertEqX4(a[2], [false, false, false, true]); - assertEqX4(a[3], [true, false, true, false]); - assertEqX4(a[4], [false, false, true, false]); - - // Splats. - assertEqX4(a[5], [false, false, false, false]); - assertEqX4(a[6], [true, true, true, true]); - assertEqX4(a[7], [false, false, false, false]); - assertEqX4(a[8], [false, false, false, false]); - - assertEqX4(a[9], [false, false, false, false]); - assertEqX4(a[10], [true, true, true, true]); - assertEqX4(a[11], [false, false, false, false]); - assertEqX4(a[12], [true, true, true, true]); - - assertEqX4(a[13], [true, true, true, true]); - assertEqX4(a[14], [false, false, false, false]); - assertEqX4(a[15], [false, false, false, false]); - assertEqX4(a[16], [true, true, true, true]); - - assertEqX4(a[17], [false, false, false, false]); - } -} - -f(); diff --git a/js/src/jit-test/tests/SIMD/bug1109911.js b/js/src/jit-test/tests/SIMD/bug1109911.js deleted file mode 100644 index 23a5c5721d..0000000000 --- a/js/src/jit-test/tests/SIMD/bug1109911.js +++ /dev/null @@ -1,11 +0,0 @@ -if (typeof TypedObject === "undefined" || typeof SIMD === 'undefined') - quit(); - -var Int32x4 = SIMD.Int32x4; -var a = Int32x4((4294967295), 200, 300, 400); -addCase( new Array(Math.pow(2,12)) ); -for ( var arg = "", i = 0; i < Math.pow(2,12); i++ ) {} -addCase( a ); -function addCase(object) { - object.length -} diff --git a/js/src/jit-test/tests/SIMD/bug1121299.js b/js/src/jit-test/tests/SIMD/bug1121299.js deleted file mode 100644 index 17ca46e2ec..0000000000 --- a/js/src/jit-test/tests/SIMD/bug1121299.js +++ /dev/null @@ -1,31 +0,0 @@ -if (!this.hasOwnProperty("SIMD")) - quit(); - -setJitCompilerOption("baseline.warmup.trigger", 10); -setJitCompilerOption("ion.warmup.trigger", 30); - -function test_1(i) { - if (i >= 40) - return; - var a = SIMD.Float32x4(1.1, 2.2, 3.3, 4.6); - SIMD.Int32x4.fromFloat32x4(a); - test_1(i + 1); -} -test_1(0); - - -var Float32x4 = SIMD.Float32x4; -function test_2() { - var Array = Float32x4.array(3); - var array = new Array([ - Float32x4(1, 2, 3, 4), - Float32x4(5, 6, 7, 8), - Float32x4(9, 10, 11, 12) - ]); - if (typeof reportCompare === "function") - reportCompare(true, true); -} -test_2(); -evaluate("test_2(); test_2();", { - isRunOnce: true, -}); diff --git a/js/src/jit-test/tests/SIMD/bug1123631.js b/js/src/jit-test/tests/SIMD/bug1123631.js deleted file mode 100644 index 28c0e0aa15..0000000000 --- a/js/src/jit-test/tests/SIMD/bug1123631.js +++ /dev/null @@ -1,9 +0,0 @@ -if (!this.hasOwnProperty("SIMD")) - quit(); - -var Float64x2 = SIMD.Float64x2; -function test() { - var a = Float64x2(1, 2); -} -test(); -test(); diff --git a/js/src/jit-test/tests/SIMD/bug1130845.js b/js/src/jit-test/tests/SIMD/bug1130845.js deleted file mode 100644 index 2baf3865d2..0000000000 --- a/js/src/jit-test/tests/SIMD/bug1130845.js +++ /dev/null @@ -1,15 +0,0 @@ -if (!this.hasOwnProperty("SIMD")) - quit(); - -var Int32x4 = SIMD.Int32x4; -function test() { - var a = Int32x4(); - var b = Int32x4(10, 20, 30, 40); - var c = SIMD.Int32x4.and(a, b); - assertEq(Int32x4.extractLane(c, 0), 0); - return 0; -} -test(); -var u = [], v = []; -for (var j=0; j<u.length; ++j) - v[test()] = t; diff --git a/js/src/jit-test/tests/SIMD/bug1241872.js b/js/src/jit-test/tests/SIMD/bug1241872.js deleted file mode 100644 index c36ebcc6b8..0000000000 --- a/js/src/jit-test/tests/SIMD/bug1241872.js +++ /dev/null @@ -1,10 +0,0 @@ -if (typeof SIMD !== 'object') - quit(0); - -function test() { - return SIMD.Float32x4().toSource(); -} - -var r = ''; -for (var i = 0; i < 10000; i++) - r = test(); diff --git a/js/src/jit-test/tests/SIMD/bug1248503.js b/js/src/jit-test/tests/SIMD/bug1248503.js deleted file mode 100644 index e121cea1d1..0000000000 --- a/js/src/jit-test/tests/SIMD/bug1248503.js +++ /dev/null @@ -1,16 +0,0 @@ -if (typeof SIMD !== 'object') - quit(0); - -function assertEqVec(v, w) { - [0].forEach(i => v, w); - function assertEqX4(...opts) {} -} -gczeal(1); -function f() { - SIMD.Float32x4(); - var i1 = SIMD.Int32x4(); - for (j = 0; j < 100000; ++j, eval.eval) - assertEqVec(SIMD.Int32x4.check(i1), i1); -} -f(); - diff --git a/js/src/jit-test/tests/SIMD/bug1273483.js b/js/src/jit-test/tests/SIMD/bug1273483.js deleted file mode 100644 index 3c9386b4f4..0000000000 --- a/js/src/jit-test/tests/SIMD/bug1273483.js +++ /dev/null @@ -1,9 +0,0 @@ -if (typeof SIMD === 'undefined') - quit(); - -Int8x16 = SIMD.Int8x16; -var Int32x4 = SIMD.Int32x4; -function testSwizzleForType(type) type(); -testSwizzleForType(Int8x16); -function testSwizzleInt32x4() testSwizzleForType(Int32x4); -testSwizzleInt32x4(); diff --git a/js/src/jit-test/tests/SIMD/bug1296640-gc-args.js b/js/src/jit-test/tests/SIMD/bug1296640-gc-args.js deleted file mode 100644 index 4dbe954106..0000000000 --- a/js/src/jit-test/tests/SIMD/bug1296640-gc-args.js +++ /dev/null @@ -1,9 +0,0 @@ -if (typeof gczeal === 'undefined' || typeof SIMD === 'undefined') { - quit(); -} - -gczeal(9, 2); -var Int8x16 = SIMD.Int8x16; -var v = Int8x16(); -var good = { valueOf: () => 21 }; -Int8x16.shiftLeftByScalar(v, good); diff --git a/js/src/jit-test/tests/SIMD/bug1303780-gc-args.js b/js/src/jit-test/tests/SIMD/bug1303780-gc-args.js deleted file mode 100644 index a894d532ef..0000000000 --- a/js/src/jit-test/tests/SIMD/bug1303780-gc-args.js +++ /dev/null @@ -1,12 +0,0 @@ -if (typeof gczeal === 'undefined' || typeof SIMD === 'undefined') { - quit(); -} - -gczeal(14,2); -var Float32x4 = SIMD.Float32x4; -function test() { - var v = Float32x4(1,2,3,4); - var good = {valueOf: () => 42}; - Float32x4.replaceLane(v, 0, good); -} -test(); diff --git a/js/src/jit-test/tests/SIMD/bug953108.js b/js/src/jit-test/tests/SIMD/bug953108.js deleted file mode 100644 index a8ae80e170..0000000000 --- a/js/src/jit-test/tests/SIMD/bug953108.js +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - */ - -if (!this.hasOwnProperty("TypedObject") || !this.hasOwnProperty("SIMD")) - quit(); - -var Float32x4 = SIMD.Float32x4; -Float32x4.array(1); diff --git a/js/src/jit-test/tests/SIMD/check.js b/js/src/jit-test/tests/SIMD/check.js deleted file mode 100644 index bef0b6c688..0000000000 --- a/js/src/jit-test/tests/SIMD/check.js +++ /dev/null @@ -1,25 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 50); - -function f() { - var f1 = SIMD.Float32x4(1, 2, 3, 4); - var i1 = SIMD.Int32x4(1, 2, -3, 4); - var b1 = SIMD.Bool32x4(true, true, false, true); - var i = 0; - try { - for (; i < 150; i++) { - if (i > 148) - i1 = f1; - assertEqVec(SIMD.Int32x4.check(i1), i1); - assertEqVec(SIMD.Float32x4.check(f1), f1); - assertEqVec(SIMD.Bool32x4.check(b1), b1); - } - } catch (ex) { - assertEq(i, 149); - assertEq(ex instanceof TypeError, true); - } -} - -f(); - diff --git a/js/src/jit-test/tests/SIMD/compare.js b/js/src/jit-test/tests/SIMD/compare.js deleted file mode 100644 index 21dca20cd8..0000000000 --- a/js/src/jit-test/tests/SIMD/compare.js +++ /dev/null @@ -1,39 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 50); - -function f() { - var f1 = SIMD.Float32x4(1, 2, 3, 4); - var f2 = SIMD.Float32x4(NaN, Infinity, 3.14, -0); - - var i1 = SIMD.Int32x4(1, 2, -3, 4); - var i2 = SIMD.Int32x4(1, -2, 3, 0); - - var u1 = SIMD.Uint32x4(1, 2, -3, 4); - var u2 = SIMD.Uint32x4(1, -2, 3, 0x80000000); - - for (var i = 0; i < 150; i++) { - assertEqX4(SIMD.Int32x4.lessThan(i1, i2), [false, false, true, false]); - assertEqX4(SIMD.Int32x4.lessThanOrEqual(i1, i2), [true, false, true, false]); - assertEqX4(SIMD.Int32x4.equal(i1, i2), [true, false, false, false]); - assertEqX4(SIMD.Int32x4.notEqual(i1, i2), [false, true, true, true]); - assertEqX4(SIMD.Int32x4.greaterThan(i1, i2), [false, true, false, true]); - assertEqX4(SIMD.Int32x4.greaterThanOrEqual(i1, i2), [true, true, false, true]); - - assertEqX4(SIMD.Uint32x4.lessThan(u1, u2), [false, true, false, true]); - assertEqX4(SIMD.Uint32x4.lessThanOrEqual(u1, u2), [true, true, false, true]); - assertEqX4(SIMD.Uint32x4.equal(u1, u2), [true, false, false, false]); - assertEqX4(SIMD.Uint32x4.notEqual(u1, u2), [false, true, true, true]); - assertEqX4(SIMD.Uint32x4.greaterThan(u1, u2), [false, false, true, false]); - assertEqX4(SIMD.Uint32x4.greaterThanOrEqual(u1, u2), [true, false, true, false]); - - assertEqX4(SIMD.Float32x4.lessThan(f1, f2), [false, true, true, false]); - assertEqX4(SIMD.Float32x4.lessThanOrEqual(f1, f2), [false, true, true, false]); - assertEqX4(SIMD.Float32x4.equal(f1, f2), [false, false, false, false]); - assertEqX4(SIMD.Float32x4.notEqual(f1, f2), [true, true, true, true]); - assertEqX4(SIMD.Float32x4.greaterThan(f1, f2), [false, false, false, true]); - assertEqX4(SIMD.Float32x4.greaterThanOrEqual(f1, f2), [false, false, false, true]); - } -} - -f(); diff --git a/js/src/jit-test/tests/SIMD/complex-4.js b/js/src/jit-test/tests/SIMD/complex-4.js deleted file mode 100644 index ca5e8b0f67..0000000000 --- a/js/src/jit-test/tests/SIMD/complex-4.js +++ /dev/null @@ -1,70 +0,0 @@ -load(libdir + 'simd.js'); - -if (typeof SIMD === "undefined") - quit(); - -setJitCompilerOption("baseline.warmup.trigger", 10); -setJitCompilerOption("ion.warmup.trigger", 90); -var max = 100; // Make have the warm-up counter high enough to - // consider inlining functions. - -var f4 = SIMD.Int32x4; // :TODO: Support Float32x4 arith. -var f4add = f4.add; -var f4sub = f4.sub; -var f4mul = f4.mul; - -function c4mul(z1, z2) { - var { re: re1, im: im1 } = z1; - var { re: re2, im: im2 } = z2; - var rere = f4mul(re1, re2); - var reim = f4mul(re1, im2); - var imre = f4mul(im1, re2); - var imim = f4mul(im1, im2); - return { re: f4sub(rere, imim), im: f4add(reim, imre) }; -} - -function c4inv(z) { - var { re: re, im: im } = z; - var minus = f4(-1, -1, -1, -1); - return { re: re, im: f4mul(im, minus) }; -} - -function c4inv_inplace(z) { - var res = c4inv(z); - z.re = res.re; - z.im = res.im; -} - -function c4norm(z) { - var { re: re, im: im } = c4mul(z, c4inv(z)); - return re; -} - -function c4scale(z, s) { - var { re: re, im: im } = z; - var f4s = f4(s, s, s, s); - return { re: f4mul(re, f4s), im: f4mul(im, f4s) }; -} - -var rotate90 = { re: f4(0, 0, 0, 0), im: f4(1, 1, 1, 1) }; -var cardinals = { re: f4(1, 0, -1, 0), im: f4(0, 1, 0, -1) }; - -function test(dots) { - for (var j = 0; j < 4; j++) { - dots = c4mul(rotate90, dots); - if (j % 2 == 0) // Magic ! - c4inv_inplace(dots); - dots = c4scale(dots, 2); - } - return dots; -} - -assertEqX4(c4norm(cardinals), simdToArray(f4.splat(1))); -var cardinals16 = c4scale(cardinals, 16); - -for (var i = 0; i < max; i++) { - var res = test(cardinals); - assertEqX4(c4norm(res), simdToArray(f4.splat(16 * 16))); - assertEqX4(res.re, simdToArray(cardinals16.re)); - assertEqX4(res.im, simdToArray(cardinals16.im)); -} diff --git a/js/src/jit-test/tests/SIMD/convert.js b/js/src/jit-test/tests/SIMD/convert.js deleted file mode 100644 index b27a041e7f..0000000000 --- a/js/src/jit-test/tests/SIMD/convert.js +++ /dev/null @@ -1,68 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 30); - -var cast = (function() { - var i32 = new Int32Array(1); - var f32 = new Float32Array(i32.buffer); - return { - fromInt32Bits(x) { - i32[0] = x; - return f32[0]; - }, - - fromFloat32Bits(x) { - f32[0] = x; - return i32[0]; - } - } -})(); - -function f() { - // No bailout here. - var f4 = SIMD.Float32x4(1, 2, 3, 4); - var i4 = SIMD.Int32x4(1, 2, 3, 4); - var BitOrZero = (x) => x | 0; - for (var i = 0; i < 150; i++) { - assertEqX4(SIMD.Float32x4.fromInt32x4(i4), unaryX4(BitOrZero, f4, Math.fround)); - assertEqX4(SIMD.Float32x4.fromInt32x4Bits(i4), unaryX4(cast.fromInt32Bits, f4, Math.fround)); - assertEqX4(SIMD.Int32x4.fromFloat32x4(f4), unaryX4(Math.fround, i4, BitOrZero)); - assertEqX4(SIMD.Int32x4.fromFloat32x4Bits(f4), unaryX4(cast.fromFloat32Bits, i4, BitOrZero)); - } -} - -function uglyDuckling(val) { - // We bail out when i == 149 because the conversion will return - // 0x80000000 and the input actually wasn't in bounds. - val = Math.fround(val); - for (var i = 0; i < 150; i++) { - var caught = false; - try { - var v = SIMD.Float32x4(i < 149 ? 0 : val, 0, 0, 0) - SIMD.Int32x4.fromFloat32x4(v); - } catch(e) { - assertEq(e instanceof RangeError, true); - assertEq(i, 149); - caught = true; - } - assertEq(i < 149 || caught, true); - } -} - -function dontBail() { - // On x86, the conversion will return 0x80000000, which will imply that we - // check the input values. However, we shouldn't bail out in this case. - for (var i = 0; i < 150; i++) { - var v = SIMD.Float32x4(i < 149 ? 0 : -Math.pow(2, 31), 0, 0, 0) - SIMD.Int32x4.fromFloat32x4(v); - } -} - -f(); - -dontBail(); -dontBail(); - -uglyDuckling(Math.pow(2, 31)); -uglyDuckling(NaN); -uglyDuckling(-Math.pow(2, 32)); diff --git a/js/src/jit-test/tests/SIMD/float32x4-binary-arith.js b/js/src/jit-test/tests/SIMD/float32x4-binary-arith.js deleted file mode 100644 index 63e9215d9f..0000000000 --- a/js/src/jit-test/tests/SIMD/float32x4-binary-arith.js +++ /dev/null @@ -1,33 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 50); - -function maxNum(x, y) { - if (x != x) - return y; - if (y != y) - return x; - return Math.max(x, y); -} - -function minNum(x, y) { - if (x != x) - return y; - if (y != y) - return x; - return Math.min(x, y); -} - -function f() { - var f1 = SIMD.Float32x4(1, 2, 3, 4); - var f2 = SIMD.Float32x4(4, 3, 2, 1); - for (var i = 0; i < 150; i++) { - assertEqX4(SIMD.Float32x4.div(f1, f2), binaryX((x, y) => x / y, f1, f2)); - assertEqX4(SIMD.Float32x4.min(f1, f2), binaryX(Math.min, f1, f2)); - assertEqX4(SIMD.Float32x4.max(f1, f2), binaryX(Math.max, f1, f2)); - assertEqX4(SIMD.Float32x4.minNum(f1, f2), binaryX(minNum, f1, f2)); - assertEqX4(SIMD.Float32x4.maxNum(f1, f2), binaryX(maxNum, f1, f2)); - } -} - -f(); diff --git a/js/src/jit-test/tests/SIMD/getters.js b/js/src/jit-test/tests/SIMD/getters.js deleted file mode 100644 index 5a895bbe2f..0000000000 --- a/js/src/jit-test/tests/SIMD/getters.js +++ /dev/null @@ -1,48 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 50); - -function f() { - var i4 = SIMD.Int32x4(1, -2, 3, -4); - var u4 = SIMD.Uint32x4(1, -2, 3, 0x88000000); - var b4 = SIMD.Bool32x4(true, true, false, true); - - - var bt4 = SIMD.Bool32x4(true, true, true, true); - var bf4 = SIMD.Bool32x4(false, false, false, false); - - var v = Math.fround(13.37); - var f4 = SIMD.Float32x4(13.37, NaN, Infinity, -0); - - for (var i = 0; i < 150; i++) { - assertEq(SIMD.Int32x4.extractLane(i4, 0), 1); - assertEq(SIMD.Int32x4.extractLane(i4, 1), -2); - assertEq(SIMD.Int32x4.extractLane(i4, 2), 3); - assertEq(SIMD.Int32x4.extractLane(i4, 3), -4); - - assertEq(SIMD.Uint32x4.extractLane(u4, 0), 1); - assertEq(SIMD.Uint32x4.extractLane(u4, 1), -2 >>> 0); - assertEq(SIMD.Uint32x4.extractLane(u4, 2), 3); - assertEq(SIMD.Uint32x4.extractLane(u4, 3), 0x88000000); - - assertEq(SIMD.Float32x4.extractLane(f4, 0), v); - assertEq(SIMD.Float32x4.extractLane(f4, 1), NaN); - assertEq(SIMD.Float32x4.extractLane(f4, 2), Infinity); - assertEq(SIMD.Float32x4.extractLane(f4, 3), -0); - - assertEq(SIMD.Bool32x4.extractLane(b4, 0), true); - assertEq(SIMD.Bool32x4.extractLane(b4, 1), true); - assertEq(SIMD.Bool32x4.extractLane(b4, 2), false); - assertEq(SIMD.Bool32x4.extractLane(b4, 3), true); - - assertEq(SIMD.Bool32x4.anyTrue(b4), true); - assertEq(SIMD.Bool32x4.allTrue(b4), false); - - assertEq(SIMD.Bool32x4.anyTrue(bt4), true); - assertEq(SIMD.Bool32x4.allTrue(bt4), true); - assertEq(SIMD.Bool32x4.anyTrue(bf4), false); - assertEq(SIMD.Bool32x4.allTrue(bf4), false); - } -} - -f(); diff --git a/js/src/jit-test/tests/SIMD/inline-missing-arguments.js b/js/src/jit-test/tests/SIMD/inline-missing-arguments.js deleted file mode 100644 index 5ef91d072a..0000000000 --- a/js/src/jit-test/tests/SIMD/inline-missing-arguments.js +++ /dev/null @@ -1,81 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 50); - -function test(i) { - assertEqX4(SIMD.Int32x4(), [0, 0, 0, 0]); - assertEqX4(SIMD.Int32x4(i), [i, 0, 0, 0]); - assertEqX4(SIMD.Int32x4(i, 1), [i, 1, 0, 0]); - assertEqX4(SIMD.Int32x4(i, 1, 2), [i, 1, 2, 0]); - assertEqX4(SIMD.Int32x4(i, 1, 2, 3), [i, 1, 2, 3]); - assertEqX4(SIMD.Int32x4(i, 1, 2, 3, 4), [i, 1, 2, 3]); - - assertEqVecArr(SIMD.Int16x8(), [0, 0, 0, 0, 0, 0, 0, 0]); - assertEqVecArr(SIMD.Int16x8(i), [i, 0, 0, 0, 0, 0, 0, 0]); - assertEqVecArr(SIMD.Int16x8(i, 1), [i, 1, 0, 0, 0, 0, 0, 0]); - assertEqVecArr(SIMD.Int16x8(i, 1, 2), [i, 1, 2, 0, 0, 0, 0, 0]); - assertEqVecArr(SIMD.Int16x8(i, 1, 2, 3), [i, 1, 2, 3, 0, 0, 0, 0]); - assertEqVecArr(SIMD.Int16x8(i, 1, 2, 3, 4), [i, 1, 2, 3, 4, 0, 0, 0]); - assertEqVecArr(SIMD.Int16x8(i, 1, 2, 3, 4, 5, 6), - [i, 1, 2, 3, 4, 5, 6, 0]); - j = i & 32 - assertEqVecArr(SIMD.Int8x16(), [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - assertEqVecArr(SIMD.Int8x16(j), [j, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - assertEqVecArr(SIMD.Int8x16(j, 1), [j, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - assertEqVecArr(SIMD.Int8x16(j, 1, 2), [j, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - assertEqVecArr(SIMD.Int8x16(j, 1, 2, 3), [j, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - assertEqVecArr(SIMD.Int8x16(j, 1, 2, 3, 4), [j, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - assertEqVecArr(SIMD.Int8x16(j, 1, 2, 3, 4, 5, 6), - [j, 1, 2, 3, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - assertEqVecArr(SIMD.Int8x16(j, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), - [j, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 0]); - - assertEqX4(SIMD.Float32x4(), [NaN, NaN, NaN, NaN]); - assertEqX4(SIMD.Float32x4(i), [i, NaN, NaN, NaN]); - assertEqX4(SIMD.Float32x4(i, 1), [i, 1, NaN, NaN]); - assertEqX4(SIMD.Float32x4(i, 1, 2), [i, 1, 2, NaN]); - assertEqX4(SIMD.Float32x4(i, 1, 2, 3), [i, 1, 2, 3 ]); - assertEqX4(SIMD.Float32x4(i, 1, 2, 3, 4), [i, 1, 2, 3 ]); - - var b = i % 2 > 0 ; - assertEqX4(SIMD.Bool32x4(), [false, false, false, false]); - assertEqX4(SIMD.Bool32x4(b), [b, false, false, false]); - assertEqX4(SIMD.Bool32x4(b, true), [b, true, false, false]); - assertEqX4(SIMD.Bool32x4(b, false, true), [b, false, true, false]); - assertEqX4(SIMD.Bool32x4(b, false, true, true), [b, false, true, true ]); - assertEqX4(SIMD.Bool32x4(b, false, true, true, true), [b, false, true, true ]); - - assertEqVecArr(SIMD.Bool16x8(), - [false, false, false, false, false, false, false, false]); - assertEqVecArr(SIMD.Bool16x8(b), - [b, false, false, false, false, false, false, false]); - assertEqVecArr(SIMD.Bool16x8(b, true), - [b, true, false, false, false, false, false, false]); - assertEqVecArr(SIMD.Bool16x8(b, false, true), - [b, false, true, false, false, false, false, false]); - assertEqVecArr(SIMD.Bool16x8(b, false, true, true), - [b, false, true, true, false, false, false, false]); - assertEqVecArr(SIMD.Bool16x8(b, false, true, true, true), - [b, false, true, true, true, false, false, false]); - assertEqVecArr(SIMD.Bool16x8(b, false, true, true, true, true), - [b, false, true, true, true, true, false, false]); - - assertEqVecArr(SIMD.Bool8x16(), - [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]); - assertEqVecArr(SIMD.Bool8x16(b), - [b, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]); - assertEqVecArr(SIMD.Bool8x16(b, true), - [b, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false]); - assertEqVecArr(SIMD.Bool8x16(b, false, true), - [b, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false]); - assertEqVecArr(SIMD.Bool8x16(b, false, true, true), - [b, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false]); - assertEqVecArr(SIMD.Bool8x16(b, false, true, true, true), - [b, false, true, true, true, false, false, false, false, false, false, false, false, false, false, false]); - assertEqVecArr(SIMD.Bool8x16(b, false, true, true, true, true, false, true, true, true), - [b, false, true, true, true, true, false, true, true, true, false, false, false, false, false, false]); -} - -for(var i=0; i<300; i++) { - test(i); -} diff --git a/js/src/jit-test/tests/SIMD/load.js b/js/src/jit-test/tests/SIMD/load.js deleted file mode 100644 index 5cdb8cce63..0000000000 --- a/js/src/jit-test/tests/SIMD/load.js +++ /dev/null @@ -1,123 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 40); - -function f() { - var f32 = new Float32Array(16); - for (var i = 0; i < 16; i++) - f32[i] = i + 1; - - var f64 = new Float64Array(f32.buffer); - var i32 = new Int32Array(f32.buffer); - var u32 = new Uint32Array(f32.buffer); - var i16 = new Int16Array(f32.buffer); - var u16 = new Uint16Array(f32.buffer); - var i8 = new Int8Array(f32.buffer); - var u8 = new Uint8Array(f32.buffer); - - function testLoad() { - assertEqX4(SIMD.Float32x4.load(f64, 0), [1,2,3,4]); - assertEqX4(SIMD.Float32x4.load(f32, 1), [2,3,4,5]); - assertEqX4(SIMD.Float32x4.load(i32, 2), [3,4,5,6]); - assertEqX4(SIMD.Float32x4.load(i16, 3 << 1), [4,5,6,7]); - assertEqX4(SIMD.Float32x4.load(u16, 4 << 1), [5,6,7,8]); - assertEqX4(SIMD.Float32x4.load(i8 , 5 << 2), [6,7,8,9]); - assertEqX4(SIMD.Float32x4.load(u8 , 6 << 2), [7,8,9,10]); - - assertEqX4(SIMD.Float32x4.load(f64, (16 >> 1) - (4 >> 1)), [13,14,15,16]); - assertEqX4(SIMD.Float32x4.load(f32, 16 - 4), [13,14,15,16]); - assertEqX4(SIMD.Float32x4.load(i32, 16 - 4), [13,14,15,16]); - assertEqX4(SIMD.Float32x4.load(i16, (16 << 1) - (4 << 1)), [13,14,15,16]); - assertEqX4(SIMD.Float32x4.load(u16, (16 << 1) - (4 << 1)), [13,14,15,16]); - assertEqX4(SIMD.Float32x4.load(i8, (16 << 2) - (4 << 2)), [13,14,15,16]); - assertEqX4(SIMD.Float32x4.load(u8, (16 << 2) - (4 << 2)), [13,14,15,16]); - } - - function testLoad1() { - assertEqX4(SIMD.Float32x4.load1(f64, 0), [1,0,0,0]); - assertEqX4(SIMD.Float32x4.load1(f32, 1), [2,0,0,0]); - assertEqX4(SIMD.Float32x4.load1(i32, 2), [3,0,0,0]); - assertEqX4(SIMD.Float32x4.load1(i16, 3 << 1), [4,0,0,0]); - assertEqX4(SIMD.Float32x4.load1(u16, 4 << 1), [5,0,0,0]); - assertEqX4(SIMD.Float32x4.load1(i8 , 5 << 2), [6,0,0,0]); - assertEqX4(SIMD.Float32x4.load1(u8 , 6 << 2), [7,0,0,0]); - - assertEqX4(SIMD.Float32x4.load1(f64, (16 >> 1) - (4 >> 1)), [13,0,0,0]); - assertEqX4(SIMD.Float32x4.load1(f32, 16 - 4), [13,0,0,0]); - assertEqX4(SIMD.Float32x4.load1(i32, 16 - 4), [13,0,0,0]); - assertEqX4(SIMD.Float32x4.load1(i16, (16 << 1) - (4 << 1)), [13,0,0,0]); - assertEqX4(SIMD.Float32x4.load1(u16, (16 << 1) - (4 << 1)), [13,0,0,0]); - assertEqX4(SIMD.Float32x4.load1(i8, (16 << 2) - (4 << 2)), [13,0,0,0]); - assertEqX4(SIMD.Float32x4.load1(u8, (16 << 2) - (4 << 2)), [13,0,0,0]); - } - - function testLoad2() { - assertEqX4(SIMD.Float32x4.load2(f64, 0), [1,2,0,0]); - assertEqX4(SIMD.Float32x4.load2(f32, 1), [2,3,0,0]); - assertEqX4(SIMD.Float32x4.load2(i32, 2), [3,4,0,0]); - assertEqX4(SIMD.Float32x4.load2(i16, 3 << 1), [4,5,0,0]); - assertEqX4(SIMD.Float32x4.load2(u16, 4 << 1), [5,6,0,0]); - assertEqX4(SIMD.Float32x4.load2(i8 , 5 << 2), [6,7,0,0]); - assertEqX4(SIMD.Float32x4.load2(u8 , 6 << 2), [7,8,0,0]); - - assertEqX4(SIMD.Float32x4.load2(f64, (16 >> 1) - (4 >> 1)), [13,14,0,0]); - assertEqX4(SIMD.Float32x4.load2(f32, 16 - 4), [13,14,0,0]); - assertEqX4(SIMD.Float32x4.load2(i32, 16 - 4), [13,14,0,0]); - assertEqX4(SIMD.Float32x4.load2(i16, (16 << 1) - (4 << 1)), [13,14,0,0]); - assertEqX4(SIMD.Float32x4.load2(u16, (16 << 1) - (4 << 1)), [13,14,0,0]); - assertEqX4(SIMD.Float32x4.load2(i8, (16 << 2) - (4 << 2)), [13,14,0,0]); - assertEqX4(SIMD.Float32x4.load2(u8, (16 << 2) - (4 << 2)), [13,14,0,0]); - } - - function testLoad3() { - assertEqX4(SIMD.Float32x4.load3(f64, 0), [1,2,3,0]); - assertEqX4(SIMD.Float32x4.load3(f32, 1), [2,3,4,0]); - assertEqX4(SIMD.Float32x4.load3(i32, 2), [3,4,5,0]); - assertEqX4(SIMD.Float32x4.load3(i16, 3 << 1), [4,5,6,0]); - assertEqX4(SIMD.Float32x4.load3(u16, 4 << 1), [5,6,7,0]); - assertEqX4(SIMD.Float32x4.load3(i8 , 5 << 2), [6,7,8,0]); - assertEqX4(SIMD.Float32x4.load3(u8 , 6 << 2), [7,8,9,0]); - - assertEqX4(SIMD.Float32x4.load3(f64, (16 >> 1) - (4 >> 1)), [13,14,15,0]); - assertEqX4(SIMD.Float32x4.load3(f32, 16 - 4), [13,14,15,0]); - assertEqX4(SIMD.Float32x4.load3(i32, 16 - 4), [13,14,15,0]); - assertEqX4(SIMD.Float32x4.load3(i16, (16 << 1) - (4 << 1)), [13,14,15,0]); - assertEqX4(SIMD.Float32x4.load3(u16, (16 << 1) - (4 << 1)), [13,14,15,0]); - assertEqX4(SIMD.Float32x4.load3(i8, (16 << 2) - (4 << 2)), [13,14,15,0]); - assertEqX4(SIMD.Float32x4.load3(u8, (16 << 2) - (4 << 2)), [13,14,15,0]); - } - - for (var i = 0; i < 150; i++) { - testLoad(); - testLoad1(); - testLoad2(); - testLoad3(); - } -} - -f(); - -function testBailout(uglyDuckling) { - var f32 = new Float32Array(16); - for (var i = 0; i < 16; i++) - f32[i] = i + 1; - - var i8 = new Int8Array(f32.buffer); - - for (var i = 0; i < 150; i++) { - var caught = false; - try { - SIMD.Float32x4.load(i8, (i < 149) ? 0 : uglyDuckling); - } catch (e) { - print(e); - assertEq(e instanceof RangeError, true); - caught = true; - } - assertEq(i < 149 || caught, true); - } -} - -print('Testing range checks...'); -testBailout(-1); -testBailout(-15); -testBailout(12 * 4 + 1); diff --git a/js/src/jit-test/tests/SIMD/nursery-overflow.js b/js/src/jit-test/tests/SIMD/nursery-overflow.js deleted file mode 100644 index 5aecff908b..0000000000 --- a/js/src/jit-test/tests/SIMD/nursery-overflow.js +++ /dev/null @@ -1,29 +0,0 @@ -load(libdir + 'simd.js'); - -if (typeof SIMD === "undefined") - quit(); - -setJitCompilerOption("baseline.warmup.trigger", 10); -setJitCompilerOption("ion.warmup.trigger", 30); - -var i4 = SIMD.Int32x4; -var i4sub = SIMD.Int32x4.sub; - -function simdbox(i) { - return i4(i, i, i, i); -} - -function test() { - var arr = []; - - // overflow the nursery with live SIMD objects. - for (var i = 0; i < 100000; i++) { - arr.push(simdbox(i)); - } - - return arr; -} - -var arr = test(); -for (var i = 0; i < arr.length; i++) - assertEqX4(arr[i], [i, i, i, i]); diff --git a/js/src/jit-test/tests/SIMD/recover.js b/js/src/jit-test/tests/SIMD/recover.js deleted file mode 100644 index a8fb0002ed..0000000000 --- a/js/src/jit-test/tests/SIMD/recover.js +++ /dev/null @@ -1,70 +0,0 @@ -load(libdir + 'simd.js'); - -if (!this.hasOwnProperty("SIMD")) - quit(); - -// This test case ensure that if we are able to optimize SIMD, then we can use -// recover instructions to get rid of the allocations. So, there is no value -// (and the test case would fail) if we are not able to inline SIMD -// constructors. -if (!isSimdAvailable()) - quit(); - -setJitCompilerOption("baseline.warmup.trigger", 10); -setJitCompilerOption("ion.warmup.trigger", 20); - -// This function is used to cause an invalidation after having removed a branch -// after DCE. This is made to check if we correctly recover an array -// allocation. -var uceFault = function (i) { - if (i > 98) - uceFault = function (i) { return true; }; - return false; -}; - -// Check that we can correctly recover a boxed value. -var uceFault_simdBox_i4 = eval(uneval(uceFault).replace('uceFault', 'uceFault_simdBox_i4')); -function simdBox_i4(i) { - var a = SIMD.Int32x4(i, i, i, i); - if (uceFault_simdBox_i4(i) || uceFault_simdBox_i4(i)) - assertEqX4(a, [i, i, i, i]); - assertRecoveredOnBailout(a, true); - return 0; -} - -var uceFault_simdBox_u4 = eval(uneval(uceFault).replace('uceFault', 'uceFault_simdBox_u4')); -function simdBox_u4(i) { - var a = SIMD.Uint32x4(i, 98 - i, i + 0x7ffffff0, i + 0xffffff00); - if (uceFault_simdBox_u4(i) || uceFault_simdBox_u4(i)) - assertEqX4(a, [i, 98 - i, i + 0x7ffffff0, i + 0xffffff00].map(x => x >>> 0)); - assertRecoveredOnBailout(a, true); - return 0; -} - -var uceFault_simdBox_f4 = eval(uneval(uceFault).replace('uceFault', 'uceFault_simdBox_f4')); -function simdBox_f4(i) { - var a = SIMD.Float32x4(i, i + 0.1, i + 0.2, i + 0.3); - if (uceFault_simdBox_f4(i) || uceFault_simdBox_f4(i)) - assertEqX4(a, [i, i + 0.1, i + 0.2, i + 0.3].map(Math.fround)); - assertRecoveredOnBailout(a, true); - return 0; -} - -var uceFault_simdBox_b4 = eval(uneval(uceFault).replace('uceFault', 'uceFault_simdBox_b4')); -function simdBox_b4(i) { - var val1 = i%2 === 0, - val2 = !val1; - - var a = SIMD.Bool32x4(val1, val2, val1, val2); - if (uceFault_simdBox_b4(i) || uceFault_simdBox_b4(i)) - assertEqX4(a, [val1, val2, val1, val2]); - assertRecoveredOnBailout(a, true); - return 0; -} - -for (var i = 0; i < 100; i++) { - simdBox_i4(i); - simdBox_u4(i); - simdBox_f4(i); - simdBox_b4(i); -} diff --git a/js/src/jit-test/tests/SIMD/replacelane.js b/js/src/jit-test/tests/SIMD/replacelane.js deleted file mode 100644 index c6b37ad5ab..0000000000 --- a/js/src/jit-test/tests/SIMD/replacelane.js +++ /dev/null @@ -1,181 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 50); - -function f() { - var f4 = SIMD.Float32x4(1, 2, 3, 4); - var i4 = SIMD.Int32x4(1, 2, 3, 4); - var b4 = SIMD.Bool32x4(true, false, true, false); - - for (var i = 0; i < 150; i++) { - assertEqX4(SIMD.Int32x4.replaceLane(i4, 0, 42), [42, 2, 3, 4]); - assertEqX4(SIMD.Int32x4.replaceLane(i4, 1, 42), [1, 42, 3, 4]); - assertEqX4(SIMD.Int32x4.replaceLane(i4, 2, 42), [1, 2, 42, 4]); - assertEqX4(SIMD.Int32x4.replaceLane(i4, 3, 42), [1, 2, 3, 42]); - - assertEqX4(SIMD.Float32x4.replaceLane(f4, 0, 42), [42, 2, 3, 4]); - assertEqX4(SIMD.Float32x4.replaceLane(f4, 1, 42), [1, 42, 3, 4]); - assertEqX4(SIMD.Float32x4.replaceLane(f4, 2, 42), [1, 2, 42, 4]); - assertEqX4(SIMD.Float32x4.replaceLane(f4, 3, 42), [1, 2, 3, 42]); - - assertEqX4(SIMD.Bool32x4.replaceLane(b4, 0, false), [false, false, true, false]); - assertEqX4(SIMD.Bool32x4.replaceLane(b4, 1, true), [true, true, true, false]); - assertEqX4(SIMD.Bool32x4.replaceLane(b4, 2, false), [true, false, false, false]); - assertEqX4(SIMD.Bool32x4.replaceLane(b4, 3, true), [true, false, true, true]); - } -} - -f(); - -function e() { - var f4 = SIMD.Float32x4(1, 2, 3, 4); - var i4 = SIMD.Int32x4(1, 2, 3, 4); - var b4 = SIMD.Bool32x4(true, false, true, false); - - for (let i = 0; i < 150; i++) { - let caught = false; - try { - let x = SIMD.Int32x4.replaceLane(i < 149 ? i4 : f4, 0, 42); - } catch(e) { - assertEq(e instanceof TypeError, true); - assertEq(i, 149); - caught = true; - } - assertEq(i < 149 || caught, true); - } - - for (let i = 0; i < 150; i++) { - let caught = false; - try { - let x = SIMD.Int32x4.replaceLane(i < 149 ? i4 : b4, 0, 42); - } catch(e) { - assertEq(e instanceof TypeError, true); - assertEq(i, 149); - caught = true; - } - assertEq(i < 149 || caught, true); - } - - for (let i = 0; i < 150; i++) { - let caught = false; - try { - let x = SIMD.Int32x4.replaceLane(i4, i < 149 ? 0 : 4, 42); - } catch(e) { - assertEq(e instanceof RangeError, true); - assertEq(i, 149); - caught = true; - } - assertEq(i < 149 || caught, true); - } - - for (let i = 0; i < 150; i++) { - let caught = false; - try { - let x = SIMD.Int32x4.replaceLane(i4, i < 149 ? 0 : 1.1, 42); - } catch(e) { - assertEq(e instanceof RangeError, true); - assertEq(i, 149); - caught = true; - } - assertEq(i < 149 || caught, true); - } - - for (let i = 0; i < 150; i++) { - let caught = false; - try { - let x = SIMD.Float32x4.replaceLane(i < 149 ? f4 : i4, 0, 42); - } catch(e) { - assertEq(e instanceof TypeError, true); - assertEq(i, 149); - caught = true; - } - assertEq(i < 149 || caught, true); - } - - for (let i = 0; i < 150; i++) { - let caught = false; - try { - let x = SIMD.Float32x4.replaceLane(i < 149 ? f4 : b4, 0, 42); - } catch(e) { - assertEq(e instanceof TypeError, true); - assertEq(i, 149); - caught = true; - } - assertEq(i < 149 || caught, true); - } - - for (let i = 0; i < 150; i++) { - let caught = false; - try { - let x = SIMD.Float32x4.replaceLane(f4, i < 149 ? 0 : 4, 42); - } catch(e) { - assertEq(e instanceof RangeError, true); - assertEq(i, 149); - caught = true; - } - assertEq(i < 149 || caught, true); - } - - for (let i = 0; i < 150; i++) { - let caught = false; - try { - let x = SIMD.Float32x4.replaceLane(f4, i < 149 ? 0 : 1.1, 42); - } catch(e) { - assertEq(e instanceof RangeError, true); - assertEq(i, 149); - caught = true; - } - assertEq(i < 149 || caught, true); - } - - for (let i = 0; i < 150; i++) { - let caught = false; - try { - let x = SIMD.Bool32x4.replaceLane(i < 149 ? b4 : i4, 0, true); - } catch(e) { - assertEq(e instanceof TypeError, true); - assertEq(i, 149); - caught = true; - } - assertEq(i < 149 || caught, true); - } - - for (let i = 0; i < 150; i++) { - let caught = false; - try { - let x = SIMD.Bool32x4.replaceLane(i < 149 ? b4 : f4, 0, true); - } catch(e) { - assertEq(e instanceof TypeError, true); - assertEq(i, 149); - caught = true; - } - assertEq(i < 149 || caught, true); - } - - for (let i = 0; i < 150; i++) { - let caught = false; - try { - let x = SIMD.Bool32x4.replaceLane(b4, i < 149 ? 0 : 4, true); - } catch(e) { - assertEq(e instanceof RangeError, true); - assertEq(i, 149); - caught = true; - } - assertEq(i < 149 || caught, true); - } - - for (let i = 0; i < 150; i++) { - let caught = false; - try { - let x = SIMD.Bool32x4.replaceLane(b4, i < 149 ? 0 : 1.1, true); - } catch(e) { - assertEq(e instanceof RangeError, true); - assertEq(i, 149); - caught = true; - } - assertEq(i < 149 || caught, true); - } - -} - -e(); diff --git a/js/src/jit-test/tests/SIMD/saturate.js b/js/src/jit-test/tests/SIMD/saturate.js deleted file mode 100644 index a98cf7ad79..0000000000 --- a/js/src/jit-test/tests/SIMD/saturate.js +++ /dev/null @@ -1,37 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 50); - -const INT8_MIN = -128; -const INT8_MAX = 127; -const UINT8_MAX = 255; - -function sat8(x) { - if (x < INT8_MIN) return INT8_MIN; - if (x > INT8_MAX) return INT8_MAX; - return x; -} - -function usat8(x) { - if (x < 0) return 0; - if (x > UINT8_MAX) return UINT8_MAX; - return x; -} - -function f() { - var i1 = SIMD.Int8x16(1, 100, 3, 4); - var i2 = SIMD.Int8x16(4, 30, 2, 1); - - var u1 = SIMD.Uint8x16(1, 2, 3, 4); - var u2 = SIMD.Uint8x16(4, 3, 2, 1); - - for (var i = 0; i < 150; i++) { - assertEqX4(SIMD.Int8x16.addSaturate(i1, i2), binaryX((x, y) => sat8(x + y), i1, i2)); - assertEqX4(SIMD.Int8x16.subSaturate(i1, i2), binaryX((x, y) => sat8(x - y), i1, i2)); - - assertEqX4(SIMD.Uint8x16.addSaturate(u1, u2), binaryX((x, y) => usat8(x + y), u1, u2)); - assertEqX4(SIMD.Uint8x16.subSaturate(u1, u2), binaryX((x, y) => usat8(x - y), u1, u2)); - } -} - -f(); diff --git a/js/src/jit-test/tests/SIMD/select.js b/js/src/jit-test/tests/SIMD/select.js deleted file mode 100644 index 3f0d783dac..0000000000 --- a/js/src/jit-test/tests/SIMD/select.js +++ /dev/null @@ -1,35 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 50); - -function select(type, mask, ifTrue, ifFalse) { - var arr = []; - for (var i = 0; i < 4; i++) { - var selector = SIMD.Bool32x4.extractLane(mask, i); - arr.push(type.extractLane(selector ? ifTrue : ifFalse, i)); - } - return arr; -} - -function f() { - var f1 = SIMD.Float32x4(1, 2, 3, 4); - var f2 = SIMD.Float32x4(NaN, Infinity, 3.14, -0); - - var i1 = SIMD.Int32x4(2, 3, 5, 8); - var i2 = SIMD.Int32x4(13, 37, 24, 42); - - var TTFT = SIMD.Bool32x4(true, true, false, true); - var TFTF = SIMD.Bool32x4(true, false, true, false); - - var mask = SIMD.Int32x4(0xdeadbeef, 0xbaadf00d, 0x00ff1ce, 0xdeadc0de); - - for (var i = 0; i < 150; i++) { - assertEqX4(SIMD.Float32x4.select(TTFT, f1, f2), select(SIMD.Float32x4, TTFT, f1, f2)); - assertEqX4(SIMD.Float32x4.select(TFTF, f1, f2), select(SIMD.Float32x4, TFTF, f1, f2)); - - assertEqX4(SIMD.Int32x4.select(TFTF, i1, i2), select(SIMD.Int32x4, TFTF, i1, i2)); - assertEqX4(SIMD.Int32x4.select(TTFT, i1, i2), select(SIMD.Int32x4, TTFT, i1, i2)); - } -} - -f(); diff --git a/js/src/jit-test/tests/SIMD/shift.js b/js/src/jit-test/tests/SIMD/shift.js deleted file mode 100644 index 8448e52ecb..0000000000 --- a/js/src/jit-test/tests/SIMD/shift.js +++ /dev/null @@ -1,75 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 50); - -function curry(f, arg) { return f.bind(null, arg); } - -function binaryLsh(count, v) { count &= 31; return (v << count) | 0; } -function lsh(count) { return curry(binaryLsh, count); } - -function binaryRsh(count, v) { count &= 31; return (v >> count) | 0; } -function rsh(count) { return curry(binaryRsh, count); } - -function binaryUlsh(count, v) { count &= 31; return (v << count) >>> 0; } -function ulsh(count) { return curry(binaryUlsh, count); } - -function binaryUrsh(count, v) { count &= 31; return v >>> count; } -function ursh(count) { return curry(binaryUrsh, count); } - -function f() { - var v = SIMD.Int32x4(1, 2, -3, 4); - var u = SIMD.Uint32x4(1, 0x55005500, -3, 0xaa00aa00); - var a = [1, 2, -3, 4]; - var b = [1, 0x55005500, -3, 0xaa00aa00]; - - var shifts = [-2, -1, 0, 1, 31, 32, 33]; - - var r; - for (var i = 0; i < 150; i++) { - // Constant shift counts - assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, -1), a.map(lsh(-1))); - assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 0), a.map(lsh(0))); - assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 1), a.map(lsh(1))); - assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 2), a.map(lsh(2))); - assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 31), a.map(lsh(31))); - assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 32), a.map(lsh(32))); - assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 33), a.map(lsh(33))); - - assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, -1), a.map(rsh(31))); - assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 0), a.map(rsh(0))); - assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 1), a.map(rsh(1))); - assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 2), a.map(rsh(2))); - assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 31), a.map(rsh(31))); - assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 32), a.map(rsh(32))); - assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 33), a.map(rsh(33))); - - assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, -1), b.map(ulsh(-1))); - assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 0), b.map(ulsh(0))); - assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 1), b.map(ulsh(1))); - assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 2), b.map(ulsh(2))); - assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 31), b.map(ulsh(31))); - assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 32), b.map(ulsh(32))); - assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 33), b.map(ulsh(33))); - - assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, -1), b.map(ursh(-1))); - assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 0), b.map(ursh(0))); - assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 1), b.map(ursh(1))); - assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 2), b.map(ursh(2))); - assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 31), b.map(ursh(31))); - assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 32), b.map(ursh(32))); - assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 33), b.map(ursh(33))); - - // Non constant shift counts - var c = shifts[i % shifts.length]; - - assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, c), a.map(lsh(c))); - assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, c), a.map(rsh(c))); - - assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, c), b.map(ulsh(c))); - assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, c), b.map(ursh(c))); - } - return r; -} - -f(); - diff --git a/js/src/jit-test/tests/SIMD/shuffle.js b/js/src/jit-test/tests/SIMD/shuffle.js deleted file mode 100644 index 505f01131f..0000000000 --- a/js/src/jit-test/tests/SIMD/shuffle.js +++ /dev/null @@ -1,86 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 50); - -function f() { - var i1 = SIMD.Int32x4(1, 2, 3, 4); - var i2 = SIMD.Int32x4(5, 6, 7, 8); - - var leet = Math.fround(13.37); - var f1 = SIMD.Float32x4(-.5, -0, Infinity, leet); - var f2 = SIMD.Float32x4(42, .5, 23, -10); - - // computes all rotations of a given array - function *gen(arr) { - var previous = arr.slice().splice(0, 4); - var i = 4; - for (var j = 0; j < 8; j++) { - yield previous.slice(); - previous = previous.splice(1, previous.length - 1); - previous.push(arr[i]); - i = (i + 1) % arr.length; - } - } - - var compI = []; - var baseI = []; - for (var i = 0; i < 8; i++) - baseI.push(SIMD.Int32x4.extractLane(i < 4 ? i1 : i2, i % 4)); - for (var k of gen(baseI)) - compI.push(k); - - var compF = []; - var baseF = []; - for (var i = 0; i < 8; i++) - baseF.push(SIMD.Float32x4.extractLane(i < 4 ? f1 : f2, i % 4)); - for (var k of gen(baseF)) - compF.push(k); - - for (var i = 0; i < 150; i++) { - // Variable lanes - var r = SIMD.Float32x4.shuffle(f1, f2, i % 8, (i + 1) % 8, (i + 2) % 8, (i + 3) % 8); - assertEqX4(r, compF[i % 8]); - - // Constant lanes - assertEqX4(SIMD.Float32x4.shuffle(f1, f2, 3, 2, 4, 5), [leet, Infinity, 42, .5]); - - // Variable lanes - var r = SIMD.Int32x4.shuffle(i1, i2, i % 8, (i + 1) % 8, (i + 2) % 8, (i + 3) % 8); - assertEqX4(r, compI[i % 8]); - - // Constant lanes - assertEqX4(SIMD.Int32x4.shuffle(i1, i2, 3, 2, 4, 5), [4, 3, 5, 6]); - } -} - -function testBailouts(expectException, uglyDuckling) { - var i1 = SIMD.Int32x4(1, 2, 3, 4); - var i2 = SIMD.Int32x4(5, 6, 7, 8); - - for (var i = 0; i < 150; i++) { - // Test bailouts - var value = i == 149 ? uglyDuckling : 0; - var caught = false; - try { - assertEqX4(SIMD.Int32x4.shuffle(i1, i2, value, 2, 4, 5), [1, 3, 5, 6]); - } catch(e) { - print(e); - caught = true; - assertEq(i, 149); - assertEq(e instanceof TypeError || e instanceof RangeError, true); - } - if (i == 149) - assertEq(caught, expectException); - } -} - -f(); -testBailouts(true, -1); -testBailouts(true, 8); -testBailouts(true, 2.5); -testBailouts(true, undefined); -testBailouts(true, {}); -testBailouts(true, 'one'); -testBailouts(false, false); -testBailouts(false, null); -testBailouts(false, " 0.0 "); diff --git a/js/src/jit-test/tests/SIMD/splat.js b/js/src/jit-test/tests/SIMD/splat.js deleted file mode 100644 index 38eda3085e..0000000000 --- a/js/src/jit-test/tests/SIMD/splat.js +++ /dev/null @@ -1,15 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 50); - -function f() { - for (var i = 0; i < 150; i++) { - assertEqX4(SIMD.Int32x4.splat(42), [42, 42, 42, 42]); - assertEqX4(SIMD.Float32x4.splat(42), [42, 42, 42, 42]); - assertEqX4(SIMD.Bool32x4.splat(true), [true, true, true, true]); - assertEqX4(SIMD.Bool32x4.splat(false), [false, false, false, false]); - } -} - -f(); - diff --git a/js/src/jit-test/tests/SIMD/store.js b/js/src/jit-test/tests/SIMD/store.js deleted file mode 100644 index 8cfa354277..0000000000 --- a/js/src/jit-test/tests/SIMD/store.js +++ /dev/null @@ -1,143 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 40); - -function f() { - var f32 = new Float32Array(16); - for (var i = 0; i < 16; i++) - f32[i] = i + 1; - - var f64 = new Float64Array(f32.buffer); - var i32 = new Int32Array(f32.buffer); - var u32 = new Uint32Array(f32.buffer); - var i16 = new Int16Array(f32.buffer); - var u16 = new Uint16Array(f32.buffer); - var i8 = new Int8Array(f32.buffer); - var u8 = new Uint8Array(f32.buffer); - - var f4 = SIMD.Float32x4(42, 43, 44, 45); - - function check(n) { - assertEq(f32[0], 42); - assertEq(f32[1], n > 1 ? 43 : 2); - assertEq(f32[2], n > 2 ? 44 : 3); - assertEq(f32[3], n > 3 ? 45 : 4); - - f32[0] = 1; - f32[1] = 2; - f32[2] = 3; - f32[3] = 4; - } - - function testStore() { - SIMD.Float32x4.store(f64, 0, f4); - check(4); - SIMD.Float32x4.store(f32, 0, f4); - check(4); - SIMD.Float32x4.store(i32, 0, f4); - check(4); - SIMD.Float32x4.store(u32, 0, f4); - check(4); - SIMD.Float32x4.store(i16, 0, f4); - check(4); - SIMD.Float32x4.store(u16, 0, f4); - check(4); - SIMD.Float32x4.store(i8, 0, f4); - check(4); - SIMD.Float32x4.store(u8, 0, f4); - check(4); - } - - function testStore1() { - SIMD.Float32x4.store1(f64, 0, f4); - check(1); - SIMD.Float32x4.store1(f32, 0, f4); - check(1); - SIMD.Float32x4.store1(i32, 0, f4); - check(1); - SIMD.Float32x4.store1(u32, 0, f4); - check(1); - SIMD.Float32x4.store1(i16, 0, f4); - check(1); - SIMD.Float32x4.store1(u16, 0, f4); - check(1); - SIMD.Float32x4.store1(i8, 0, f4); - check(1); - SIMD.Float32x4.store1(u8, 0, f4); - check(1); - } - - function testStore2() { - SIMD.Float32x4.store2(f64, 0, f4); - check(2); - SIMD.Float32x4.store2(f32, 0, f4); - check(2); - SIMD.Float32x4.store2(i32, 0, f4); - check(2); - SIMD.Float32x4.store2(u32, 0, f4); - check(2); - SIMD.Float32x4.store2(i16, 0, f4); - check(2); - SIMD.Float32x4.store2(u16, 0, f4); - check(2); - SIMD.Float32x4.store2(i8, 0, f4); - check(2); - SIMD.Float32x4.store2(u8, 0, f4); - check(2); - } - - function testStore3() { - SIMD.Float32x4.store3(f64, 0, f4); - check(3); - SIMD.Float32x4.store3(f32, 0, f4); - check(3); - SIMD.Float32x4.store3(i32, 0, f4); - check(3); - SIMD.Float32x4.store3(u32, 0, f4); - check(3); - SIMD.Float32x4.store3(i16, 0, f4); - check(3); - SIMD.Float32x4.store3(u16, 0, f4); - check(3); - SIMD.Float32x4.store3(i8, 0, f4); - check(3); - SIMD.Float32x4.store3(u8, 0, f4); - check(3); - } - - for (var i = 0; i < 150; i++) { - testStore(); - testStore1(); - testStore2(); - testStore3(); - } -} - -f(); - -function testBailout(uglyDuckling) { - var f32 = new Float32Array(16); - for (var i = 0; i < 16; i++) - f32[i] = i + 1; - - var i8 = new Int8Array(f32.buffer); - - var f4 = SIMD.Float32x4(42, 43, 44, 45); - - for (var i = 0; i < 150; i++) { - var caught = false; - try { - SIMD.Float32x4.store(i8, (i < 149) ? 0 : (16 << 2) - (4 << 2) + 1, f4); - } catch (e) { - print(e); - assertEq(e instanceof RangeError, true); - caught = true; - } - assertEq(i < 149 || caught, true); - } -} - -print('Testing range checks...'); -testBailout(-1); -testBailout(-15); -testBailout(12 * 4 + 1); diff --git a/js/src/jit-test/tests/SIMD/swizzle.js b/js/src/jit-test/tests/SIMD/swizzle.js deleted file mode 100644 index 2fd56620be..0000000000 --- a/js/src/jit-test/tests/SIMD/swizzle.js +++ /dev/null @@ -1,104 +0,0 @@ -if (!this.hasOwnProperty("SIMD")) - quit(); - -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 50); - -function f() { - var i4 = SIMD.Int32x4(1, 2, 3, 4); - - var leet = Math.fround(13.37); - var f4 = SIMD.Float32x4(-.5, -0, Infinity, leet); - - var compI = [ - [1,2,3,4], - [2,3,4,1], - [3,4,1,2], - [4,1,2,3] - ]; - - var compF = [ - [-.5, -0, Infinity, leet], - [-0, Infinity, leet, -.5], - [Infinity, leet, -.5, -0], - [leet, -.5, -0, Infinity] - ]; - - for (var i = 0; i < 150; i++) { - // Variable lanes - var r = SIMD.Float32x4.swizzle(f4, i % 4, (i + 1) % 4, (i + 2) % 4, (i + 3) % 4); - assertEqX4(r, compF[i % 4]); - - // Constant lanes - assertEqX4(SIMD.Float32x4.swizzle(f4, 3, 2, 1, 0), [leet, Infinity, -0, -.5]); - - // Variable lanes - var r = SIMD.Int32x4.swizzle(i4, i % 4, (i + 1) % 4, (i + 2) % 4, (i + 3) % 4); - assertEqX4(r, compI[i % 4]); - - // Constant lanes - assertEqX4(SIMD.Int32x4.swizzle(i4, 3, 2, 1, 0), [4, 3, 2, 1]); - } -} - -function testBailouts(expectException, uglyDuckling) { - var i4 = SIMD.Int32x4(1, 2, 3, 4); - for (var i = 0; i < 150; i++) { - // Test bailouts - var value = i == 149 ? uglyDuckling : 0; - var caught = false; - try { - assertEqX4(SIMD.Int32x4.swizzle(i4, value, 3, 2, 0), [1, 4, 3, 1]); - } catch(e) { - print(e); - caught = true; - assertEq(i, 149); - assertEq(e instanceof TypeError || e instanceof RangeError, true); - } - if (i == 149) - assertEq(caught, expectException); - } -} - -function testInt32x4SwizzleBailout() { - // Test out-of-bounds non-constant indices. This is expected to throw. - var i4 = SIMD.Int32x4(1, 2, 3, 4); - for (var i = 0; i < 150; i++) { - assertEqX4(SIMD.Int32x4.swizzle(i4, i, 3, 2, 0), [i + 1, 4, 3, 1]); - } -} - -f(); -testBailouts(true, -1); -testBailouts(true, 4); -testBailouts(true, 2.5); -testBailouts(true, undefined); -testBailouts(true, {}); -testBailouts(true, 'one'); -testBailouts(false, false); -testBailouts(false, null); -testBailouts(false, " 0.0 "); - -try { - testInt32x4SwizzleBailout(); - throw 'not caught'; -} catch(e) { - assertEq(e instanceof RangeError, true); -} - -(function() { - var zappa = 0; - - function testBailouts() { - var i4 = SIMD.Int32x4(1, 2, 3, 4); - for (var i = 0; i < 300; i++) { - var value = i == 299 ? 2.5 : 1; - SIMD.Int32x4.swizzle(i4, value, 3, 2, 0); - zappa = i; - } - } - - try { testBailouts(); } catch (e) {} - assertEq(zappa, 298); -})(); diff --git a/js/src/jit-test/tests/SIMD/uconvert.js b/js/src/jit-test/tests/SIMD/uconvert.js deleted file mode 100644 index a45fd7af9c..0000000000 --- a/js/src/jit-test/tests/SIMD/uconvert.js +++ /dev/null @@ -1,86 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 30); - -// Testing Uint32 <-> Float32 conversions. -// These conversions deserve special attention because SSE doesn't provide -// simple conversion instructions. - -// Convert an Uint32Array to a Float32Array using scalar conversions. -function cvt_utof_scalar(u32s, f32s) { - assertEq(u32s.length, f32s.length); - for (var i = 0; i < u32s.length; i++) { - f32s[i] = u32s[i]; - } -} - -// Convert an Uint32Array to a Float32Array using simd conversions. -function cvt_utof_simd(u32s, f32s) { - assertEq(u32s.length, f32s.length); - for (var i = 0; i < u32s.length; i += 4) { - SIMD.Float32x4.store(f32s, i, SIMD.Float32x4.fromUint32x4(SIMD.Uint32x4.load(u32s, i))); - } -} - -// Convert a Float32Array to an Uint32Array using scalar conversions. -function cvt_ftou_scalar(f32s, u32s) { - assertEq(f32s.length, u32s.length); - for (var i = 0; i < f32s.length; i++) { - u32s[i] = f32s[i]; - } -} - -// Convert a Float32Array to an Uint32Array using simd conversions. -function cvt_ftou_simd(f32s, u32s) { - assertEq(f32s.length, u32s.length); - for (var i = 0; i < f32s.length; i += 4) { - SIMD.Uint32x4.store(u32s, i, SIMD.Uint32x4.fromFloat32x4(SIMD.Float32x4.load(f32s, i))); - } -} - -function check(a, b) { - assertEq(a.length, b.length); - for (var i = 0; i < a.length; i++) { - assertEq(a[i], b[i]); - } -} - -// Uint32x4 --> Float32x4 tests. -var src = new Uint32Array(8000); -var dst1 = new Float32Array(8000); -var dst2 = new Float32Array(8000); - -for (var i = 0; i < 2000; i++) { - src[i] = i; - src[i + 2000] = 0x7fffffff - i; - src[i + 4000] = 0x80000000 + i; - src[i + 6000] = 0xffffffff - i; -} - -for (var n = 0; n < 10; n++) { - cvt_utof_scalar(src, dst1); - cvt_utof_simd(src, dst2); - check(dst1, dst2); -} - -// Float32x4 --> Uint32x4 tests. -var fsrc = dst1; -var fdst1 = new Uint32Array(8000); -var fdst2 = new Uint32Array(8000); - -// The 0xffffffff entries in fsrc round to 0x1.0p32f which throws. -// Go as high as 0x0.ffffffp32f. -for (var i = 0; i < 2000; i++) { - fsrc[i + 6000] = 0xffffff7f - i; -} - -// Truncation towards 0. -fsrc[1990] = -0.9 -fsrc[1991] = 0.9 -fsrc[1992] = 1.9 - -for (var n = 0; n < 10; n++) { - cvt_ftou_scalar(fsrc, fdst1); - cvt_ftou_simd(fsrc, fdst2); - check(fdst1, fdst2); -} diff --git a/js/src/jit-test/tests/SIMD/unary.js b/js/src/jit-test/tests/SIMD/unary.js deleted file mode 100644 index 34ec3fb100..0000000000 --- a/js/src/jit-test/tests/SIMD/unary.js +++ /dev/null @@ -1,35 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("ion.warmup.trigger", 50); - -var notf = (function() { - var i32 = new Int32Array(1); - var f32 = new Float32Array(i32.buffer); - return function(x) { - f32[0] = x; - i32[0] = ~i32[0]; - return f32[0]; - } -})(); - -function f() { - var f4 = SIMD.Float32x4(1, 2, 3, 4); - var i4 = SIMD.Int32x4(1, 2, 3, 4); - var b4 = SIMD.Bool32x4(true, false, true, false); - var BitOrZero = (x) => x | 0; - for (var i = 0; i < 150; i++) { - assertEqX4(SIMD.Float32x4.neg(f4), unaryX4((x) => -x, f4, Math.fround)); - assertEqX4(SIMD.Float32x4.abs(f4), unaryX4(Math.abs, f4, Math.fround)); - assertEqX4(SIMD.Float32x4.sqrt(f4), unaryX4(Math.sqrt, f4, Math.fround)); - - assertEqX4(SIMD.Float32x4.reciprocalApproximation(f4), unaryX4((x) => 1 / x, f4, Math.fround), assertNear); - assertEqX4(SIMD.Float32x4.reciprocalSqrtApproximation(f4), unaryX4((x) => 1 / Math.sqrt(x), f4, Math.fround), assertNear); - - assertEqX4(SIMD.Int32x4.not(i4), unaryX4((x) => ~x, i4, BitOrZero)); - assertEqX4(SIMD.Int32x4.neg(i4), unaryX4((x) => -x, i4, BitOrZero)); - - assertEqX4(SIMD.Bool32x4.not(b4), unaryX4((x) => !x, b4, (x) => x )); - } -} - -f(); diff --git a/js/src/jit-test/tests/SIMD/unbox.js b/js/src/jit-test/tests/SIMD/unbox.js deleted file mode 100644 index 2fffddd066..0000000000 --- a/js/src/jit-test/tests/SIMD/unbox.js +++ /dev/null @@ -1,144 +0,0 @@ -load(libdir + 'simd.js'); - -setJitCompilerOption("baseline.warmup.trigger", 10); -setJitCompilerOption("ion.warmup.trigger", 30); - -var max = 40, pivot = 35; - -var i32x4 = SIMD.Int32x4; -var f32x4 = SIMD.Float32x4; -var i32x4Add = SIMD.Int32x4.add; - -var FakeSIMDType = function (o) { this.x = o.x; this.y = o.y; this.z = o.z; this.w = o.w; }; -if (this.hasOwnProperty("TypedObject")) { - var TO = TypedObject; - FakeSIMDType = new TO.StructType({ x: TO.int32, y: TO.int32, z: TO.int32, w: TO.int32 }); -} - -function simdunbox_bail_undef(i, lhs, rhs) { - return i32x4Add(lhs, rhs); -} - -function simdunbox_bail_object(i, lhs, rhs) { - return i32x4Add(lhs, rhs); -} - -function simdunbox_bail_typeobj(i, lhs, rhs) { - return i32x4Add(lhs, rhs); -} - -function simdunbox_bail_badsimd(i, lhs, rhs) { - return i32x4Add(lhs, rhs); -} - -var arr_undef = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ]; -var fail_undef = 0; -var arr_object = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ]; -var fail_object = 0; -var arr_typeobj = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ]; -var fail_typeobj = 0; -var arr_badsimd = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ]; -var fail_badsimd = 0; -for (var i = 0; i < max; i++) { - try { - arr_undef[i + 2] = simdunbox_bail_undef(i, arr_undef[i], arr_undef[i + 1]); - } catch (x) { - arr_undef[i + 2] = arr_undef[i - 1]; - fail_undef++; - } - - try { - arr_object[i + 2] = simdunbox_bail_object(i, arr_object[i], arr_object[i + 1]); - } catch (x) { - arr_object[i + 2] = arr_object[i - 1]; - fail_object++; - } - - try { - arr_typeobj[i + 2] = simdunbox_bail_typeobj(i, arr_typeobj[i], arr_typeobj[i + 1]); - } catch (x) { - arr_typeobj[i + 2] = arr_typeobj[i - 1]; - fail_typeobj++; - } - - try { - arr_badsimd[i + 2] = simdunbox_bail_badsimd(i, arr_badsimd[i], arr_badsimd[i + 1]); - } catch (x) { - arr_badsimd[i + 2] = arr_badsimd[i - 1]; - fail_badsimd++; - } - - if (i + 2 == pivot) { - arr_undef[pivot] = undefined; - arr_object[pivot] = { x: 0, y: 1, z: 2, w: 3 }; - arr_typeobj[pivot] = new FakeSIMDType({ x: 0, y: 1, z: 2, w: 3 }); - arr_badsimd[pivot] = f32x4(0, 1, 2, 3); - } -} - -assertEq(fail_undef, 2); -assertEq(fail_object, 2); -assertEq(fail_typeobj, 2); -assertEq(fail_badsimd, 2); - -// Assert that all SIMD values are correct. -function assertEqX4(real, expected, assertFunc) { - if (typeof assertFunc === 'undefined') - assertFunc = assertEq; - - assertFunc(real.x, expected[0]); - assertFunc(real.y, expected[1]); - assertFunc(real.z, expected[2]); - assertFunc(real.w, expected[3]); -} - -var fib = [0, 1]; -for (i = 0; i < max + 5; i++) - fib[i+2] = (fib[i] + fib[i+1]) | 0; - -for (i = 0; i < max; i++) { - if (i == pivot) - continue; - var ref = fib.slice(i < pivot ? i : i - 3); - assertEqX4(arr_undef[i], ref); - assertEqX4(arr_object[i], ref); - assertEqX4(arr_typeobj[i], ref); - assertEqX4(arr_badsimd[i], ref); -} - -// Check that unbox operations aren't removed -(function() { - - function add(i, v, w) { - if (i % 2 == 0) { - SIMD.Int32x4.add(v, w); - } else { - SIMD.Float32x4.add(v, w); - } - } - - var i = 0; - var caught = false; - var f4 = SIMD.Float32x4(1,2,3,4); - var i4 = SIMD.Int32x4(1,2,3,4); - try { - for (; i < 200; i++) { - if (i % 2 == 0) { - add(i, i4, i4); - } else if (i == 199) { - add(i, i4, f4); - } else { - add(i, f4, f4); - } - } - } catch(e) { - print(e); - assertEq(e instanceof TypeError, true); - assertEq(i, 199); - caught = true; - } - - assertEq(i < 199 || caught, true); - -})(); - diff --git a/js/src/jit-test/tests/asm.js/bug1126251.js b/js/src/jit-test/tests/asm.js/bug1126251.js index 8470a97727..77aa56dbeb 100644 --- a/js/src/jit-test/tests/asm.js/bug1126251.js +++ b/js/src/jit-test/tests/asm.js/bug1126251.js @@ -13,41 +13,3 @@ var v = asmLink(asmCompile('global', ` `), this)(); assertEq(v, NaN); - -if (!isSimdAvailable() || typeof SIMD === 'undefined') { - quit(0); -} - -var v = asmLink(asmCompile('global', ` - "use asm"; - var frd = global.Math.fround; - var Float32x4 = global.SIMD.Float32x4; - var splat = Float32x4.splat; - var ext = Float32x4.extractLane; - function e() { - var v = Float32x4(0,0,0,0); - var x = frd(0.); - v = splat(.1e+71); - x = ext(v,0); - x = frd(x / x); - return +x; - } - return e; -`), this)(); - -assertEq(v, NaN); - -// Bug 1130618: without GVN -setJitCompilerOption("ion.gvn.enable", 0); -var v = asmLink(asmCompile('global', ` - "use asm"; - var Float32x4 = global.SIMD.Float32x4; - var splat = Float32x4.splat; - var ext = Float32x4.extractLane; - function e() { - return +ext(splat(.1e+71),0); - } - return e; -`), this)(); - -assertEq(v, Infinity); diff --git a/js/src/jit-test/tests/asm.js/bug1201124-simd-proxy.js b/js/src/jit-test/tests/asm.js/bug1201124-simd-proxy.js deleted file mode 100644 index edcc069ffb..0000000000 --- a/js/src/jit-test/tests/asm.js/bug1201124-simd-proxy.js +++ /dev/null @@ -1,28 +0,0 @@ -load(libdir + "asm.js"); -load(libdir + "asserts.js"); - -if (typeof newGlobal !== 'function' || - !isSimdAvailable() || - typeof SIMD === 'undefined') -{ - quit(); -} - -var stdlib = new (newGlobal().Proxy)(this, new Proxy({ - simdGet: 0, - getOwnPropertyDescriptor(t, pk) { - if (pk === "SIMD" && this.simdGet++ === 1) { - return {}; - } - return Reflect.getOwnPropertyDescriptor(t, pk); - } -}, { - get(t, pk, r) { - print("trap", pk); - return Reflect.get(t, pk, r); - } -})); - -var m = asmCompile('stdlib', '"use asm"; var i4=stdlib.SIMD.Int32x4; var i4add=i4.add; return {}'); - -assertAsmLinkFail(m, stdlib); diff --git a/js/src/jit-test/tests/asm.js/simd-fbirds.js b/js/src/jit-test/tests/asm.js/simd-fbirds.js deleted file mode 100644 index f94d409359..0000000000 --- a/js/src/jit-test/tests/asm.js/simd-fbirds.js +++ /dev/null @@ -1,197 +0,0 @@ -/* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 ; js-indent-level : 2 ; js-curly-indent-offset: 0 -*- */ - -// Author: Peter Jensen - -load(libdir + "asm.js"); -if (!isSimdAvailable() || typeof SIMD === 'undefined') { - print("won't run tests as simd extensions aren't activated yet"); - quit(0); -} - -const NUM_BIRDS = 30; -const NUM_UPDATES = 20; -const ACCEL_DATA_STEPS = 30; - -var buffer = new ArrayBuffer(0x200000); -var bufferF32 = new Float32Array(buffer); - -var actualBirds = 0; - -function init() { - actualBirds = 0; - // Make it a power of two, for quick modulo wrapping. - var accelDataValues = [10.0, 9.5, 9.0, 8.0, 7.0, 6.0, 5.5, 5.0, 5.0, 5.0, 5.5, 6.0, 7.0, 8.0, 9.0, 10.0]; - accelDataValues = accelDataValues.map(function(v) { return 50*v; }); - var accelDataValuesLength = accelDataValues.length; - assertEq(accelDataValuesLength, 16); // Hard coded in the asm.js module - for (i = 0; i < accelDataValuesLength; i++) - bufferF32[i + NUM_BIRDS * 2] = accelDataValues[i]; -} - -function addBird(pos, vel) { - bufferF32[actualBirds] = pos; - bufferF32[actualBirds + NUM_BIRDS] = vel; - actualBirds++; - return actualBirds - 1; -} - -function getActualBirds() { - return actualBirds; -} - -var code = ` - "use asm"; - var toF = global.Math.fround; - var u8 = new global.Uint8Array(buffer); - var f32 = new global.Float32Array(buffer); - const maxBirds = 100000; - const maxBirdsx4 = 400000; - const maxBirdsx8 = 800000; - const accelMask = 0x3c; - const mk4 = 0x000ffff0; - - const getMaxPos = 1000.0; - const getAccelDataSteps = imp.accelDataSteps | 0; - var getActualBirds = imp.getActualBirds; - - var i4 = global.SIMD.Int32x4; - var f4 = global.SIMD.Float32x4; - var b4 = global.SIMD.Bool32x4; - var i4add = i4.add; - var i4and = i4.and; - var f4select = f4.select; - var f4add = f4.add; - var f4sub = f4.sub; - var f4mul = f4.mul; - var f4greaterThan = f4.greaterThan; - var f4splat = f4.splat; - var f4load = f4.load; - var f4store = f4.store; - var b4any = b4.anyTrue; - - const zerox4 = f4(0.0,0.0,0.0,0.0); - - function declareHeapSize() { - f32[0x0007ffff] = toF(0.0); - } - - function update(timeDelta) { - timeDelta = toF(timeDelta); - // var steps = Math.ceil(timeDelta/accelData.interval); - var steps = 0; - var subTimeDelta = toF(0.0); - var actualBirds = 0; - var maxPos = toF(0.0); - var maxPosx4 = f4(0.0,0.0,0.0,0.0); - var subTimeDeltax4 = f4(0.0,0.0,0.0,0.0); - var subTimeDeltaSquaredx4 = f4(0.0,0.0,0.0,0.0); - var point5x4 = f4(0.5, 0.5, 0.5, 0.5); - var i = 0; - var len = 0; - var accelIndex = 0; - var newPosx4 = f4(0.0,0.0,0.0,0.0); - var newVelx4 = f4(0.0,0.0,0.0,0.0); - var accel = toF(0.0); - var accelx4 = f4(0.0,0.0,0.0,0.0); - var a = 0; - var posDeltax4 = f4(0.0,0.0,0.0,0.0); - var cmpx4 = b4(0,0,0,0); - var newVelTruex4 = f4(0.0,0.0,0.0,0.0); - - steps = getAccelDataSteps | 0; - subTimeDelta = toF(toF(timeDelta / toF(steps | 0)) / toF(1000.0)); - actualBirds = getActualBirds() | 0; - maxPos = toF(+getMaxPos); - maxPosx4 = f4splat(maxPos); - subTimeDeltax4 = f4splat(subTimeDelta); - subTimeDeltaSquaredx4 = f4mul(subTimeDeltax4, subTimeDeltax4); - - len = ((actualBirds + 3) >> 2) << 4; - - for (i = 0; (i | 0) < (len | 0); i = (i + 16) | 0) { - accelIndex = 0; - newPosx4 = f4load(u8, i & mk4); - newVelx4 = f4load(u8, (i & mk4) + maxBirdsx4); - for (a = 0; (a | 0) < (steps | 0); a = (a + 1) | 0) { - accel = toF(f32[(accelIndex & accelMask) + maxBirdsx8 >> 2]); - accelx4 = f4splat(accel); - accelIndex = (accelIndex + 4) | 0; - posDeltax4 = f4mul(point5x4, f4mul(accelx4, subTimeDeltaSquaredx4)); - posDeltax4 = f4add(posDeltax4, f4mul(newVelx4, subTimeDeltax4)); - newPosx4 = f4add(newPosx4, posDeltax4); - newVelx4 = f4add(newVelx4, f4mul(accelx4, subTimeDeltax4)); - cmpx4 = f4greaterThan(newPosx4, maxPosx4); - - if (b4any(cmpx4)) { - // Work around unimplemented 'neg' operation, using 0 - x. - newVelTruex4 = f4sub(zerox4, newVelx4); - newVelx4 = f4select(cmpx4, newVelTruex4, newVelx4); - } - } - f4store(u8, i & mk4, newPosx4); - f4store(u8, (i & mk4) + maxBirdsx4, newVelx4); - } - } - - return update; -` - -var ffi = { - getActualBirds, - accelDataSteps: ACCEL_DATA_STEPS -}; - -var fbirds = asmLink(asmCompile('global', 'imp', 'buffer', code), this, ffi, buffer); - -init(); -for (var i = 0; i < NUM_BIRDS; i++) { - addBird(i / 10, Math.exp(2, NUM_BIRDS - i)); -} - -var b = dateNow(); -for (var j = 0; j < NUM_UPDATES; j++) { - fbirds(16); -} -print(dateNow() - b); - -assertEq(bufferF32[0], 0); -assertEq(bufferF32[1], 0.10000000149011612); -assertEq(bufferF32[2], 0.20000000298023224); -assertEq(bufferF32[3], 0.30000001192092896); -assertEq(bufferF32[4], 0.4000000059604645); -assertEq(bufferF32[5], 0.5); -assertEq(bufferF32[6], 0.6000000238418579); -assertEq(bufferF32[7], 0.699999988079071); -assertEq(bufferF32[8], 0.800000011920929); -assertEq(bufferF32[9], 0.8999999761581421); -assertEq(bufferF32[10], 1); -assertEq(bufferF32[11], 1.100000023841858); -assertEq(bufferF32[12], 1.2000000476837158); -assertEq(bufferF32[13], 1.2999999523162842); -assertEq(bufferF32[14], 1.399999976158142); -assertEq(bufferF32[15], 1.5); -assertEq(bufferF32[16], 1.600000023841858); -assertEq(bufferF32[17], 1.7000000476837158); -assertEq(bufferF32[18], 1.7999999523162842); -assertEq(bufferF32[19], 1.899999976158142); -assertEq(bufferF32[20], 2); -assertEq(bufferF32[21], 2.0999999046325684); -assertEq(bufferF32[22], 2.200000047683716); -assertEq(bufferF32[23], 2.299999952316284); -assertEq(bufferF32[24], 2.4000000953674316); -assertEq(bufferF32[25], 2.5); -assertEq(bufferF32[26], 2.5999999046325684); -assertEq(bufferF32[27], 2.700000047683716); -assertEq(bufferF32[28], 2.799999952316284); -assertEq(bufferF32[29], 2.9000000953674316); - - -// Code used to generate the assertEq list above. -function generateAssertList() { - var buf = ''; - for (var k = 0; k < NUM_BIRDS; k++) { - buf += 'assertEq(bufferF32['+ k + '], ' + bufferF32[k] + ');\n'; - } - print(buf); -} -//generateAssertList(); diff --git a/js/src/jit-test/tests/asm.js/simd-mandelbrot.js b/js/src/jit-test/tests/asm.js/simd-mandelbrot.js deleted file mode 100644 index 690548eb83..0000000000 --- a/js/src/jit-test/tests/asm.js/simd-mandelbrot.js +++ /dev/null @@ -1,1818 +0,0 @@ -/* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 ; js-indent-level : 2 ; js-curly-indent-offset: 0 -*- */ - -// Mandelbrot using SIMD -// Author: Peter Jensen, Intel Corporation - -load(libdir + "asm.js"); -if (!isSimdAvailable() || typeof SIMD === 'undefined') { - print("won't run tests as simd extensions aren't activated yet"); - quit(0); -} - -// global variables -const MAX_ITERATIONS = 10; -const DRAW_ITERATIONS = 10; - -const CANVAS_WIDTH = 20; -const CANVAS_HEIGHT = 20; - -const LIMIT_SHOW = 20 * 20 * 4; - -// Asm.js module buffer. -var buffer = new ArrayBuffer(16 * 1024 * 1024); -var view = new Uint8Array(buffer); - -var moduleCode = ` - "use asm" - var b8 = new global.Uint8Array(buffer); - var toF = global.Math.fround; - var i4 = global.SIMD.Int32x4; - var ci4 = i4.check; - var f4 = global.SIMD.Float32x4; - var i4add = i4.add; - var i4and = i4.and; - var i4ext = i4.extractLane; - var i4sel = i4.select; - var f4add = f4.add; - var f4sub = f4.sub; - var f4mul = f4.mul; - var f4lessThanOrEqual = f4.lessThanOrEqual; - var f4splat = f4.splat; - var imul = global.Math.imul; - var b4 = global.SIMD.Bool32x4; - var b4any = b4.anyTrue; - const zero4 = i4(0,0,0,0), one4 = i4(1,1,1,1), two4 = f4(2,2,2,2), four4 = f4(4,4,4,4); - - const mk0 = 0x007fffff; - - function declareHeapLength() { - b8[0x00ffffff] = 0; - } - - function mapColorAndSetPixel (x, y, width, value, max_iterations) { - x = x | 0; - y = y | 0; - width = width | 0; - value = value | 0; - max_iterations = max_iterations | 0; - - var rgb = 0, r = 0, g = 0, b = 0, index = 0; - - index = (((imul((width >>> 0), (y >>> 0)) + x) | 0) * 4) | 0; - if ((value | 0) == (max_iterations | 0)) { - r = 0; - g = 0; - b = 0; - } else { - rgb = ~~toF(toF(toF(toF(value >>> 0) * toF(0xffff)) / toF(max_iterations >>> 0)) * toF(0xff)); - r = rgb & 0xff; - g = (rgb >>> 8) & 0xff; - b = (rgb >>> 16) & 0xff; - } - b8[(index & mk0) >> 0] = r; - b8[(index & mk0) + 1 >> 0] = g; - b8[(index & mk0) + 2 >> 0] = b; - b8[(index & mk0) + 3 >> 0] = 255; - } - - function mandelPixelX4 (xf, yf, yd, max_iterations) { - xf = toF(xf); - yf = toF(yf); - yd = toF(yd); - max_iterations = max_iterations | 0; - var c_re4 = f4(0,0,0,0), c_im4 = f4(0,0,0,0); - var z_re4 = f4(0,0,0,0), z_im4 = f4(0,0,0,0); - var count4 = i4(0,0,0,0); - var z_re24 = f4(0,0,0,0), z_im24 = f4(0,0,0,0); - var new_re4 = f4(0,0,0,0), new_im4 = f4(0,0,0,0); - var i = 0; - var mb4 = b4(0,0,0,0); - - c_re4 = f4splat(xf); - c_im4 = f4(yf, toF(yd + yf), toF(yd + toF(yd + yf)), toF(yd + toF(yd + toF(yd + yf)))); - - z_re4 = c_re4; - z_im4 = c_im4; - - for (i = 0; (i | 0) < (max_iterations | 0); i = (i + 1) | 0) { - z_re24 = f4mul(z_re4, z_re4); - z_im24 = f4mul(z_im4, z_im4); - mb4 = f4lessThanOrEqual(f4add(z_re24, z_im24), four4); - // If all 4 values are greater than 4.0, there's no reason to continue. - if (!b4any(mb4)) - break; - - new_re4 = f4sub(z_re24, z_im24); - new_im4 = f4mul(f4mul(two4, z_re4), z_im4); - z_re4 = f4add(c_re4, new_re4); - z_im4 = f4add(c_im4, new_im4); - count4 = i4add(count4, i4sel(mb4, one4, zero4)); - } - return ci4(count4); - } - - function mandelColumnX4 (x, width, height, xf, yf, yd, max_iterations) { - x = x | 0; - width = width | 0; - height = height | 0; - xf = toF(xf); - yf = toF(yf); - yd = toF(yd); - max_iterations = max_iterations | 0; - - var y = 0; - var ydx4 = toF(0); - var m4 = i4(0,0,0,0); - - ydx4 = toF(yd * toF(4)); - for (y = 0; (y | 0) < (height | 0); y = (y + 4) | 0) { - m4 = ci4(mandelPixelX4(toF(xf), toF(yf), toF(yd), max_iterations)); - mapColorAndSetPixel(x | 0, y | 0, width, i4ext(m4,0), max_iterations); - mapColorAndSetPixel(x | 0, (y + 1) | 0, width, i4ext(m4,1), max_iterations); - mapColorAndSetPixel(x | 0, (y + 2) | 0, width, i4ext(m4,2), max_iterations); - mapColorAndSetPixel(x | 0, (y + 3) | 0, width, i4ext(m4,3), max_iterations); - yf = toF(yf + ydx4); - } - } - - function mandel (width, height, xc, yc, scale, max_iterations) { - width = width | 0; - height = height | 0; - xc = toF(xc); - yc = toF(yc); - scale = toF(scale); - max_iterations = max_iterations | 0; - - var x0 = toF(0), y0 = toF(0); - var xd = toF(0), yd = toF(0); - var xf = toF(0); - var x = 0; - - x0 = toF(xc - toF(scale * toF(1.5))); - y0 = toF(yc - scale); - xd = toF(toF(scale * toF(3)) / toF(width >>> 0)); - yd = toF(toF(scale * toF(2)) / toF(height >>> 0)); - xf = x0; - - for (x = 0; (x | 0) < (width | 0); x = (x + 1) | 0) { - mandelColumnX4(x, width, height, xf, y0, yd, max_iterations); - xf = toF(xf + xd); - } - } - - return mandel; -`; - -var FFI = {}; -var mandelbro = asmLink(asmCompile('global', 'ffi', 'buffer', moduleCode), this, FFI, buffer); - -function animateMandelbrot () { - var scale_start = 1.0; - var scale_end = 0.0005; - var xc_start = -0.5; - var yc_start = 0.0; - var xc_end = 0.0; - var yc_end = 0.75; - var steps = 200.0; - var scale_step = (scale_end - scale_start)/steps; - var xc_step = (xc_end - xc_start)/steps; - var yc_step = (yc_end - yc_start)/steps; - var scale = scale_start; - var xc = xc_start; - var yc = yc_start; - var i = 0; - var now = dateNow(); - - function draw1 () { - mandelbro(CANVAS_WIDTH, CANVAS_HEIGHT, xc, yc, scale, MAX_ITERATIONS); - if (scale < scale_end || scale > scale_start) { - scale_step = -scale_step; - xc_step = -xc_step; - yc_step = -yc_step; - } - scale += scale_step; - xc += xc_step; - yc += yc_step; - i++; - } - - var b = dateNow(); - for (var j = DRAW_ITERATIONS; j --> 0;) - draw1(); - print(dateNow() - b); -} - -animateMandelbrot(); - -assertEq(view[0], 0, "0th value should be 0"); -assertEq(view[1], 0, "1th value should be 0"); -assertEq(view[2], 0, "2th value should be 0"); -assertEq(view[3], 255, "3th value should be 255"); -assertEq(view[4], 230, "4th value should be 230"); -assertEq(view[5], 127, "5th value should be 127"); -assertEq(view[6], 25, "6th value should be 25"); -assertEq(view[7], 255, "7th value should be 255"); -assertEq(view[8], 230, "8th value should be 230"); -assertEq(view[9], 127, "9th value should be 127"); -assertEq(view[10], 25, "10th value should be 25"); -assertEq(view[11], 255, "11th value should be 255"); -assertEq(view[12], 205, "12th value should be 205"); -assertEq(view[13], 255, "13th value should be 255"); -assertEq(view[14], 50, "14th value should be 50"); -assertEq(view[15], 255, "15th value should be 255"); -assertEq(view[16], 205, "16th value should be 205"); -assertEq(view[17], 255, "17th value should be 255"); -assertEq(view[18], 50, "18th value should be 50"); -assertEq(view[19], 255, "19th value should be 255"); -assertEq(view[20], 205, "20th value should be 205"); -assertEq(view[21], 255, "21th value should be 255"); -assertEq(view[22], 50, "22th value should be 50"); -assertEq(view[23], 255, "23th value should be 255"); -assertEq(view[24], 205, "24th value should be 205"); -assertEq(view[25], 255, "25th value should be 255"); -assertEq(view[26], 50, "26th value should be 50"); -assertEq(view[27], 255, "27th value should be 255"); -assertEq(view[28], 205, "28th value should be 205"); -assertEq(view[29], 255, "29th value should be 255"); -assertEq(view[30], 50, "30th value should be 50"); -assertEq(view[31], 255, "31th value should be 255"); -assertEq(view[32], 179, "32th value should be 179"); -assertEq(view[33], 127, "33th value should be 127"); -assertEq(view[34], 76, "34th value should be 76"); -assertEq(view[35], 255, "35th value should be 255"); -assertEq(view[36], 179, "36th value should be 179"); -assertEq(view[37], 127, "37th value should be 127"); -assertEq(view[38], 76, "38th value should be 76"); -assertEq(view[39], 255, "39th value should be 255"); -assertEq(view[40], 179, "40th value should be 179"); -assertEq(view[41], 127, "41th value should be 127"); -assertEq(view[42], 76, "42th value should be 76"); -assertEq(view[43], 255, "43th value should be 255"); -assertEq(view[44], 154, "44th value should be 154"); -assertEq(view[45], 255, "45th value should be 255"); -assertEq(view[46], 101, "46th value should be 101"); -assertEq(view[47], 255, "47th value should be 255"); -assertEq(view[48], 78, "48th value should be 78"); -assertEq(view[49], 127, "49th value should be 127"); -assertEq(view[50], 178, "50th value should be 178"); -assertEq(view[51], 255, "51th value should be 255"); -assertEq(view[52], 52, "52th value should be 52"); -assertEq(view[53], 255, "53th value should be 255"); -assertEq(view[54], 203, "54th value should be 203"); -assertEq(view[55], 255, "55th value should be 255"); -assertEq(view[56], 154, "56th value should be 154"); -assertEq(view[57], 255, "57th value should be 255"); -assertEq(view[58], 101, "58th value should be 101"); -assertEq(view[59], 255, "59th value should be 255"); -assertEq(view[60], 179, "60th value should be 179"); -assertEq(view[61], 127, "61th value should be 127"); -assertEq(view[62], 76, "62th value should be 76"); -assertEq(view[63], 255, "63th value should be 255"); -assertEq(view[64], 205, "64th value should be 205"); -assertEq(view[65], 255, "65th value should be 255"); -assertEq(view[66], 50, "66th value should be 50"); -assertEq(view[67], 255, "67th value should be 255"); -assertEq(view[68], 205, "68th value should be 205"); -assertEq(view[69], 255, "69th value should be 255"); -assertEq(view[70], 50, "70th value should be 50"); -assertEq(view[71], 255, "71th value should be 255"); -assertEq(view[72], 230, "72th value should be 230"); -assertEq(view[73], 127, "73th value should be 127"); -assertEq(view[74], 25, "74th value should be 25"); -assertEq(view[75], 255, "75th value should be 255"); -assertEq(view[76], 230, "76th value should be 230"); -assertEq(view[77], 127, "77th value should be 127"); -assertEq(view[78], 25, "78th value should be 25"); -assertEq(view[79], 255, "79th value should be 255"); -assertEq(view[80], 0, "80th value should be 0"); -assertEq(view[81], 0, "81th value should be 0"); -assertEq(view[82], 0, "82th value should be 0"); -assertEq(view[83], 255, "83th value should be 255"); -assertEq(view[84], 230, "84th value should be 230"); -assertEq(view[85], 127, "85th value should be 127"); -assertEq(view[86], 25, "86th value should be 25"); -assertEq(view[87], 255, "87th value should be 255"); -assertEq(view[88], 205, "88th value should be 205"); -assertEq(view[89], 255, "89th value should be 255"); -assertEq(view[90], 50, "90th value should be 50"); -assertEq(view[91], 255, "91th value should be 255"); -assertEq(view[92], 205, "92th value should be 205"); -assertEq(view[93], 255, "93th value should be 255"); -assertEq(view[94], 50, "94th value should be 50"); -assertEq(view[95], 255, "95th value should be 255"); -assertEq(view[96], 205, "96th value should be 205"); -assertEq(view[97], 255, "97th value should be 255"); -assertEq(view[98], 50, "98th value should be 50"); -assertEq(view[99], 255, "99th value should be 255"); -assertEq(view[100], 205, "100th value should be 205"); -assertEq(view[101], 255, "101th value should be 255"); -assertEq(view[102], 50, "102th value should be 50"); -assertEq(view[103], 255, "103th value should be 255"); -assertEq(view[104], 205, "104th value should be 205"); -assertEq(view[105], 255, "105th value should be 255"); -assertEq(view[106], 50, "106th value should be 50"); -assertEq(view[107], 255, "107th value should be 255"); -assertEq(view[108], 205, "108th value should be 205"); -assertEq(view[109], 255, "109th value should be 255"); -assertEq(view[110], 50, "110th value should be 50"); -assertEq(view[111], 255, "111th value should be 255"); -assertEq(view[112], 179, "112th value should be 179"); -assertEq(view[113], 127, "113th value should be 127"); -assertEq(view[114], 76, "114th value should be 76"); -assertEq(view[115], 255, "115th value should be 255"); -assertEq(view[116], 179, "116th value should be 179"); -assertEq(view[117], 127, "117th value should be 127"); -assertEq(view[118], 76, "118th value should be 76"); -assertEq(view[119], 255, "119th value should be 255"); -assertEq(view[120], 154, "120th value should be 154"); -assertEq(view[121], 255, "121th value should be 255"); -assertEq(view[122], 101, "122th value should be 101"); -assertEq(view[123], 255, "123th value should be 255"); -assertEq(view[124], 103, "124th value should be 103"); -assertEq(view[125], 255, "125th value should be 255"); -assertEq(view[126], 152, "126th value should be 152"); -assertEq(view[127], 255, "127th value should be 255"); -assertEq(view[128], 0, "128th value should be 0"); -assertEq(view[129], 0, "129th value should be 0"); -assertEq(view[130], 0, "130th value should be 0"); -assertEq(view[131], 255, "131th value should be 255"); -assertEq(view[132], 0, "132th value should be 0"); -assertEq(view[133], 0, "133th value should be 0"); -assertEq(view[134], 0, "134th value should be 0"); -assertEq(view[135], 255, "135th value should be 255"); -assertEq(view[136], 128, "136th value should be 128"); -assertEq(view[137], 127, "137th value should be 127"); -assertEq(view[138], 127, "138th value should be 127"); -assertEq(view[139], 255, "139th value should be 255"); -assertEq(view[140], 154, "140th value should be 154"); -assertEq(view[141], 255, "141th value should be 255"); -assertEq(view[142], 101, "142th value should be 101"); -assertEq(view[143], 255, "143th value should be 255"); -assertEq(view[144], 179, "144th value should be 179"); -assertEq(view[145], 127, "145th value should be 127"); -assertEq(view[146], 76, "146th value should be 76"); -assertEq(view[147], 255, "147th value should be 255"); -assertEq(view[148], 205, "148th value should be 205"); -assertEq(view[149], 255, "149th value should be 255"); -assertEq(view[150], 50, "150th value should be 50"); -assertEq(view[151], 255, "151th value should be 255"); -assertEq(view[152], 205, "152th value should be 205"); -assertEq(view[153], 255, "153th value should be 255"); -assertEq(view[154], 50, "154th value should be 50"); -assertEq(view[155], 255, "155th value should be 255"); -assertEq(view[156], 230, "156th value should be 230"); -assertEq(view[157], 127, "157th value should be 127"); -assertEq(view[158], 25, "158th value should be 25"); -assertEq(view[159], 255, "159th value should be 255"); -assertEq(view[160], 0, "160th value should be 0"); -assertEq(view[161], 0, "161th value should be 0"); -assertEq(view[162], 0, "162th value should be 0"); -assertEq(view[163], 255, "163th value should be 255"); -assertEq(view[164], 230, "164th value should be 230"); -assertEq(view[165], 127, "165th value should be 127"); -assertEq(view[166], 25, "166th value should be 25"); -assertEq(view[167], 255, "167th value should be 255"); -assertEq(view[168], 205, "168th value should be 205"); -assertEq(view[169], 255, "169th value should be 255"); -assertEq(view[170], 50, "170th value should be 50"); -assertEq(view[171], 255, "171th value should be 255"); -assertEq(view[172], 205, "172th value should be 205"); -assertEq(view[173], 255, "173th value should be 255"); -assertEq(view[174], 50, "174th value should be 50"); -assertEq(view[175], 255, "175th value should be 255"); -assertEq(view[176], 205, "176th value should be 205"); -assertEq(view[177], 255, "177th value should be 255"); -assertEq(view[178], 50, "178th value should be 50"); -assertEq(view[179], 255, "179th value should be 255"); -assertEq(view[180], 205, "180th value should be 205"); -assertEq(view[181], 255, "181th value should be 255"); -assertEq(view[182], 50, "182th value should be 50"); -assertEq(view[183], 255, "183th value should be 255"); -assertEq(view[184], 205, "184th value should be 205"); -assertEq(view[185], 255, "185th value should be 255"); -assertEq(view[186], 50, "186th value should be 50"); -assertEq(view[187], 255, "187th value should be 255"); -assertEq(view[188], 179, "188th value should be 179"); -assertEq(view[189], 127, "189th value should be 127"); -assertEq(view[190], 76, "190th value should be 76"); -assertEq(view[191], 255, "191th value should be 255"); -assertEq(view[192], 179, "192th value should be 179"); -assertEq(view[193], 127, "193th value should be 127"); -assertEq(view[194], 76, "194th value should be 76"); -assertEq(view[195], 255, "195th value should be 255"); -assertEq(view[196], 154, "196th value should be 154"); -assertEq(view[197], 255, "197th value should be 255"); -assertEq(view[198], 101, "198th value should be 101"); -assertEq(view[199], 255, "199th value should be 255"); -assertEq(view[200], 103, "200th value should be 103"); -assertEq(view[201], 255, "201th value should be 255"); -assertEq(view[202], 152, "202th value should be 152"); -assertEq(view[203], 255, "203th value should be 255"); -assertEq(view[204], 78, "204th value should be 78"); -assertEq(view[205], 127, "205th value should be 127"); -assertEq(view[206], 178, "206th value should be 178"); -assertEq(view[207], 255, "207th value should be 255"); -assertEq(view[208], 0, "208th value should be 0"); -assertEq(view[209], 0, "209th value should be 0"); -assertEq(view[210], 0, "210th value should be 0"); -assertEq(view[211], 255, "211th value should be 255"); -assertEq(view[212], 0, "212th value should be 0"); -assertEq(view[213], 0, "213th value should be 0"); -assertEq(view[214], 0, "214th value should be 0"); -assertEq(view[215], 255, "215th value should be 255"); -assertEq(view[216], 78, "216th value should be 78"); -assertEq(view[217], 127, "217th value should be 127"); -assertEq(view[218], 178, "218th value should be 178"); -assertEq(view[219], 255, "219th value should be 255"); -assertEq(view[220], 128, "220th value should be 128"); -assertEq(view[221], 127, "221th value should be 127"); -assertEq(view[222], 127, "222th value should be 127"); -assertEq(view[223], 255, "223th value should be 255"); -assertEq(view[224], 154, "224th value should be 154"); -assertEq(view[225], 255, "225th value should be 255"); -assertEq(view[226], 101, "226th value should be 101"); -assertEq(view[227], 255, "227th value should be 255"); -assertEq(view[228], 205, "228th value should be 205"); -assertEq(view[229], 255, "229th value should be 255"); -assertEq(view[230], 50, "230th value should be 50"); -assertEq(view[231], 255, "231th value should be 255"); -assertEq(view[232], 205, "232th value should be 205"); -assertEq(view[233], 255, "233th value should be 255"); -assertEq(view[234], 50, "234th value should be 50"); -assertEq(view[235], 255, "235th value should be 255"); -assertEq(view[236], 230, "236th value should be 230"); -assertEq(view[237], 127, "237th value should be 127"); -assertEq(view[238], 25, "238th value should be 25"); -assertEq(view[239], 255, "239th value should be 255"); -assertEq(view[240], 0, "240th value should be 0"); -assertEq(view[241], 0, "241th value should be 0"); -assertEq(view[242], 0, "242th value should be 0"); -assertEq(view[243], 255, "243th value should be 255"); -assertEq(view[244], 205, "244th value should be 205"); -assertEq(view[245], 255, "245th value should be 255"); -assertEq(view[246], 50, "246th value should be 50"); -assertEq(view[247], 255, "247th value should be 255"); -assertEq(view[248], 205, "248th value should be 205"); -assertEq(view[249], 255, "249th value should be 255"); -assertEq(view[250], 50, "250th value should be 50"); -assertEq(view[251], 255, "251th value should be 255"); -assertEq(view[252], 205, "252th value should be 205"); -assertEq(view[253], 255, "253th value should be 255"); -assertEq(view[254], 50, "254th value should be 50"); -assertEq(view[255], 255, "255th value should be 255"); -assertEq(view[256], 205, "256th value should be 205"); -assertEq(view[257], 255, "257th value should be 255"); -assertEq(view[258], 50, "258th value should be 50"); -assertEq(view[259], 255, "259th value should be 255"); -assertEq(view[260], 205, "260th value should be 205"); -assertEq(view[261], 255, "261th value should be 255"); -assertEq(view[262], 50, "262th value should be 50"); -assertEq(view[263], 255, "263th value should be 255"); -assertEq(view[264], 179, "264th value should be 179"); -assertEq(view[265], 127, "265th value should be 127"); -assertEq(view[266], 76, "266th value should be 76"); -assertEq(view[267], 255, "267th value should be 255"); -assertEq(view[268], 179, "268th value should be 179"); -assertEq(view[269], 127, "269th value should be 127"); -assertEq(view[270], 76, "270th value should be 76"); -assertEq(view[271], 255, "271th value should be 255"); -assertEq(view[272], 154, "272th value should be 154"); -assertEq(view[273], 255, "273th value should be 255"); -assertEq(view[274], 101, "274th value should be 101"); -assertEq(view[275], 255, "275th value should be 255"); -assertEq(view[276], 52, "276th value should be 52"); -assertEq(view[277], 255, "277th value should be 255"); -assertEq(view[278], 203, "278th value should be 203"); -assertEq(view[279], 255, "279th value should be 255"); -assertEq(view[280], 0, "280th value should be 0"); -assertEq(view[281], 0, "281th value should be 0"); -assertEq(view[282], 0, "282th value should be 0"); -assertEq(view[283], 255, "283th value should be 255"); -assertEq(view[284], 0, "284th value should be 0"); -assertEq(view[285], 0, "285th value should be 0"); -assertEq(view[286], 0, "286th value should be 0"); -assertEq(view[287], 255, "287th value should be 255"); -assertEq(view[288], 0, "288th value should be 0"); -assertEq(view[289], 0, "289th value should be 0"); -assertEq(view[290], 0, "290th value should be 0"); -assertEq(view[291], 255, "291th value should be 255"); -assertEq(view[292], 0, "292th value should be 0"); -assertEq(view[293], 0, "293th value should be 0"); -assertEq(view[294], 0, "294th value should be 0"); -assertEq(view[295], 255, "295th value should be 255"); -assertEq(view[296], 0, "296th value should be 0"); -assertEq(view[297], 0, "297th value should be 0"); -assertEq(view[298], 0, "298th value should be 0"); -assertEq(view[299], 255, "299th value should be 255"); -assertEq(view[300], 52, "300th value should be 52"); -assertEq(view[301], 255, "301th value should be 255"); -assertEq(view[302], 203, "302th value should be 203"); -assertEq(view[303], 255, "303th value should be 255"); -assertEq(view[304], 52, "304th value should be 52"); -assertEq(view[305], 255, "305th value should be 255"); -assertEq(view[306], 203, "306th value should be 203"); -assertEq(view[307], 255, "307th value should be 255"); -assertEq(view[308], 179, "308th value should be 179"); -assertEq(view[309], 127, "309th value should be 127"); -assertEq(view[310], 76, "310th value should be 76"); -assertEq(view[311], 255, "311th value should be 255"); -assertEq(view[312], 205, "312th value should be 205"); -assertEq(view[313], 255, "313th value should be 255"); -assertEq(view[314], 50, "314th value should be 50"); -assertEq(view[315], 255, "315th value should be 255"); -assertEq(view[316], 205, "316th value should be 205"); -assertEq(view[317], 255, "317th value should be 255"); -assertEq(view[318], 50, "318th value should be 50"); -assertEq(view[319], 255, "319th value should be 255"); -assertEq(view[320], 230, "320th value should be 230"); -assertEq(view[321], 127, "321th value should be 127"); -assertEq(view[322], 25, "322th value should be 25"); -assertEq(view[323], 255, "323th value should be 255"); -assertEq(view[324], 205, "324th value should be 205"); -assertEq(view[325], 255, "325th value should be 255"); -assertEq(view[326], 50, "326th value should be 50"); -assertEq(view[327], 255, "327th value should be 255"); -assertEq(view[328], 205, "328th value should be 205"); -assertEq(view[329], 255, "329th value should be 255"); -assertEq(view[330], 50, "330th value should be 50"); -assertEq(view[331], 255, "331th value should be 255"); -assertEq(view[332], 205, "332th value should be 205"); -assertEq(view[333], 255, "333th value should be 255"); -assertEq(view[334], 50, "334th value should be 50"); -assertEq(view[335], 255, "335th value should be 255"); -assertEq(view[336], 205, "336th value should be 205"); -assertEq(view[337], 255, "337th value should be 255"); -assertEq(view[338], 50, "338th value should be 50"); -assertEq(view[339], 255, "339th value should be 255"); -assertEq(view[340], 179, "340th value should be 179"); -assertEq(view[341], 127, "341th value should be 127"); -assertEq(view[342], 76, "342th value should be 76"); -assertEq(view[343], 255, "343th value should be 255"); -assertEq(view[344], 154, "344th value should be 154"); -assertEq(view[345], 255, "345th value should be 255"); -assertEq(view[346], 101, "346th value should be 101"); -assertEq(view[347], 255, "347th value should be 255"); -assertEq(view[348], 154, "348th value should be 154"); -assertEq(view[349], 255, "349th value should be 255"); -assertEq(view[350], 101, "350th value should be 101"); -assertEq(view[351], 255, "351th value should be 255"); -assertEq(view[352], 128, "352th value should be 128"); -assertEq(view[353], 127, "353th value should be 127"); -assertEq(view[354], 127, "354th value should be 127"); -assertEq(view[355], 255, "355th value should be 255"); -assertEq(view[356], 52, "356th value should be 52"); -assertEq(view[357], 255, "357th value should be 255"); -assertEq(view[358], 203, "358th value should be 203"); -assertEq(view[359], 255, "359th value should be 255"); -assertEq(view[360], 0, "360th value should be 0"); -assertEq(view[361], 0, "361th value should be 0"); -assertEq(view[362], 0, "362th value should be 0"); -assertEq(view[363], 255, "363th value should be 255"); -assertEq(view[364], 0, "364th value should be 0"); -assertEq(view[365], 0, "365th value should be 0"); -assertEq(view[366], 0, "366th value should be 0"); -assertEq(view[367], 255, "367th value should be 255"); -assertEq(view[368], 0, "368th value should be 0"); -assertEq(view[369], 0, "369th value should be 0"); -assertEq(view[370], 0, "370th value should be 0"); -assertEq(view[371], 255, "371th value should be 255"); -assertEq(view[372], 0, "372th value should be 0"); -assertEq(view[373], 0, "373th value should be 0"); -assertEq(view[374], 0, "374th value should be 0"); -assertEq(view[375], 255, "375th value should be 255"); -assertEq(view[376], 0, "376th value should be 0"); -assertEq(view[377], 0, "377th value should be 0"); -assertEq(view[378], 0, "378th value should be 0"); -assertEq(view[379], 255, "379th value should be 255"); -assertEq(view[380], 0, "380th value should be 0"); -assertEq(view[381], 0, "381th value should be 0"); -assertEq(view[382], 0, "382th value should be 0"); -assertEq(view[383], 255, "383th value should be 255"); -assertEq(view[384], 52, "384th value should be 52"); -assertEq(view[385], 255, "385th value should be 255"); -assertEq(view[386], 203, "386th value should be 203"); -assertEq(view[387], 255, "387th value should be 255"); -assertEq(view[388], 179, "388th value should be 179"); -assertEq(view[389], 127, "389th value should be 127"); -assertEq(view[390], 76, "390th value should be 76"); -assertEq(view[391], 255, "391th value should be 255"); -assertEq(view[392], 205, "392th value should be 205"); -assertEq(view[393], 255, "393th value should be 255"); -assertEq(view[394], 50, "394th value should be 50"); -assertEq(view[395], 255, "395th value should be 255"); -assertEq(view[396], 205, "396th value should be 205"); -assertEq(view[397], 255, "397th value should be 255"); -assertEq(view[398], 50, "398th value should be 50"); -assertEq(view[399], 255, "399th value should be 255"); -assertEq(view[400], 205, "400th value should be 205"); -assertEq(view[401], 255, "401th value should be 255"); -assertEq(view[402], 50, "402th value should be 50"); -assertEq(view[403], 255, "403th value should be 255"); -assertEq(view[404], 205, "404th value should be 205"); -assertEq(view[405], 255, "405th value should be 255"); -assertEq(view[406], 50, "406th value should be 50"); -assertEq(view[407], 255, "407th value should be 255"); -assertEq(view[408], 205, "408th value should be 205"); -assertEq(view[409], 255, "409th value should be 255"); -assertEq(view[410], 50, "410th value should be 50"); -assertEq(view[411], 255, "411th value should be 255"); -assertEq(view[412], 205, "412th value should be 205"); -assertEq(view[413], 255, "413th value should be 255"); -assertEq(view[414], 50, "414th value should be 50"); -assertEq(view[415], 255, "415th value should be 255"); -assertEq(view[416], 154, "416th value should be 154"); -assertEq(view[417], 255, "417th value should be 255"); -assertEq(view[418], 101, "418th value should be 101"); -assertEq(view[419], 255, "419th value should be 255"); -assertEq(view[420], 128, "420th value should be 128"); -assertEq(view[421], 127, "421th value should be 127"); -assertEq(view[422], 127, "422th value should be 127"); -assertEq(view[423], 255, "423th value should be 255"); -assertEq(view[424], 154, "424th value should be 154"); -assertEq(view[425], 255, "425th value should be 255"); -assertEq(view[426], 101, "426th value should be 101"); -assertEq(view[427], 255, "427th value should be 255"); -assertEq(view[428], 128, "428th value should be 128"); -assertEq(view[429], 127, "429th value should be 127"); -assertEq(view[430], 127, "430th value should be 127"); -assertEq(view[431], 255, "431th value should be 255"); -assertEq(view[432], 103, "432th value should be 103"); -assertEq(view[433], 255, "433th value should be 255"); -assertEq(view[434], 152, "434th value should be 152"); -assertEq(view[435], 255, "435th value should be 255"); -assertEq(view[436], 0, "436th value should be 0"); -assertEq(view[437], 0, "437th value should be 0"); -assertEq(view[438], 0, "438th value should be 0"); -assertEq(view[439], 255, "439th value should be 255"); -assertEq(view[440], 0, "440th value should be 0"); -assertEq(view[441], 0, "441th value should be 0"); -assertEq(view[442], 0, "442th value should be 0"); -assertEq(view[443], 255, "443th value should be 255"); -assertEq(view[444], 0, "444th value should be 0"); -assertEq(view[445], 0, "445th value should be 0"); -assertEq(view[446], 0, "446th value should be 0"); -assertEq(view[447], 255, "447th value should be 255"); -assertEq(view[448], 0, "448th value should be 0"); -assertEq(view[449], 0, "449th value should be 0"); -assertEq(view[450], 0, "450th value should be 0"); -assertEq(view[451], 255, "451th value should be 255"); -assertEq(view[452], 0, "452th value should be 0"); -assertEq(view[453], 0, "453th value should be 0"); -assertEq(view[454], 0, "454th value should be 0"); -assertEq(view[455], 255, "455th value should be 255"); -assertEq(view[456], 0, "456th value should be 0"); -assertEq(view[457], 0, "457th value should be 0"); -assertEq(view[458], 0, "458th value should be 0"); -assertEq(view[459], 255, "459th value should be 255"); -assertEq(view[460], 0, "460th value should be 0"); -assertEq(view[461], 0, "461th value should be 0"); -assertEq(view[462], 0, "462th value should be 0"); -assertEq(view[463], 255, "463th value should be 255"); -assertEq(view[464], 78, "464th value should be 78"); -assertEq(view[465], 127, "465th value should be 127"); -assertEq(view[466], 178, "466th value should be 178"); -assertEq(view[467], 255, "467th value should be 255"); -assertEq(view[468], 154, "468th value should be 154"); -assertEq(view[469], 255, "469th value should be 255"); -assertEq(view[470], 101, "470th value should be 101"); -assertEq(view[471], 255, "471th value should be 255"); -assertEq(view[472], 205, "472th value should be 205"); -assertEq(view[473], 255, "473th value should be 255"); -assertEq(view[474], 50, "474th value should be 50"); -assertEq(view[475], 255, "475th value should be 255"); -assertEq(view[476], 205, "476th value should be 205"); -assertEq(view[477], 255, "477th value should be 255"); -assertEq(view[478], 50, "478th value should be 50"); -assertEq(view[479], 255, "479th value should be 255"); -assertEq(view[480], 205, "480th value should be 205"); -assertEq(view[481], 255, "481th value should be 255"); -assertEq(view[482], 50, "482th value should be 50"); -assertEq(view[483], 255, "483th value should be 255"); -assertEq(view[484], 205, "484th value should be 205"); -assertEq(view[485], 255, "485th value should be 255"); -assertEq(view[486], 50, "486th value should be 50"); -assertEq(view[487], 255, "487th value should be 255"); -assertEq(view[488], 179, "488th value should be 179"); -assertEq(view[489], 127, "489th value should be 127"); -assertEq(view[490], 76, "490th value should be 76"); -assertEq(view[491], 255, "491th value should be 255"); -assertEq(view[492], 179, "492th value should be 179"); -assertEq(view[493], 127, "493th value should be 127"); -assertEq(view[494], 76, "494th value should be 76"); -assertEq(view[495], 255, "495th value should be 255"); -assertEq(view[496], 128, "496th value should be 128"); -assertEq(view[497], 127, "497th value should be 127"); -assertEq(view[498], 127, "498th value should be 127"); -assertEq(view[499], 255, "499th value should be 255"); -assertEq(view[500], 52, "500th value should be 52"); -assertEq(view[501], 255, "501th value should be 255"); -assertEq(view[502], 203, "502th value should be 203"); -assertEq(view[503], 255, "503th value should be 255"); -assertEq(view[504], 0, "504th value should be 0"); -assertEq(view[505], 0, "505th value should be 0"); -assertEq(view[506], 0, "506th value should be 0"); -assertEq(view[507], 255, "507th value should be 255"); -assertEq(view[508], 78, "508th value should be 78"); -assertEq(view[509], 127, "509th value should be 127"); -assertEq(view[510], 178, "510th value should be 178"); -assertEq(view[511], 255, "511th value should be 255"); -assertEq(view[512], 52, "512th value should be 52"); -assertEq(view[513], 255, "513th value should be 255"); -assertEq(view[514], 203, "514th value should be 203"); -assertEq(view[515], 255, "515th value should be 255"); -assertEq(view[516], 0, "516th value should be 0"); -assertEq(view[517], 0, "517th value should be 0"); -assertEq(view[518], 0, "518th value should be 0"); -assertEq(view[519], 255, "519th value should be 255"); -assertEq(view[520], 0, "520th value should be 0"); -assertEq(view[521], 0, "521th value should be 0"); -assertEq(view[522], 0, "522th value should be 0"); -assertEq(view[523], 255, "523th value should be 255"); -assertEq(view[524], 0, "524th value should be 0"); -assertEq(view[525], 0, "525th value should be 0"); -assertEq(view[526], 0, "526th value should be 0"); -assertEq(view[527], 255, "527th value should be 255"); -assertEq(view[528], 0, "528th value should be 0"); -assertEq(view[529], 0, "529th value should be 0"); -assertEq(view[530], 0, "530th value should be 0"); -assertEq(view[531], 255, "531th value should be 255"); -assertEq(view[532], 0, "532th value should be 0"); -assertEq(view[533], 0, "533th value should be 0"); -assertEq(view[534], 0, "534th value should be 0"); -assertEq(view[535], 255, "535th value should be 255"); -assertEq(view[536], 0, "536th value should be 0"); -assertEq(view[537], 0, "537th value should be 0"); -assertEq(view[538], 0, "538th value should be 0"); -assertEq(view[539], 255, "539th value should be 255"); -assertEq(view[540], 0, "540th value should be 0"); -assertEq(view[541], 0, "541th value should be 0"); -assertEq(view[542], 0, "542th value should be 0"); -assertEq(view[543], 255, "543th value should be 255"); -assertEq(view[544], 0, "544th value should be 0"); -assertEq(view[545], 0, "545th value should be 0"); -assertEq(view[546], 0, "546th value should be 0"); -assertEq(view[547], 255, "547th value should be 255"); -assertEq(view[548], 154, "548th value should be 154"); -assertEq(view[549], 255, "549th value should be 255"); -assertEq(view[550], 101, "550th value should be 101"); -assertEq(view[551], 255, "551th value should be 255"); -assertEq(view[552], 205, "552th value should be 205"); -assertEq(view[553], 255, "553th value should be 255"); -assertEq(view[554], 50, "554th value should be 50"); -assertEq(view[555], 255, "555th value should be 255"); -assertEq(view[556], 205, "556th value should be 205"); -assertEq(view[557], 255, "557th value should be 255"); -assertEq(view[558], 50, "558th value should be 50"); -assertEq(view[559], 255, "559th value should be 255"); -assertEq(view[560], 205, "560th value should be 205"); -assertEq(view[561], 255, "561th value should be 255"); -assertEq(view[562], 50, "562th value should be 50"); -assertEq(view[563], 255, "563th value should be 255"); -assertEq(view[564], 179, "564th value should be 179"); -assertEq(view[565], 127, "565th value should be 127"); -assertEq(view[566], 76, "566th value should be 76"); -assertEq(view[567], 255, "567th value should be 255"); -assertEq(view[568], 179, "568th value should be 179"); -assertEq(view[569], 127, "569th value should be 127"); -assertEq(view[570], 76, "570th value should be 76"); -assertEq(view[571], 255, "571th value should be 255"); -assertEq(view[572], 154, "572th value should be 154"); -assertEq(view[573], 255, "573th value should be 255"); -assertEq(view[574], 101, "574th value should be 101"); -assertEq(view[575], 255, "575th value should be 255"); -assertEq(view[576], 103, "576th value should be 103"); -assertEq(view[577], 255, "577th value should be 255"); -assertEq(view[578], 152, "578th value should be 152"); -assertEq(view[579], 255, "579th value should be 255"); -assertEq(view[580], 0, "580th value should be 0"); -assertEq(view[581], 0, "581th value should be 0"); -assertEq(view[582], 0, "582th value should be 0"); -assertEq(view[583], 255, "583th value should be 255"); -assertEq(view[584], 0, "584th value should be 0"); -assertEq(view[585], 0, "585th value should be 0"); -assertEq(view[586], 0, "586th value should be 0"); -assertEq(view[587], 255, "587th value should be 255"); -assertEq(view[588], 0, "588th value should be 0"); -assertEq(view[589], 0, "589th value should be 0"); -assertEq(view[590], 0, "590th value should be 0"); -assertEq(view[591], 255, "591th value should be 255"); -assertEq(view[592], 0, "592th value should be 0"); -assertEq(view[593], 0, "593th value should be 0"); -assertEq(view[594], 0, "594th value should be 0"); -assertEq(view[595], 255, "595th value should be 255"); -assertEq(view[596], 0, "596th value should be 0"); -assertEq(view[597], 0, "597th value should be 0"); -assertEq(view[598], 0, "598th value should be 0"); -assertEq(view[599], 255, "599th value should be 255"); -assertEq(view[600], 0, "600th value should be 0"); -assertEq(view[601], 0, "601th value should be 0"); -assertEq(view[602], 0, "602th value should be 0"); -assertEq(view[603], 255, "603th value should be 255"); -assertEq(view[604], 0, "604th value should be 0"); -assertEq(view[605], 0, "605th value should be 0"); -assertEq(view[606], 0, "606th value should be 0"); -assertEq(view[607], 255, "607th value should be 255"); -assertEq(view[608], 0, "608th value should be 0"); -assertEq(view[609], 0, "609th value should be 0"); -assertEq(view[610], 0, "610th value should be 0"); -assertEq(view[611], 255, "611th value should be 255"); -assertEq(view[612], 0, "612th value should be 0"); -assertEq(view[613], 0, "613th value should be 0"); -assertEq(view[614], 0, "614th value should be 0"); -assertEq(view[615], 255, "615th value should be 255"); -assertEq(view[616], 0, "616th value should be 0"); -assertEq(view[617], 0, "617th value should be 0"); -assertEq(view[618], 0, "618th value should be 0"); -assertEq(view[619], 255, "619th value should be 255"); -assertEq(view[620], 0, "620th value should be 0"); -assertEq(view[621], 0, "621th value should be 0"); -assertEq(view[622], 0, "622th value should be 0"); -assertEq(view[623], 255, "623th value should be 255"); -assertEq(view[624], 0, "624th value should be 0"); -assertEq(view[625], 0, "625th value should be 0"); -assertEq(view[626], 0, "626th value should be 0"); -assertEq(view[627], 255, "627th value should be 255"); -assertEq(view[628], 154, "628th value should be 154"); -assertEq(view[629], 255, "629th value should be 255"); -assertEq(view[630], 101, "630th value should be 101"); -assertEq(view[631], 255, "631th value should be 255"); -assertEq(view[632], 205, "632th value should be 205"); -assertEq(view[633], 255, "633th value should be 255"); -assertEq(view[634], 50, "634th value should be 50"); -assertEq(view[635], 255, "635th value should be 255"); -assertEq(view[636], 205, "636th value should be 205"); -assertEq(view[637], 255, "637th value should be 255"); -assertEq(view[638], 50, "638th value should be 50"); -assertEq(view[639], 255, "639th value should be 255"); -assertEq(view[640], 179, "640th value should be 179"); -assertEq(view[641], 127, "641th value should be 127"); -assertEq(view[642], 76, "642th value should be 76"); -assertEq(view[643], 255, "643th value should be 255"); -assertEq(view[644], 179, "644th value should be 179"); -assertEq(view[645], 127, "645th value should be 127"); -assertEq(view[646], 76, "646th value should be 76"); -assertEq(view[647], 255, "647th value should be 255"); -assertEq(view[648], 154, "648th value should be 154"); -assertEq(view[649], 255, "649th value should be 255"); -assertEq(view[650], 101, "650th value should be 101"); -assertEq(view[651], 255, "651th value should be 255"); -assertEq(view[652], 128, "652th value should be 128"); -assertEq(view[653], 127, "653th value should be 127"); -assertEq(view[654], 127, "654th value should be 127"); -assertEq(view[655], 255, "655th value should be 255"); -assertEq(view[656], 52, "656th value should be 52"); -assertEq(view[657], 255, "657th value should be 255"); -assertEq(view[658], 203, "658th value should be 203"); -assertEq(view[659], 255, "659th value should be 255"); -assertEq(view[660], 0, "660th value should be 0"); -assertEq(view[661], 0, "661th value should be 0"); -assertEq(view[662], 0, "662th value should be 0"); -assertEq(view[663], 255, "663th value should be 255"); -assertEq(view[664], 0, "664th value should be 0"); -assertEq(view[665], 0, "665th value should be 0"); -assertEq(view[666], 0, "666th value should be 0"); -assertEq(view[667], 255, "667th value should be 255"); -assertEq(view[668], 0, "668th value should be 0"); -assertEq(view[669], 0, "669th value should be 0"); -assertEq(view[670], 0, "670th value should be 0"); -assertEq(view[671], 255, "671th value should be 255"); -assertEq(view[672], 0, "672th value should be 0"); -assertEq(view[673], 0, "673th value should be 0"); -assertEq(view[674], 0, "674th value should be 0"); -assertEq(view[675], 255, "675th value should be 255"); -assertEq(view[676], 0, "676th value should be 0"); -assertEq(view[677], 0, "677th value should be 0"); -assertEq(view[678], 0, "678th value should be 0"); -assertEq(view[679], 255, "679th value should be 255"); -assertEq(view[680], 0, "680th value should be 0"); -assertEq(view[681], 0, "681th value should be 0"); -assertEq(view[682], 0, "682th value should be 0"); -assertEq(view[683], 255, "683th value should be 255"); -assertEq(view[684], 0, "684th value should be 0"); -assertEq(view[685], 0, "685th value should be 0"); -assertEq(view[686], 0, "686th value should be 0"); -assertEq(view[687], 255, "687th value should be 255"); -assertEq(view[688], 0, "688th value should be 0"); -assertEq(view[689], 0, "689th value should be 0"); -assertEq(view[690], 0, "690th value should be 0"); -assertEq(view[691], 255, "691th value should be 255"); -assertEq(view[692], 0, "692th value should be 0"); -assertEq(view[693], 0, "693th value should be 0"); -assertEq(view[694], 0, "694th value should be 0"); -assertEq(view[695], 255, "695th value should be 255"); -assertEq(view[696], 0, "696th value should be 0"); -assertEq(view[697], 0, "697th value should be 0"); -assertEq(view[698], 0, "698th value should be 0"); -assertEq(view[699], 255, "699th value should be 255"); -assertEq(view[700], 0, "700th value should be 0"); -assertEq(view[701], 0, "701th value should be 0"); -assertEq(view[702], 0, "702th value should be 0"); -assertEq(view[703], 255, "703th value should be 255"); -assertEq(view[704], 0, "704th value should be 0"); -assertEq(view[705], 0, "705th value should be 0"); -assertEq(view[706], 0, "706th value should be 0"); -assertEq(view[707], 255, "707th value should be 255"); -assertEq(view[708], 154, "708th value should be 154"); -assertEq(view[709], 255, "709th value should be 255"); -assertEq(view[710], 101, "710th value should be 101"); -assertEq(view[711], 255, "711th value should be 255"); -assertEq(view[712], 179, "712th value should be 179"); -assertEq(view[713], 127, "713th value should be 127"); -assertEq(view[714], 76, "714th value should be 76"); -assertEq(view[715], 255, "715th value should be 255"); -assertEq(view[716], 205, "716th value should be 205"); -assertEq(view[717], 255, "717th value should be 255"); -assertEq(view[718], 50, "718th value should be 50"); -assertEq(view[719], 255, "719th value should be 255"); -assertEq(view[720], 154, "720th value should be 154"); -assertEq(view[721], 255, "721th value should be 255"); -assertEq(view[722], 101, "722th value should be 101"); -assertEq(view[723], 255, "723th value should be 255"); -assertEq(view[724], 52, "724th value should be 52"); -assertEq(view[725], 255, "725th value should be 255"); -assertEq(view[726], 203, "726th value should be 203"); -assertEq(view[727], 255, "727th value should be 255"); -assertEq(view[728], 128, "728th value should be 128"); -assertEq(view[729], 127, "729th value should be 127"); -assertEq(view[730], 127, "730th value should be 127"); -assertEq(view[731], 255, "731th value should be 255"); -assertEq(view[732], 78, "732th value should be 78"); -assertEq(view[733], 127, "733th value should be 127"); -assertEq(view[734], 178, "734th value should be 178"); -assertEq(view[735], 255, "735th value should be 255"); -assertEq(view[736], 0, "736th value should be 0"); -assertEq(view[737], 0, "737th value should be 0"); -assertEq(view[738], 0, "738th value should be 0"); -assertEq(view[739], 255, "739th value should be 255"); -assertEq(view[740], 0, "740th value should be 0"); -assertEq(view[741], 0, "741th value should be 0"); -assertEq(view[742], 0, "742th value should be 0"); -assertEq(view[743], 255, "743th value should be 255"); -assertEq(view[744], 0, "744th value should be 0"); -assertEq(view[745], 0, "745th value should be 0"); -assertEq(view[746], 0, "746th value should be 0"); -assertEq(view[747], 255, "747th value should be 255"); -assertEq(view[748], 0, "748th value should be 0"); -assertEq(view[749], 0, "749th value should be 0"); -assertEq(view[750], 0, "750th value should be 0"); -assertEq(view[751], 255, "751th value should be 255"); -assertEq(view[752], 0, "752th value should be 0"); -assertEq(view[753], 0, "753th value should be 0"); -assertEq(view[754], 0, "754th value should be 0"); -assertEq(view[755], 255, "755th value should be 255"); -assertEq(view[756], 0, "756th value should be 0"); -assertEq(view[757], 0, "757th value should be 0"); -assertEq(view[758], 0, "758th value should be 0"); -assertEq(view[759], 255, "759th value should be 255"); -assertEq(view[760], 0, "760th value should be 0"); -assertEq(view[761], 0, "761th value should be 0"); -assertEq(view[762], 0, "762th value should be 0"); -assertEq(view[763], 255, "763th value should be 255"); -assertEq(view[764], 0, "764th value should be 0"); -assertEq(view[765], 0, "765th value should be 0"); -assertEq(view[766], 0, "766th value should be 0"); -assertEq(view[767], 255, "767th value should be 255"); -assertEq(view[768], 0, "768th value should be 0"); -assertEq(view[769], 0, "769th value should be 0"); -assertEq(view[770], 0, "770th value should be 0"); -assertEq(view[771], 255, "771th value should be 255"); -assertEq(view[772], 0, "772th value should be 0"); -assertEq(view[773], 0, "773th value should be 0"); -assertEq(view[774], 0, "774th value should be 0"); -assertEq(view[775], 255, "775th value should be 255"); -assertEq(view[776], 0, "776th value should be 0"); -assertEq(view[777], 0, "777th value should be 0"); -assertEq(view[778], 0, "778th value should be 0"); -assertEq(view[779], 255, "779th value should be 255"); -assertEq(view[780], 0, "780th value should be 0"); -assertEq(view[781], 0, "781th value should be 0"); -assertEq(view[782], 0, "782th value should be 0"); -assertEq(view[783], 255, "783th value should be 255"); -assertEq(view[784], 78, "784th value should be 78"); -assertEq(view[785], 127, "785th value should be 127"); -assertEq(view[786], 178, "786th value should be 178"); -assertEq(view[787], 255, "787th value should be 255"); -assertEq(view[788], 154, "788th value should be 154"); -assertEq(view[789], 255, "789th value should be 255"); -assertEq(view[790], 101, "790th value should be 101"); -assertEq(view[791], 255, "791th value should be 255"); -assertEq(view[792], 179, "792th value should be 179"); -assertEq(view[793], 127, "793th value should be 127"); -assertEq(view[794], 76, "794th value should be 76"); -assertEq(view[795], 255, "795th value should be 255"); -assertEq(view[796], 205, "796th value should be 205"); -assertEq(view[797], 255, "797th value should be 255"); -assertEq(view[798], 50, "798th value should be 50"); -assertEq(view[799], 255, "799th value should be 255"); -assertEq(view[800], 128, "800th value should be 128"); -assertEq(view[801], 127, "801th value should be 127"); -assertEq(view[802], 127, "802th value should be 127"); -assertEq(view[803], 255, "803th value should be 255"); -assertEq(view[804], 0, "804th value should be 0"); -assertEq(view[805], 0, "805th value should be 0"); -assertEq(view[806], 0, "806th value should be 0"); -assertEq(view[807], 255, "807th value should be 255"); -assertEq(view[808], 26, "808th value should be 26"); -assertEq(view[809], 127, "809th value should be 127"); -assertEq(view[810], 229, "810th value should be 229"); -assertEq(view[811], 255, "811th value should be 255"); -assertEq(view[812], 0, "812th value should be 0"); -assertEq(view[813], 0, "813th value should be 0"); -assertEq(view[814], 0, "814th value should be 0"); -assertEq(view[815], 255, "815th value should be 255"); -assertEq(view[816], 0, "816th value should be 0"); -assertEq(view[817], 0, "817th value should be 0"); -assertEq(view[818], 0, "818th value should be 0"); -assertEq(view[819], 255, "819th value should be 255"); -assertEq(view[820], 0, "820th value should be 0"); -assertEq(view[821], 0, "821th value should be 0"); -assertEq(view[822], 0, "822th value should be 0"); -assertEq(view[823], 255, "823th value should be 255"); -assertEq(view[824], 0, "824th value should be 0"); -assertEq(view[825], 0, "825th value should be 0"); -assertEq(view[826], 0, "826th value should be 0"); -assertEq(view[827], 255, "827th value should be 255"); -assertEq(view[828], 0, "828th value should be 0"); -assertEq(view[829], 0, "829th value should be 0"); -assertEq(view[830], 0, "830th value should be 0"); -assertEq(view[831], 255, "831th value should be 255"); -assertEq(view[832], 0, "832th value should be 0"); -assertEq(view[833], 0, "833th value should be 0"); -assertEq(view[834], 0, "834th value should be 0"); -assertEq(view[835], 255, "835th value should be 255"); -assertEq(view[836], 0, "836th value should be 0"); -assertEq(view[837], 0, "837th value should be 0"); -assertEq(view[838], 0, "838th value should be 0"); -assertEq(view[839], 255, "839th value should be 255"); -assertEq(view[840], 0, "840th value should be 0"); -assertEq(view[841], 0, "841th value should be 0"); -assertEq(view[842], 0, "842th value should be 0"); -assertEq(view[843], 255, "843th value should be 255"); -assertEq(view[844], 0, "844th value should be 0"); -assertEq(view[845], 0, "845th value should be 0"); -assertEq(view[846], 0, "846th value should be 0"); -assertEq(view[847], 255, "847th value should be 255"); -assertEq(view[848], 0, "848th value should be 0"); -assertEq(view[849], 0, "849th value should be 0"); -assertEq(view[850], 0, "850th value should be 0"); -assertEq(view[851], 255, "851th value should be 255"); -assertEq(view[852], 0, "852th value should be 0"); -assertEq(view[853], 0, "853th value should be 0"); -assertEq(view[854], 0, "854th value should be 0"); -assertEq(view[855], 255, "855th value should be 255"); -assertEq(view[856], 0, "856th value should be 0"); -assertEq(view[857], 0, "857th value should be 0"); -assertEq(view[858], 0, "858th value should be 0"); -assertEq(view[859], 255, "859th value should be 255"); -assertEq(view[860], 0, "860th value should be 0"); -assertEq(view[861], 0, "861th value should be 0"); -assertEq(view[862], 0, "862th value should be 0"); -assertEq(view[863], 255, "863th value should be 255"); -assertEq(view[864], 103, "864th value should be 103"); -assertEq(view[865], 255, "865th value should be 255"); -assertEq(view[866], 152, "866th value should be 152"); -assertEq(view[867], 255, "867th value should be 255"); -assertEq(view[868], 154, "868th value should be 154"); -assertEq(view[869], 255, "869th value should be 255"); -assertEq(view[870], 101, "870th value should be 101"); -assertEq(view[871], 255, "871th value should be 255"); -assertEq(view[872], 179, "872th value should be 179"); -assertEq(view[873], 127, "873th value should be 127"); -assertEq(view[874], 76, "874th value should be 76"); -assertEq(view[875], 255, "875th value should be 255"); -assertEq(view[876], 205, "876th value should be 205"); -assertEq(view[877], 255, "877th value should be 255"); -assertEq(view[878], 50, "878th value should be 50"); -assertEq(view[879], 255, "879th value should be 255"); -assertEq(view[880], 179, "880th value should be 179"); -assertEq(view[881], 127, "881th value should be 127"); -assertEq(view[882], 76, "882th value should be 76"); -assertEq(view[883], 255, "883th value should be 255"); -assertEq(view[884], 179, "884th value should be 179"); -assertEq(view[885], 127, "885th value should be 127"); -assertEq(view[886], 76, "886th value should be 76"); -assertEq(view[887], 255, "887th value should be 255"); -assertEq(view[888], 128, "888th value should be 128"); -assertEq(view[889], 127, "889th value should be 127"); -assertEq(view[890], 127, "890th value should be 127"); -assertEq(view[891], 255, "891th value should be 255"); -assertEq(view[892], 103, "892th value should be 103"); -assertEq(view[893], 255, "893th value should be 255"); -assertEq(view[894], 152, "894th value should be 152"); -assertEq(view[895], 255, "895th value should be 255"); -assertEq(view[896], 26, "896th value should be 26"); -assertEq(view[897], 127, "897th value should be 127"); -assertEq(view[898], 229, "898th value should be 229"); -assertEq(view[899], 255, "899th value should be 255"); -assertEq(view[900], 0, "900th value should be 0"); -assertEq(view[901], 0, "901th value should be 0"); -assertEq(view[902], 0, "902th value should be 0"); -assertEq(view[903], 255, "903th value should be 255"); -assertEq(view[904], 0, "904th value should be 0"); -assertEq(view[905], 0, "905th value should be 0"); -assertEq(view[906], 0, "906th value should be 0"); -assertEq(view[907], 255, "907th value should be 255"); -assertEq(view[908], 0, "908th value should be 0"); -assertEq(view[909], 0, "909th value should be 0"); -assertEq(view[910], 0, "910th value should be 0"); -assertEq(view[911], 255, "911th value should be 255"); -assertEq(view[912], 0, "912th value should be 0"); -assertEq(view[913], 0, "913th value should be 0"); -assertEq(view[914], 0, "914th value should be 0"); -assertEq(view[915], 255, "915th value should be 255"); -assertEq(view[916], 0, "916th value should be 0"); -assertEq(view[917], 0, "917th value should be 0"); -assertEq(view[918], 0, "918th value should be 0"); -assertEq(view[919], 255, "919th value should be 255"); -assertEq(view[920], 0, "920th value should be 0"); -assertEq(view[921], 0, "921th value should be 0"); -assertEq(view[922], 0, "922th value should be 0"); -assertEq(view[923], 255, "923th value should be 255"); -assertEq(view[924], 0, "924th value should be 0"); -assertEq(view[925], 0, "925th value should be 0"); -assertEq(view[926], 0, "926th value should be 0"); -assertEq(view[927], 255, "927th value should be 255"); -assertEq(view[928], 0, "928th value should be 0"); -assertEq(view[929], 0, "929th value should be 0"); -assertEq(view[930], 0, "930th value should be 0"); -assertEq(view[931], 255, "931th value should be 255"); -assertEq(view[932], 0, "932th value should be 0"); -assertEq(view[933], 0, "933th value should be 0"); -assertEq(view[934], 0, "934th value should be 0"); -assertEq(view[935], 255, "935th value should be 255"); -assertEq(view[936], 0, "936th value should be 0"); -assertEq(view[937], 0, "937th value should be 0"); -assertEq(view[938], 0, "938th value should be 0"); -assertEq(view[939], 255, "939th value should be 255"); -assertEq(view[940], 0, "940th value should be 0"); -assertEq(view[941], 0, "941th value should be 0"); -assertEq(view[942], 0, "942th value should be 0"); -assertEq(view[943], 255, "943th value should be 255"); -assertEq(view[944], 0, "944th value should be 0"); -assertEq(view[945], 0, "945th value should be 0"); -assertEq(view[946], 0, "946th value should be 0"); -assertEq(view[947], 255, "947th value should be 255"); -assertEq(view[948], 154, "948th value should be 154"); -assertEq(view[949], 255, "949th value should be 255"); -assertEq(view[950], 101, "950th value should be 101"); -assertEq(view[951], 255, "951th value should be 255"); -assertEq(view[952], 179, "952th value should be 179"); -assertEq(view[953], 127, "953th value should be 127"); -assertEq(view[954], 76, "954th value should be 76"); -assertEq(view[955], 255, "955th value should be 255"); -assertEq(view[956], 205, "956th value should be 205"); -assertEq(view[957], 255, "957th value should be 255"); -assertEq(view[958], 50, "958th value should be 50"); -assertEq(view[959], 255, "959th value should be 255"); -assertEq(view[960], 179, "960th value should be 179"); -assertEq(view[961], 127, "961th value should be 127"); -assertEq(view[962], 76, "962th value should be 76"); -assertEq(view[963], 255, "963th value should be 255"); -assertEq(view[964], 179, "964th value should be 179"); -assertEq(view[965], 127, "965th value should be 127"); -assertEq(view[966], 76, "966th value should be 76"); -assertEq(view[967], 255, "967th value should be 255"); -assertEq(view[968], 179, "968th value should be 179"); -assertEq(view[969], 127, "969th value should be 127"); -assertEq(view[970], 76, "970th value should be 76"); -assertEq(view[971], 255, "971th value should be 255"); -assertEq(view[972], 154, "972th value should be 154"); -assertEq(view[973], 255, "973th value should be 255"); -assertEq(view[974], 101, "974th value should be 101"); -assertEq(view[975], 255, "975th value should be 255"); -assertEq(view[976], 103, "976th value should be 103"); -assertEq(view[977], 255, "977th value should be 255"); -assertEq(view[978], 152, "978th value should be 152"); -assertEq(view[979], 255, "979th value should be 255"); -assertEq(view[980], 0, "980th value should be 0"); -assertEq(view[981], 0, "981th value should be 0"); -assertEq(view[982], 0, "982th value should be 0"); -assertEq(view[983], 255, "983th value should be 255"); -assertEq(view[984], 0, "984th value should be 0"); -assertEq(view[985], 0, "985th value should be 0"); -assertEq(view[986], 0, "986th value should be 0"); -assertEq(view[987], 255, "987th value should be 255"); -assertEq(view[988], 0, "988th value should be 0"); -assertEq(view[989], 0, "989th value should be 0"); -assertEq(view[990], 0, "990th value should be 0"); -assertEq(view[991], 255, "991th value should be 255"); -assertEq(view[992], 0, "992th value should be 0"); -assertEq(view[993], 0, "993th value should be 0"); -assertEq(view[994], 0, "994th value should be 0"); -assertEq(view[995], 255, "995th value should be 255"); -assertEq(view[996], 0, "996th value should be 0"); -assertEq(view[997], 0, "997th value should be 0"); -assertEq(view[998], 0, "998th value should be 0"); -assertEq(view[999], 255, "999th value should be 255"); -assertEq(view[1000], 0, "1000th value should be 0"); -assertEq(view[1001], 0, "1001th value should be 0"); -assertEq(view[1002], 0, "1002th value should be 0"); -assertEq(view[1003], 255, "1003th value should be 255"); -assertEq(view[1004], 0, "1004th value should be 0"); -assertEq(view[1005], 0, "1005th value should be 0"); -assertEq(view[1006], 0, "1006th value should be 0"); -assertEq(view[1007], 255, "1007th value should be 255"); -assertEq(view[1008], 0, "1008th value should be 0"); -assertEq(view[1009], 0, "1009th value should be 0"); -assertEq(view[1010], 0, "1010th value should be 0"); -assertEq(view[1011], 255, "1011th value should be 255"); -assertEq(view[1012], 0, "1012th value should be 0"); -assertEq(view[1013], 0, "1013th value should be 0"); -assertEq(view[1014], 0, "1014th value should be 0"); -assertEq(view[1015], 255, "1015th value should be 255"); -assertEq(view[1016], 0, "1016th value should be 0"); -assertEq(view[1017], 0, "1017th value should be 0"); -assertEq(view[1018], 0, "1018th value should be 0"); -assertEq(view[1019], 255, "1019th value should be 255"); -assertEq(view[1020], 0, "1020th value should be 0"); -assertEq(view[1021], 0, "1021th value should be 0"); -assertEq(view[1022], 0, "1022th value should be 0"); -assertEq(view[1023], 255, "1023th value should be 255"); -assertEq(view[1024], 0, "1024th value should be 0"); -assertEq(view[1025], 0, "1025th value should be 0"); -assertEq(view[1026], 0, "1026th value should be 0"); -assertEq(view[1027], 255, "1027th value should be 255"); -assertEq(view[1028], 154, "1028th value should be 154"); -assertEq(view[1029], 255, "1029th value should be 255"); -assertEq(view[1030], 101, "1030th value should be 101"); -assertEq(view[1031], 255, "1031th value should be 255"); -assertEq(view[1032], 205, "1032th value should be 205"); -assertEq(view[1033], 255, "1033th value should be 255"); -assertEq(view[1034], 50, "1034th value should be 50"); -assertEq(view[1035], 255, "1035th value should be 255"); -assertEq(view[1036], 205, "1036th value should be 205"); -assertEq(view[1037], 255, "1037th value should be 255"); -assertEq(view[1038], 50, "1038th value should be 50"); -assertEq(view[1039], 255, "1039th value should be 255"); -assertEq(view[1040], 205, "1040th value should be 205"); -assertEq(view[1041], 255, "1041th value should be 255"); -assertEq(view[1042], 50, "1042th value should be 50"); -assertEq(view[1043], 255, "1043th value should be 255"); -assertEq(view[1044], 179, "1044th value should be 179"); -assertEq(view[1045], 127, "1045th value should be 127"); -assertEq(view[1046], 76, "1046th value should be 76"); -assertEq(view[1047], 255, "1047th value should be 255"); -assertEq(view[1048], 179, "1048th value should be 179"); -assertEq(view[1049], 127, "1049th value should be 127"); -assertEq(view[1050], 76, "1050th value should be 76"); -assertEq(view[1051], 255, "1051th value should be 255"); -assertEq(view[1052], 154, "1052th value should be 154"); -assertEq(view[1053], 255, "1053th value should be 255"); -assertEq(view[1054], 101, "1054th value should be 101"); -assertEq(view[1055], 255, "1055th value should be 255"); -assertEq(view[1056], 128, "1056th value should be 128"); -assertEq(view[1057], 127, "1057th value should be 127"); -assertEq(view[1058], 127, "1058th value should be 127"); -assertEq(view[1059], 255, "1059th value should be 255"); -assertEq(view[1060], 0, "1060th value should be 0"); -assertEq(view[1061], 0, "1061th value should be 0"); -assertEq(view[1062], 0, "1062th value should be 0"); -assertEq(view[1063], 255, "1063th value should be 255"); -assertEq(view[1064], 0, "1064th value should be 0"); -assertEq(view[1065], 0, "1065th value should be 0"); -assertEq(view[1066], 0, "1066th value should be 0"); -assertEq(view[1067], 255, "1067th value should be 255"); -assertEq(view[1068], 26, "1068th value should be 26"); -assertEq(view[1069], 127, "1069th value should be 127"); -assertEq(view[1070], 229, "1070th value should be 229"); -assertEq(view[1071], 255, "1071th value should be 255"); -assertEq(view[1072], 26, "1072th value should be 26"); -assertEq(view[1073], 127, "1073th value should be 127"); -assertEq(view[1074], 229, "1074th value should be 229"); -assertEq(view[1075], 255, "1075th value should be 255"); -assertEq(view[1076], 0, "1076th value should be 0"); -assertEq(view[1077], 0, "1077th value should be 0"); -assertEq(view[1078], 0, "1078th value should be 0"); -assertEq(view[1079], 255, "1079th value should be 255"); -assertEq(view[1080], 0, "1080th value should be 0"); -assertEq(view[1081], 0, "1081th value should be 0"); -assertEq(view[1082], 0, "1082th value should be 0"); -assertEq(view[1083], 255, "1083th value should be 255"); -assertEq(view[1084], 0, "1084th value should be 0"); -assertEq(view[1085], 0, "1085th value should be 0"); -assertEq(view[1086], 0, "1086th value should be 0"); -assertEq(view[1087], 255, "1087th value should be 255"); -assertEq(view[1088], 0, "1088th value should be 0"); -assertEq(view[1089], 0, "1089th value should be 0"); -assertEq(view[1090], 0, "1090th value should be 0"); -assertEq(view[1091], 255, "1091th value should be 255"); -assertEq(view[1092], 0, "1092th value should be 0"); -assertEq(view[1093], 0, "1093th value should be 0"); -assertEq(view[1094], 0, "1094th value should be 0"); -assertEq(view[1095], 255, "1095th value should be 255"); -assertEq(view[1096], 0, "1096th value should be 0"); -assertEq(view[1097], 0, "1097th value should be 0"); -assertEq(view[1098], 0, "1098th value should be 0"); -assertEq(view[1099], 255, "1099th value should be 255"); -assertEq(view[1100], 0, "1100th value should be 0"); -assertEq(view[1101], 0, "1101th value should be 0"); -assertEq(view[1102], 0, "1102th value should be 0"); -assertEq(view[1103], 255, "1103th value should be 255"); -assertEq(view[1104], 0, "1104th value should be 0"); -assertEq(view[1105], 0, "1105th value should be 0"); -assertEq(view[1106], 0, "1106th value should be 0"); -assertEq(view[1107], 255, "1107th value should be 255"); -assertEq(view[1108], 154, "1108th value should be 154"); -assertEq(view[1109], 255, "1109th value should be 255"); -assertEq(view[1110], 101, "1110th value should be 101"); -assertEq(view[1111], 255, "1111th value should be 255"); -assertEq(view[1112], 205, "1112th value should be 205"); -assertEq(view[1113], 255, "1113th value should be 255"); -assertEq(view[1114], 50, "1114th value should be 50"); -assertEq(view[1115], 255, "1115th value should be 255"); -assertEq(view[1116], 205, "1116th value should be 205"); -assertEq(view[1117], 255, "1117th value should be 255"); -assertEq(view[1118], 50, "1118th value should be 50"); -assertEq(view[1119], 255, "1119th value should be 255"); -assertEq(view[1120], 205, "1120th value should be 205"); -assertEq(view[1121], 255, "1121th value should be 255"); -assertEq(view[1122], 50, "1122th value should be 50"); -assertEq(view[1123], 255, "1123th value should be 255"); -assertEq(view[1124], 205, "1124th value should be 205"); -assertEq(view[1125], 255, "1125th value should be 255"); -assertEq(view[1126], 50, "1126th value should be 50"); -assertEq(view[1127], 255, "1127th value should be 255"); -assertEq(view[1128], 205, "1128th value should be 205"); -assertEq(view[1129], 255, "1129th value should be 255"); -assertEq(view[1130], 50, "1130th value should be 50"); -assertEq(view[1131], 255, "1131th value should be 255"); -assertEq(view[1132], 179, "1132th value should be 179"); -assertEq(view[1133], 127, "1133th value should be 127"); -assertEq(view[1134], 76, "1134th value should be 76"); -assertEq(view[1135], 255, "1135th value should be 255"); -assertEq(view[1136], 154, "1136th value should be 154"); -assertEq(view[1137], 255, "1137th value should be 255"); -assertEq(view[1138], 101, "1138th value should be 101"); -assertEq(view[1139], 255, "1139th value should be 255"); -assertEq(view[1140], 128, "1140th value should be 128"); -assertEq(view[1141], 127, "1141th value should be 127"); -assertEq(view[1142], 127, "1142th value should be 127"); -assertEq(view[1143], 255, "1143th value should be 255"); -assertEq(view[1144], 128, "1144th value should be 128"); -assertEq(view[1145], 127, "1145th value should be 127"); -assertEq(view[1146], 127, "1146th value should be 127"); -assertEq(view[1147], 255, "1147th value should be 255"); -assertEq(view[1148], 103, "1148th value should be 103"); -assertEq(view[1149], 255, "1149th value should be 255"); -assertEq(view[1150], 152, "1150th value should be 152"); -assertEq(view[1151], 255, "1151th value should be 255"); -assertEq(view[1152], 78, "1152th value should be 78"); -assertEq(view[1153], 127, "1153th value should be 127"); -assertEq(view[1154], 178, "1154th value should be 178"); -assertEq(view[1155], 255, "1155th value should be 255"); -assertEq(view[1156], 0, "1156th value should be 0"); -assertEq(view[1157], 0, "1157th value should be 0"); -assertEq(view[1158], 0, "1158th value should be 0"); -assertEq(view[1159], 255, "1159th value should be 255"); -assertEq(view[1160], 0, "1160th value should be 0"); -assertEq(view[1161], 0, "1161th value should be 0"); -assertEq(view[1162], 0, "1162th value should be 0"); -assertEq(view[1163], 255, "1163th value should be 255"); -assertEq(view[1164], 0, "1164th value should be 0"); -assertEq(view[1165], 0, "1165th value should be 0"); -assertEq(view[1166], 0, "1166th value should be 0"); -assertEq(view[1167], 255, "1167th value should be 255"); -assertEq(view[1168], 0, "1168th value should be 0"); -assertEq(view[1169], 0, "1169th value should be 0"); -assertEq(view[1170], 0, "1170th value should be 0"); -assertEq(view[1171], 255, "1171th value should be 255"); -assertEq(view[1172], 0, "1172th value should be 0"); -assertEq(view[1173], 0, "1173th value should be 0"); -assertEq(view[1174], 0, "1174th value should be 0"); -assertEq(view[1175], 255, "1175th value should be 255"); -assertEq(view[1176], 0, "1176th value should be 0"); -assertEq(view[1177], 0, "1177th value should be 0"); -assertEq(view[1178], 0, "1178th value should be 0"); -assertEq(view[1179], 255, "1179th value should be 255"); -assertEq(view[1180], 0, "1180th value should be 0"); -assertEq(view[1181], 0, "1181th value should be 0"); -assertEq(view[1182], 0, "1182th value should be 0"); -assertEq(view[1183], 255, "1183th value should be 255"); -assertEq(view[1184], 26, "1184th value should be 26"); -assertEq(view[1185], 127, "1185th value should be 127"); -assertEq(view[1186], 229, "1186th value should be 229"); -assertEq(view[1187], 255, "1187th value should be 255"); -assertEq(view[1188], 154, "1188th value should be 154"); -assertEq(view[1189], 255, "1189th value should be 255"); -assertEq(view[1190], 101, "1190th value should be 101"); -assertEq(view[1191], 255, "1191th value should be 255"); -assertEq(view[1192], 205, "1192th value should be 205"); -assertEq(view[1193], 255, "1193th value should be 255"); -assertEq(view[1194], 50, "1194th value should be 50"); -assertEq(view[1195], 255, "1195th value should be 255"); -assertEq(view[1196], 205, "1196th value should be 205"); -assertEq(view[1197], 255, "1197th value should be 255"); -assertEq(view[1198], 50, "1198th value should be 50"); -assertEq(view[1199], 255, "1199th value should be 255"); -assertEq(view[1200], 230, "1200th value should be 230"); -assertEq(view[1201], 127, "1201th value should be 127"); -assertEq(view[1202], 25, "1202th value should be 25"); -assertEq(view[1203], 255, "1203th value should be 255"); -assertEq(view[1204], 205, "1204th value should be 205"); -assertEq(view[1205], 255, "1205th value should be 255"); -assertEq(view[1206], 50, "1206th value should be 50"); -assertEq(view[1207], 255, "1207th value should be 255"); -assertEq(view[1208], 205, "1208th value should be 205"); -assertEq(view[1209], 255, "1209th value should be 255"); -assertEq(view[1210], 50, "1210th value should be 50"); -assertEq(view[1211], 255, "1211th value should be 255"); -assertEq(view[1212], 205, "1212th value should be 205"); -assertEq(view[1213], 255, "1213th value should be 255"); -assertEq(view[1214], 50, "1214th value should be 50"); -assertEq(view[1215], 255, "1215th value should be 255"); -assertEq(view[1216], 205, "1216th value should be 205"); -assertEq(view[1217], 255, "1217th value should be 255"); -assertEq(view[1218], 50, "1218th value should be 50"); -assertEq(view[1219], 255, "1219th value should be 255"); -assertEq(view[1220], 154, "1220th value should be 154"); -assertEq(view[1221], 255, "1221th value should be 255"); -assertEq(view[1222], 101, "1222th value should be 101"); -assertEq(view[1223], 255, "1223th value should be 255"); -assertEq(view[1224], 154, "1224th value should be 154"); -assertEq(view[1225], 255, "1225th value should be 255"); -assertEq(view[1226], 101, "1226th value should be 101"); -assertEq(view[1227], 255, "1227th value should be 255"); -assertEq(view[1228], 154, "1228th value should be 154"); -assertEq(view[1229], 255, "1229th value should be 255"); -assertEq(view[1230], 101, "1230th value should be 101"); -assertEq(view[1231], 255, "1231th value should be 255"); -assertEq(view[1232], 128, "1232th value should be 128"); -assertEq(view[1233], 127, "1233th value should be 127"); -assertEq(view[1234], 127, "1234th value should be 127"); -assertEq(view[1235], 255, "1235th value should be 255"); -assertEq(view[1236], 26, "1236th value should be 26"); -assertEq(view[1237], 127, "1237th value should be 127"); -assertEq(view[1238], 229, "1238th value should be 229"); -assertEq(view[1239], 255, "1239th value should be 255"); -assertEq(view[1240], 0, "1240th value should be 0"); -assertEq(view[1241], 0, "1241th value should be 0"); -assertEq(view[1242], 0, "1242th value should be 0"); -assertEq(view[1243], 255, "1243th value should be 255"); -assertEq(view[1244], 0, "1244th value should be 0"); -assertEq(view[1245], 0, "1245th value should be 0"); -assertEq(view[1246], 0, "1246th value should be 0"); -assertEq(view[1247], 255, "1247th value should be 255"); -assertEq(view[1248], 0, "1248th value should be 0"); -assertEq(view[1249], 0, "1249th value should be 0"); -assertEq(view[1250], 0, "1250th value should be 0"); -assertEq(view[1251], 255, "1251th value should be 255"); -assertEq(view[1252], 0, "1252th value should be 0"); -assertEq(view[1253], 0, "1253th value should be 0"); -assertEq(view[1254], 0, "1254th value should be 0"); -assertEq(view[1255], 255, "1255th value should be 255"); -assertEq(view[1256], 0, "1256th value should be 0"); -assertEq(view[1257], 0, "1257th value should be 0"); -assertEq(view[1258], 0, "1258th value should be 0"); -assertEq(view[1259], 255, "1259th value should be 255"); -assertEq(view[1260], 0, "1260th value should be 0"); -assertEq(view[1261], 0, "1261th value should be 0"); -assertEq(view[1262], 0, "1262th value should be 0"); -assertEq(view[1263], 255, "1263th value should be 255"); -assertEq(view[1264], 78, "1264th value should be 78"); -assertEq(view[1265], 127, "1265th value should be 127"); -assertEq(view[1266], 178, "1266th value should be 178"); -assertEq(view[1267], 255, "1267th value should be 255"); -assertEq(view[1268], 179, "1268th value should be 179"); -assertEq(view[1269], 127, "1269th value should be 127"); -assertEq(view[1270], 76, "1270th value should be 76"); -assertEq(view[1271], 255, "1271th value should be 255"); -assertEq(view[1272], 205, "1272th value should be 205"); -assertEq(view[1273], 255, "1273th value should be 255"); -assertEq(view[1274], 50, "1274th value should be 50"); -assertEq(view[1275], 255, "1275th value should be 255"); -assertEq(view[1276], 205, "1276th value should be 205"); -assertEq(view[1277], 255, "1277th value should be 255"); -assertEq(view[1278], 50, "1278th value should be 50"); -assertEq(view[1279], 255, "1279th value should be 255"); -assertEq(view[1280], 0, "1280th value should be 0"); -assertEq(view[1281], 0, "1281th value should be 0"); -assertEq(view[1282], 0, "1282th value should be 0"); -assertEq(view[1283], 255, "1283th value should be 255"); -assertEq(view[1284], 205, "1284th value should be 205"); -assertEq(view[1285], 255, "1285th value should be 255"); -assertEq(view[1286], 50, "1286th value should be 50"); -assertEq(view[1287], 255, "1287th value should be 255"); -assertEq(view[1288], 205, "1288th value should be 205"); -assertEq(view[1289], 255, "1289th value should be 255"); -assertEq(view[1290], 50, "1290th value should be 50"); -assertEq(view[1291], 255, "1291th value should be 255"); -assertEq(view[1292], 205, "1292th value should be 205"); -assertEq(view[1293], 255, "1293th value should be 255"); -assertEq(view[1294], 50, "1294th value should be 50"); -assertEq(view[1295], 255, "1295th value should be 255"); -assertEq(view[1296], 205, "1296th value should be 205"); -assertEq(view[1297], 255, "1297th value should be 255"); -assertEq(view[1298], 50, "1298th value should be 50"); -assertEq(view[1299], 255, "1299th value should be 255"); -assertEq(view[1300], 205, "1300th value should be 205"); -assertEq(view[1301], 255, "1301th value should be 255"); -assertEq(view[1302], 50, "1302th value should be 50"); -assertEq(view[1303], 255, "1303th value should be 255"); -assertEq(view[1304], 179, "1304th value should be 179"); -assertEq(view[1305], 127, "1305th value should be 127"); -assertEq(view[1306], 76, "1306th value should be 76"); -assertEq(view[1307], 255, "1307th value should be 255"); -assertEq(view[1308], 154, "1308th value should be 154"); -assertEq(view[1309], 255, "1309th value should be 255"); -assertEq(view[1310], 101, "1310th value should be 101"); -assertEq(view[1311], 255, "1311th value should be 255"); -assertEq(view[1312], 154, "1312th value should be 154"); -assertEq(view[1313], 255, "1313th value should be 255"); -assertEq(view[1314], 101, "1314th value should be 101"); -assertEq(view[1315], 255, "1315th value should be 255"); -assertEq(view[1316], 0, "1316th value should be 0"); -assertEq(view[1317], 0, "1317th value should be 0"); -assertEq(view[1318], 0, "1318th value should be 0"); -assertEq(view[1319], 255, "1319th value should be 255"); -assertEq(view[1320], 0, "1320th value should be 0"); -assertEq(view[1321], 0, "1321th value should be 0"); -assertEq(view[1322], 0, "1322th value should be 0"); -assertEq(view[1323], 255, "1323th value should be 255"); -assertEq(view[1324], 0, "1324th value should be 0"); -assertEq(view[1325], 0, "1325th value should be 0"); -assertEq(view[1326], 0, "1326th value should be 0"); -assertEq(view[1327], 255, "1327th value should be 255"); -assertEq(view[1328], 0, "1328th value should be 0"); -assertEq(view[1329], 0, "1329th value should be 0"); -assertEq(view[1330], 0, "1330th value should be 0"); -assertEq(view[1331], 255, "1331th value should be 255"); -assertEq(view[1332], 0, "1332th value should be 0"); -assertEq(view[1333], 0, "1333th value should be 0"); -assertEq(view[1334], 0, "1334th value should be 0"); -assertEq(view[1335], 255, "1335th value should be 255"); -assertEq(view[1336], 0, "1336th value should be 0"); -assertEq(view[1337], 0, "1337th value should be 0"); -assertEq(view[1338], 0, "1338th value should be 0"); -assertEq(view[1339], 255, "1339th value should be 255"); -assertEq(view[1340], 0, "1340th value should be 0"); -assertEq(view[1341], 0, "1341th value should be 0"); -assertEq(view[1342], 0, "1342th value should be 0"); -assertEq(view[1343], 255, "1343th value should be 255"); -assertEq(view[1344], 0, "1344th value should be 0"); -assertEq(view[1345], 0, "1345th value should be 0"); -assertEq(view[1346], 0, "1346th value should be 0"); -assertEq(view[1347], 255, "1347th value should be 255"); -assertEq(view[1348], 179, "1348th value should be 179"); -assertEq(view[1349], 127, "1349th value should be 127"); -assertEq(view[1350], 76, "1350th value should be 76"); -assertEq(view[1351], 255, "1351th value should be 255"); -assertEq(view[1352], 205, "1352th value should be 205"); -assertEq(view[1353], 255, "1353th value should be 255"); -assertEq(view[1354], 50, "1354th value should be 50"); -assertEq(view[1355], 255, "1355th value should be 255"); -assertEq(view[1356], 205, "1356th value should be 205"); -assertEq(view[1357], 255, "1357th value should be 255"); -assertEq(view[1358], 50, "1358th value should be 50"); -assertEq(view[1359], 255, "1359th value should be 255"); -assertEq(view[1360], 0, "1360th value should be 0"); -assertEq(view[1361], 0, "1361th value should be 0"); -assertEq(view[1362], 0, "1362th value should be 0"); -assertEq(view[1363], 255, "1363th value should be 255"); -assertEq(view[1364], 205, "1364th value should be 205"); -assertEq(view[1365], 255, "1365th value should be 255"); -assertEq(view[1366], 50, "1366th value should be 50"); -assertEq(view[1367], 255, "1367th value should be 255"); -assertEq(view[1368], 205, "1368th value should be 205"); -assertEq(view[1369], 255, "1369th value should be 255"); -assertEq(view[1370], 50, "1370th value should be 50"); -assertEq(view[1371], 255, "1371th value should be 255"); -assertEq(view[1372], 205, "1372th value should be 205"); -assertEq(view[1373], 255, "1373th value should be 255"); -assertEq(view[1374], 50, "1374th value should be 50"); -assertEq(view[1375], 255, "1375th value should be 255"); -assertEq(view[1376], 205, "1376th value should be 205"); -assertEq(view[1377], 255, "1377th value should be 255"); -assertEq(view[1378], 50, "1378th value should be 50"); -assertEq(view[1379], 255, "1379th value should be 255"); -assertEq(view[1380], 205, "1380th value should be 205"); -assertEq(view[1381], 255, "1381th value should be 255"); -assertEq(view[1382], 50, "1382th value should be 50"); -assertEq(view[1383], 255, "1383th value should be 255"); -assertEq(view[1384], 205, "1384th value should be 205"); -assertEq(view[1385], 255, "1385th value should be 255"); -assertEq(view[1386], 50, "1386th value should be 50"); -assertEq(view[1387], 255, "1387th value should be 255"); -assertEq(view[1388], 179, "1388th value should be 179"); -assertEq(view[1389], 127, "1389th value should be 127"); -assertEq(view[1390], 76, "1390th value should be 76"); -assertEq(view[1391], 255, "1391th value should be 255"); -assertEq(view[1392], 179, "1392th value should be 179"); -assertEq(view[1393], 127, "1393th value should be 127"); -assertEq(view[1394], 76, "1394th value should be 76"); -assertEq(view[1395], 255, "1395th value should be 255"); -assertEq(view[1396], 103, "1396th value should be 103"); -assertEq(view[1397], 255, "1397th value should be 255"); -assertEq(view[1398], 152, "1398th value should be 152"); -assertEq(view[1399], 255, "1399th value should be 255"); -assertEq(view[1400], 78, "1400th value should be 78"); -assertEq(view[1401], 127, "1401th value should be 127"); -assertEq(view[1402], 178, "1402th value should be 178"); -assertEq(view[1403], 255, "1403th value should be 255"); -assertEq(view[1404], 52, "1404th value should be 52"); -assertEq(view[1405], 255, "1405th value should be 255"); -assertEq(view[1406], 203, "1406th value should be 203"); -assertEq(view[1407], 255, "1407th value should be 255"); -assertEq(view[1408], 0, "1408th value should be 0"); -assertEq(view[1409], 0, "1409th value should be 0"); -assertEq(view[1410], 0, "1410th value should be 0"); -assertEq(view[1411], 255, "1411th value should be 255"); -assertEq(view[1412], 0, "1412th value should be 0"); -assertEq(view[1413], 0, "1413th value should be 0"); -assertEq(view[1414], 0, "1414th value should be 0"); -assertEq(view[1415], 255, "1415th value should be 255"); -assertEq(view[1416], 52, "1416th value should be 52"); -assertEq(view[1417], 255, "1417th value should be 255"); -assertEq(view[1418], 203, "1418th value should be 203"); -assertEq(view[1419], 255, "1419th value should be 255"); -assertEq(view[1420], 128, "1420th value should be 128"); -assertEq(view[1421], 127, "1421th value should be 127"); -assertEq(view[1422], 127, "1422th value should be 127"); -assertEq(view[1423], 255, "1423th value should be 255"); -assertEq(view[1424], 128, "1424th value should be 128"); -assertEq(view[1425], 127, "1425th value should be 127"); -assertEq(view[1426], 127, "1426th value should be 127"); -assertEq(view[1427], 255, "1427th value should be 255"); -assertEq(view[1428], 205, "1428th value should be 205"); -assertEq(view[1429], 255, "1429th value should be 255"); -assertEq(view[1430], 50, "1430th value should be 50"); -assertEq(view[1431], 255, "1431th value should be 255"); -assertEq(view[1432], 205, "1432th value should be 205"); -assertEq(view[1433], 255, "1433th value should be 255"); -assertEq(view[1434], 50, "1434th value should be 50"); -assertEq(view[1435], 255, "1435th value should be 255"); -assertEq(view[1436], 230, "1436th value should be 230"); -assertEq(view[1437], 127, "1437th value should be 127"); -assertEq(view[1438], 25, "1438th value should be 25"); -assertEq(view[1439], 255, "1439th value should be 255"); -assertEq(view[1440], 0, "1440th value should be 0"); -assertEq(view[1441], 0, "1441th value should be 0"); -assertEq(view[1442], 0, "1442th value should be 0"); -assertEq(view[1443], 255, "1443th value should be 255"); -assertEq(view[1444], 230, "1444th value should be 230"); -assertEq(view[1445], 127, "1445th value should be 127"); -assertEq(view[1446], 25, "1446th value should be 25"); -assertEq(view[1447], 255, "1447th value should be 255"); -assertEq(view[1448], 205, "1448th value should be 205"); -assertEq(view[1449], 255, "1449th value should be 255"); -assertEq(view[1450], 50, "1450th value should be 50"); -assertEq(view[1451], 255, "1451th value should be 255"); -assertEq(view[1452], 205, "1452th value should be 205"); -assertEq(view[1453], 255, "1453th value should be 255"); -assertEq(view[1454], 50, "1454th value should be 50"); -assertEq(view[1455], 255, "1455th value should be 255"); -assertEq(view[1456], 205, "1456th value should be 205"); -assertEq(view[1457], 255, "1457th value should be 255"); -assertEq(view[1458], 50, "1458th value should be 50"); -assertEq(view[1459], 255, "1459th value should be 255"); -assertEq(view[1460], 205, "1460th value should be 205"); -assertEq(view[1461], 255, "1461th value should be 255"); -assertEq(view[1462], 50, "1462th value should be 50"); -assertEq(view[1463], 255, "1463th value should be 255"); -assertEq(view[1464], 205, "1464th value should be 205"); -assertEq(view[1465], 255, "1465th value should be 255"); -assertEq(view[1466], 50, "1466th value should be 50"); -assertEq(view[1467], 255, "1467th value should be 255"); -assertEq(view[1468], 179, "1468th value should be 179"); -assertEq(view[1469], 127, "1469th value should be 127"); -assertEq(view[1470], 76, "1470th value should be 76"); -assertEq(view[1471], 255, "1471th value should be 255"); -assertEq(view[1472], 179, "1472th value should be 179"); -assertEq(view[1473], 127, "1473th value should be 127"); -assertEq(view[1474], 76, "1474th value should be 76"); -assertEq(view[1475], 255, "1475th value should be 255"); -assertEq(view[1476], 179, "1476th value should be 179"); -assertEq(view[1477], 127, "1477th value should be 127"); -assertEq(view[1478], 76, "1478th value should be 76"); -assertEq(view[1479], 255, "1479th value should be 255"); -assertEq(view[1480], 128, "1480th value should be 128"); -assertEq(view[1481], 127, "1481th value should be 127"); -assertEq(view[1482], 127, "1482th value should be 127"); -assertEq(view[1483], 255, "1483th value should be 255"); -assertEq(view[1484], 103, "1484th value should be 103"); -assertEq(view[1485], 255, "1485th value should be 255"); -assertEq(view[1486], 152, "1486th value should be 152"); -assertEq(view[1487], 255, "1487th value should be 255"); -assertEq(view[1488], 0, "1488th value should be 0"); -assertEq(view[1489], 0, "1489th value should be 0"); -assertEq(view[1490], 0, "1490th value should be 0"); -assertEq(view[1491], 255, "1491th value should be 255"); -assertEq(view[1492], 0, "1492th value should be 0"); -assertEq(view[1493], 0, "1493th value should be 0"); -assertEq(view[1494], 0, "1494th value should be 0"); -assertEq(view[1495], 255, "1495th value should be 255"); -assertEq(view[1496], 128, "1496th value should be 128"); -assertEq(view[1497], 127, "1497th value should be 127"); -assertEq(view[1498], 127, "1498th value should be 127"); -assertEq(view[1499], 255, "1499th value should be 255"); -assertEq(view[1500], 154, "1500th value should be 154"); -assertEq(view[1501], 255, "1501th value should be 255"); -assertEq(view[1502], 101, "1502th value should be 101"); -assertEq(view[1503], 255, "1503th value should be 255"); -assertEq(view[1504], 179, "1504th value should be 179"); -assertEq(view[1505], 127, "1505th value should be 127"); -assertEq(view[1506], 76, "1506th value should be 76"); -assertEq(view[1507], 255, "1507th value should be 255"); -assertEq(view[1508], 205, "1508th value should be 205"); -assertEq(view[1509], 255, "1509th value should be 255"); -assertEq(view[1510], 50, "1510th value should be 50"); -assertEq(view[1511], 255, "1511th value should be 255"); -assertEq(view[1512], 205, "1512th value should be 205"); -assertEq(view[1513], 255, "1513th value should be 255"); -assertEq(view[1514], 50, "1514th value should be 50"); -assertEq(view[1515], 255, "1515th value should be 255"); -assertEq(view[1516], 230, "1516th value should be 230"); -assertEq(view[1517], 127, "1517th value should be 127"); -assertEq(view[1518], 25, "1518th value should be 25"); -assertEq(view[1519], 255, "1519th value should be 255"); -assertEq(view[1520], 0, "1520th value should be 0"); -assertEq(view[1521], 0, "1521th value should be 0"); -assertEq(view[1522], 0, "1522th value should be 0"); -assertEq(view[1523], 255, "1523th value should be 255"); -assertEq(view[1524], 230, "1524th value should be 230"); -assertEq(view[1525], 127, "1525th value should be 127"); -assertEq(view[1526], 25, "1526th value should be 25"); -assertEq(view[1527], 255, "1527th value should be 255"); -assertEq(view[1528], 230, "1528th value should be 230"); -assertEq(view[1529], 127, "1529th value should be 127"); -assertEq(view[1530], 25, "1530th value should be 25"); -assertEq(view[1531], 255, "1531th value should be 255"); -assertEq(view[1532], 205, "1532th value should be 205"); -assertEq(view[1533], 255, "1533th value should be 255"); -assertEq(view[1534], 50, "1534th value should be 50"); -assertEq(view[1535], 255, "1535th value should be 255"); -assertEq(view[1536], 205, "1536th value should be 205"); -assertEq(view[1537], 255, "1537th value should be 255"); -assertEq(view[1538], 50, "1538th value should be 50"); -assertEq(view[1539], 255, "1539th value should be 255"); -assertEq(view[1540], 205, "1540th value should be 205"); -assertEq(view[1541], 255, "1541th value should be 255"); -assertEq(view[1542], 50, "1542th value should be 50"); -assertEq(view[1543], 255, "1543th value should be 255"); -assertEq(view[1544], 205, "1544th value should be 205"); -assertEq(view[1545], 255, "1545th value should be 255"); -assertEq(view[1546], 50, "1546th value should be 50"); -assertEq(view[1547], 255, "1547th value should be 255"); -assertEq(view[1548], 205, "1548th value should be 205"); -assertEq(view[1549], 255, "1549th value should be 255"); -assertEq(view[1550], 50, "1550th value should be 50"); -assertEq(view[1551], 255, "1551th value should be 255"); -assertEq(view[1552], 179, "1552th value should be 179"); -assertEq(view[1553], 127, "1553th value should be 127"); -assertEq(view[1554], 76, "1554th value should be 76"); -assertEq(view[1555], 255, "1555th value should be 255"); -assertEq(view[1556], 179, "1556th value should be 179"); -assertEq(view[1557], 127, "1557th value should be 127"); -assertEq(view[1558], 76, "1558th value should be 76"); -assertEq(view[1559], 255, "1559th value should be 255"); -assertEq(view[1560], 179, "1560th value should be 179"); -assertEq(view[1561], 127, "1561th value should be 127"); -assertEq(view[1562], 76, "1562th value should be 76"); -assertEq(view[1563], 255, "1563th value should be 255"); -assertEq(view[1564], 154, "1564th value should be 154"); -assertEq(view[1565], 255, "1565th value should be 255"); -assertEq(view[1566], 101, "1566th value should be 101"); -assertEq(view[1567], 255, "1567th value should be 255"); -assertEq(view[1568], 26, "1568th value should be 26"); -assertEq(view[1569], 127, "1569th value should be 127"); -assertEq(view[1570], 229, "1570th value should be 229"); -assertEq(view[1571], 255, "1571th value should be 255"); -assertEq(view[1572], 0, "1572th value should be 0"); -assertEq(view[1573], 0, "1573th value should be 0"); -assertEq(view[1574], 0, "1574th value should be 0"); -assertEq(view[1575], 255, "1575th value should be 255"); -assertEq(view[1576], 154, "1576th value should be 154"); -assertEq(view[1577], 255, "1577th value should be 255"); -assertEq(view[1578], 101, "1578th value should be 101"); -assertEq(view[1579], 255, "1579th value should be 255"); -assertEq(view[1580], 179, "1580th value should be 179"); -assertEq(view[1581], 127, "1581th value should be 127"); -assertEq(view[1582], 76, "1582th value should be 76"); -assertEq(view[1583], 255, "1583th value should be 255"); -assertEq(view[1584], 205, "1584th value should be 205"); -assertEq(view[1585], 255, "1585th value should be 255"); -assertEq(view[1586], 50, "1586th value should be 50"); -assertEq(view[1587], 255, "1587th value should be 255"); -assertEq(view[1588], 205, "1588th value should be 205"); -assertEq(view[1589], 255, "1589th value should be 255"); -assertEq(view[1590], 50, "1590th value should be 50"); -assertEq(view[1591], 255, "1591th value should be 255"); -assertEq(view[1592], 230, "1592th value should be 230"); -assertEq(view[1593], 127, "1593th value should be 127"); -assertEq(view[1594], 25, "1594th value should be 25"); -assertEq(view[1595], 255, "1595th value should be 255"); -assertEq(view[1596], 230, "1596th value should be 230"); -assertEq(view[1597], 127, "1597th value should be 127"); -assertEq(view[1598], 25, "1598th value should be 25"); -assertEq(view[1599], 255, "1599th value should be 255"); - -// Code used to generate the assertEq list above. -function generateAssertList() { - function template(i, x) { - return 'assertEq(view[' + i + '], ' + x + ', "' + i + 'th value should be ' + x + '");\n'; - } - var buf = '' - for (var i = 0; i < LIMIT_SHOW; i++) - buf += template(i, view[i]); - print(buf); -} -//generateAssertList(); diff --git a/js/src/jit-test/tests/asm.js/testAsmJSWasmMixing.js b/js/src/jit-test/tests/asm.js/testAsmJSWasmMixing.js index e82b3e4173..523c5ae4ab 100644 --- a/js/src/jit-test/tests/asm.js/testAsmJSWasmMixing.js +++ b/js/src/jit-test/tests/asm.js/testAsmJSWasmMixing.js @@ -13,13 +13,3 @@ asmLink(asmJS, this, null, asmJSBuf); var wasmMem = wasmEvalText('(module (memory 1 1) (export "mem" memory))').exports.mem; assertAsmLinkFail(asmJS, this, null, wasmMem.buffer); -if (!getBuildConfiguration().x64 && isSimdAvailable() && this["SIMD"]) { - var simdJS = asmCompile('stdlib', 'ffis', 'buf', USE_ASM + 'var i32 = new stdlib.Int32Array(buf); var i32x4 = stdlib.SIMD.Int32x4; return {}'); - assertAsmLinkFail(simdJS, this, null, asmJSBuf); - assertAsmLinkFail(simdJS, this, null, wasmMem.buffer); - - var simdJSBuf = new ArrayBuffer(BUF_MIN); - asmLink(simdJS, this, null, simdJSBuf); - asmLink(simdJS, this, null, simdJSBuf); // multiple SIMD.js instantiations succeed - assertAsmLinkFail(asmJS, this, null, simdJSBuf); // but not asm.js -} diff --git a/js/src/jit-test/tests/asm.js/testBug1099216.js b/js/src/jit-test/tests/asm.js/testBug1099216.js deleted file mode 100644 index 3514f307d5..0000000000 --- a/js/src/jit-test/tests/asm.js/testBug1099216.js +++ /dev/null @@ -1,61 +0,0 @@ -if (typeof SIMD === 'undefined' || !isSimdAvailable()) { - print("won't run tests as simd extensions aren't activated yet"); - quit(0); -} - -(function(global) { - "use asm"; - var frd = global.Math.fround; - var fx4 = global.SIMD.Float32x4; - var fc4 = fx4.check; - var fsp = fx4.splat; - function s(){} - function d(x){x=fc4(x);} - function e() { - var x = frd(0); - x = frd(x / x); - s(); - d(fsp(x)); - } - return e; -})(this)(); - -(function(m) { - "use asm" - var k = m.SIMD.Bool32x4 - var g = m.SIMD.Int32x4 - var gc = g.check; - var h = g.select - function f() { - var x = k(0, 0, 0, 0) - var y = g(1, 2, 3, 4) - return gc(h(x, y, y)) - } - return f; -})(this)(); - -t = (function(global) { - "use asm" - var toF = global.Math.fround - var f4 = global.SIMD.Float32x4 - var f4c = f4.check - function p(x, y, width, value, max_iterations) { - x = x | 0 - y = y | 0 - width = width | 0 - value = value | 0 - max_iterations = max_iterations | 0 - } - function m(xf, yf, yd, max_iterations) { - xf = toF(xf) - yf = toF(yf) - yd = toF(yd) - max_iterations = max_iterations | 0 - var _ = f4(0, 0, 0, 0), c_im4 = f4(0, 0, 0, 0) - c_im4 = f4(yf, yd, yd, yf) - return f4c(c_im4); - } - return {p:p,m:m}; -})(this) -t.p(); -t.m(); diff --git a/js/src/jit-test/tests/asm.js/testJumpRange.js b/js/src/jit-test/tests/asm.js/testJumpRange.js index bd983544bc..6e5f6200f5 100644 --- a/js/src/jit-test/tests/asm.js/testJumpRange.js +++ b/js/src/jit-test/tests/asm.js/testJumpRange.js @@ -18,26 +18,6 @@ for (let threshold of [0, 50, 100, 5000, -1]) { return h `)()(), 45); - if (isSimdAvailable() && this.SIMD) { - var buf = new ArrayBuffer(BUF_MIN); - new Int32Array(buf)[0] = 10; - new Float32Array(buf)[1] = 42; - assertEq(asmCompile('stdlib', 'ffis', 'buf', - USE_ASM + ` - var H = new stdlib.Uint8Array(buf); - var i4 = stdlib.SIMD.Int32x4; - var f4 = stdlib.SIMD.Float32x4; - var i4load = i4.load; - var f4load = f4.load; - var toi4 = i4.fromFloat32x4; - var i4ext = i4.extractLane; - function f(i) { i=i|0; return i4ext(i4load(H, i), 0)|0 } - function g(i) { i=i|0; return (i4ext(toi4(f4load(H, i)),1) + (f(i)|0))|0 } - function h(i) { i=i|0; return g(i)|0 } - return h - `)(this, null, buf)(0), 52); - } - enableSPSProfiling(); asmLink(asmCompile(USE_ASM + 'function f() {} function g() { f() } function h() { g() } return h'))(); disableSPSProfiling(); diff --git a/js/src/jit-test/tests/asm.js/testProfiling.js b/js/src/jit-test/tests/asm.js/testProfiling.js index 564f6f359b..97bca989a1 100644 --- a/js/src/jit-test/tests/asm.js/testProfiling.js +++ b/js/src/jit-test/tests/asm.js/testProfiling.js @@ -206,19 +206,6 @@ var stacks = disableSingleStepProfiling(); assertStackContainsSeq(stacks, ">,f1,>,<,f1,>,>,<,f1,>,f2,>,<,f1,>,<,f2,>,<,f1,>,f2,>,<,f1,>,>,<,f1,>,<,f1,>,f1,>,>"); -if (isSimdAvailable() && typeof SIMD !== 'undefined') { - // SIMD out-of-bounds exit - var buf = new ArrayBuffer(0x10000); - var f = asmLink(asmCompile('g','ffi','buf', USE_ASM + 'var f4=g.SIMD.float32x4; var f4l=f4.load; var u8=new g.Uint8Array(buf); function f(i) { i=i|0; return f4l(u8, 0xFFFF + i | 0); } return f'), this, {}, buf); - enableSingleStepProfiling(); - assertThrowsInstanceOf(() => f(4), RangeError); - var stacks = disableSingleStepProfiling(); - // TODO check that expected is actually the correctly expected string, when - // SIMD is implemented on ARM. - assertStackContainsSeq(stacks, ">,f,>,inline stub,f,>"); -} - - // Thunks setJitCompilerOption("jump-threshold", 0); var h = asmLink(asmCompile(USE_ASM + 'function f() {} function g() { f() } function h() { g() } return h')); diff --git a/js/src/jit-test/tests/asm.js/testSIMD-16x8.js b/js/src/jit-test/tests/asm.js/testSIMD-16x8.js deleted file mode 100644 index 6f017892ce..0000000000 --- a/js/src/jit-test/tests/asm.js/testSIMD-16x8.js +++ /dev/null @@ -1,510 +0,0 @@ -load(libdir + "asm.js"); -load(libdir + "simd.js"); -load(libdir + "asserts.js"); - -// Set to true to see more JS debugging spew. -const DEBUG = false; - -if (!isSimdAvailable()) { - DEBUG && print("won't run tests as simd extensions aren't activated yet"); - quit(0); -} - -// Tests for 16x8 SIMD types: Int16x8, Uint16x8, Bool16x8. - -const I16x8 = 'var i16x8 = glob.SIMD.Int16x8;' -const I16x8CHK = 'var i16x8chk = i16x8.check;' -const I16x8EXT = 'var i16x8ext = i16x8.extractLane;' -const I16x8REP = 'var i16x8rep = i16x8.replaceLane;' -const I16x8U16x8 = 'var i16x8u16x8 = i16x8.fromUint16x8Bits;' - -const U16x8 = 'var u16x8 = glob.SIMD.Uint16x8;' -const U16x8CHK = 'var u16x8chk = u16x8.check;' -const U16x8EXT = 'var u16x8ext = u16x8.extractLane;' -const U16x8REP = 'var u16x8rep = u16x8.replaceLane;' -const U16x8I16x8 = 'var u16x8i16x8 = u16x8.fromInt16x8Bits;' - -const B16x8 = 'var b16x8 = glob.SIMD.Bool16x8;' -const B16x8CHK = 'var b16x8chk = b16x8.check;' -const B16x8EXT = 'var b16x8ext = b16x8.extractLane;' -const B16x8REP = 'var b16x8rep = b16x8.replaceLane;' - -const INT16_MAX = 0x7fff -const INT16_MIN = -0x10000 -const UINT16_MAX = 0xffff - -// Linking -assertEq(asmLink(asmCompile('glob', USE_ASM + I16x8 + "function f() {} return f"), {SIMD:{Int16x8: SIMD.Int16x8}})(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + U16x8 + "function f() {} return f"), {SIMD:{Uint16x8: SIMD.Uint16x8}})(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + B16x8 + "function f() {} return f"), {SIMD:{Bool16x8: SIMD.Bool16x8}})(), undefined); - -// Local variable of Int16x8 type. -assertAsmTypeFail('glob', USE_ASM + "function f() {var x=Int16x8(1,2,3,4,5,6,7,8);} return f"); -assertAsmTypeFail('glob', USE_ASM + I16x8 + "function f() {var x=i16x8;} return f"); -assertAsmTypeFail('glob', USE_ASM + I16x8 + "function f() {var x=i16x8();} return f"); -assertAsmTypeFail('glob', USE_ASM + I16x8 + "function f() {var x=i16x8(1);} return f"); -assertAsmTypeFail('glob', USE_ASM + I16x8 + "function f() {var x=i16x8(1,2,3,4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I16x8 + "function f() {var x=i16x8(1,2,3,4,5,6,7,8.0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I16x8 + "function f() {var x=i16x8(1,2,3,4,5,6,7,8,9);} return f"); -assertAsmTypeFail('glob', USE_ASM + I16x8 + "function f() {var x=i16x8(1,2,3,4,5,6,7,8|0);} return f"); -assertEq(asmLink(asmCompile('glob', USE_ASM + I16x8 + "function f() {var x=i16x8(1,2,3,4,5,6,7,8);} return f"), this)(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + I16x8 + "function f() {var x=i16x8(1,2,3,4,5,6,7," + (INT16_MAX + 1) + ");} return f"), this)(), undefined); - -// Local variable of Uint16x8 type. -assertAsmTypeFail('glob', USE_ASM + "function f() {var x=Uint16x8(1,2,3,4,5,6,7,8);} return f"); -assertAsmTypeFail('glob', USE_ASM + U16x8 + "function f() {var x=u16x8;} return f"); -assertAsmTypeFail('glob', USE_ASM + U16x8 + "function f() {var x=u16x8();} return f"); -assertAsmTypeFail('glob', USE_ASM + U16x8 + "function f() {var x=u16x8(1);} return f"); -assertAsmTypeFail('glob', USE_ASM + U16x8 + "function f() {var x=u16x8(1,2,3,4);} return f"); -assertAsmTypeFail('glob', USE_ASM + U16x8 + "function f() {var x=u16x8(1,2,3,4,5,6,7,8.0);} return f"); -assertAsmTypeFail('glob', USE_ASM + U16x8 + "function f() {var x=u16x8(1,2,3,4,5,6,7,8,9);} return f"); -assertAsmTypeFail('glob', USE_ASM + U16x8 + "function f() {var x=u16x8(1,2,3,4,5,6,7,8|0);} return f"); -assertEq(asmLink(asmCompile('glob', USE_ASM + U16x8 + "function f() {var x=u16x8(1,2,3,4,5,6,7,8);} return f"), this)(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + U16x8 + "function f() {var x=u16x8(1,2,3,4,5,6,7," + (UINT16_MAX + 1) + ");} return f"), this)(), undefined); - -// Local variable of Bool16x8 type. -assertAsmTypeFail('glob', USE_ASM + "function f() {var x=Bool16x8(1,0,0,0, 0,0,0,0);} return f"); -assertAsmTypeFail('glob', USE_ASM + B16x8 + "function f() {var x=b16x8;} return f"); -assertAsmTypeFail('glob', USE_ASM + B16x8 + "function f() {var x=b16x8();} return f"); -assertAsmTypeFail('glob', USE_ASM + B16x8 + "function f() {var x=b16x8(1);} return f"); -assertAsmTypeFail('glob', USE_ASM + B16x8 + "function f() {var x=b16x8(1,0,0,0);} return f"); -assertAsmTypeFail('glob', USE_ASM + B16x8 + "function f() {var x=b16x8(1,0,0,0, 0,0,0,1.0);} return f"); -assertAsmTypeFail('glob', USE_ASM + B16x8 + "function f() {var x=b16x8(1,0,0,0, 0,0,0,0|0);} return f"); -assertAsmTypeFail('glob', USE_ASM + B16x8 + "function f() {var x=b16x8(1,0,0,0, 0,0,0,0, 1);} return f"); -assertEq(asmLink(asmCompile('glob', USE_ASM + B16x8 + "function f() {var x=b16x8(1,0,0,0, 0,-1,-2,0);} return f"), this)(), undefined); - -// Only signed Int16x8 allowed as return value. -assertEqVecArr(asmLink(asmCompile('glob', USE_ASM + I16x8 + "function f() {return i16x8(1,2,3,4,5,6,7,8);} return f"), this)(), - [1, 2, 3, 4, 5, 6, 7, 8]); -assertEqVecArr(asmLink(asmCompile('glob', USE_ASM + I16x8 + I16x8CHK + "function f() {return i16x8chk(i16x8(1,2,3,32771,5,6,7,8));} return f"), this)(), - [1, 2, 3, -32765, 5, 6, 7, 8]); -assertAsmTypeFail('glob', USE_ASM + U16x8 + "function f() {return u16x8(1,2,3,4,5,6,7,8);} return f"); -assertAsmTypeFail('glob', USE_ASM + U16x8 + U16x8CHK + "function f() {return u16x8chk(u16x8(1,2,3,4,5,6,7,8));} return f"); - -// Test splat. -function splat(x) { - let r = [] - for (let i = 0; i < 8; i++) - r.push(x); - return r -} - -splatB = asmLink(asmCompile('glob', USE_ASM + B16x8 + - 'var splat = b16x8.splat;' + - 'function f(x) { x = x|0; return splat(x); } return f'), this); -assertEqVecArr(splatB(true), splat(true)); -assertEqVecArr(splatB(false), splat(false)); - - -splatB0 = asmLink(asmCompile('glob', USE_ASM + B16x8 + - 'var splat = b16x8.splat;' + - 'function f() { var x = 0; return splat(x); } return f'), this); -assertEqVecArr(splatB0(), splat(false)); -splatB1 = asmLink(asmCompile('glob', USE_ASM + B16x8 + - 'var splat = b16x8.splat;' + - 'function f() { var x = 1; return splat(x); } return f'), this); -assertEqVecArr(splatB1(), splat(true)); - -splatI = asmLink(asmCompile('glob', USE_ASM + I16x8 + - 'var splat = i16x8.splat;' + - 'function f(x) { x = x|0; return splat(x); } return f'), this); -for (let x of [0, 1, -1, 0x12345, 0x1234, -1000, -1000000]) { - assertEqVecArr(splatI(x), splat(x << 16 >> 16)); -} - -splatIc = asmLink(asmCompile('glob', USE_ASM + I16x8 + - 'var splat = i16x8.splat;' + - 'function f() { var x = 100; return splat(x); } return f'), this); -assertEqVecArr(splatIc(), splat(100)) - -splatU = asmLink(asmCompile('glob', USE_ASM + U16x8 + I16x8 + I16x8U16x8 + - 'var splat = u16x8.splat;' + - 'function f(x) { x = x|0; return i16x8u16x8(splat(x)); } return f'), this); -for (let x of [0, 1, -1, 0x12345, 0x1234, -1000, -1000000]) { - assertEqVecArr(SIMD.Uint16x8.fromInt16x8Bits(splatI(x)), splat(x << 16 >>> 16)); -} - -splatUc = asmLink(asmCompile('glob', USE_ASM + U16x8 + I16x8 + I16x8U16x8 + - 'var splat = u16x8.splat;' + - 'function f() { var x = 200; return i16x8u16x8(splat(x)); } return f'), this); -assertEqVecArr(SIMD.Uint16x8.fromInt16x8Bits(splatUc()), splat(200)) - - -// Test extractLane. -// -// The lane index must be a literal int, and we generate different code for -// different lanes. -function extractI(a, i) { - return asmLink(asmCompile('glob', USE_ASM + I16x8 + I16x8EXT + - `function f() {var x=i16x8(${a.join(',')}); return i16x8ext(x, ${i})|0; } return f`), this)(); -} -a = [-1,2,-3,4,-5,6,-7,-8]; -for (var i = 0; i < 8; i++) - assertEq(extractI(a, i), a[i]); -a = a.map(x => -x); -for (var i = 0; i < 8; i++) - assertEq(extractI(a, i), a[i]); - -function extractU(a, i) { - return asmLink(asmCompile('glob', USE_ASM + U16x8 + U16x8EXT + - `function f() {var x=u16x8(${a.join(',')}); return u16x8ext(x, ${i})|0; } return f`), this)(); -} -a = [1,255,12,13,14,150,200,3]; -for (var i = 0; i < 8; i++) - assertEq(extractU(a, i), a[i]); -a = a.map(x => UINT16_MAX-x); -for (var i = 0; i < 8; i++) - assertEq(extractU(a, i), a[i]); - -function extractB(a, i) { - return asmLink(asmCompile('glob', USE_ASM + B16x8 + B16x8EXT + - `function f() {var x=b16x8(${a.join(',')}); return b16x8ext(x, ${i})|0; } return f`), this)(); -} -a = [1,1,0,1, 1,0,0,0]; -for (var i = 0; i < 8; i++) - assertEq(extractB(a, i), a[i]); -a = a.map(x => 1-x); -for (var i = 0; i < 8; i++) - assertEq(extractB(a, i), a[i]); - -// Test replaceLane. -function replaceI(a, i) { - return asmLink(asmCompile('glob', USE_ASM + I16x8 + I16x8REP + - `function f(v) {v=v|0; var x=i16x8(${a.join(',')}); return i16x8rep(x,${i},v); } return f`), this); -} -a = [-1,2,-3,4,-5,6,-7,-9]; -for (var i = 0; i < 8; i++) { - var f = replaceI(a, i); - var b = a.slice(0); - b[i] = -20; - assertEqVecArr(f(-20), b); -} - -function replaceU(a, i) { - return asmLink(asmCompile('glob', USE_ASM + U16x8 + U16x8REP + I16x8 + I16x8U16x8 + - `function f(v) {v=v|0; var x=u16x8(${a.join(',')}); return i16x8u16x8(u16x8rep(x,${i},v)); } return f`), this); -} -a = [65000-1,2,65000-3,4,65000-5,6,65000-7,65000-9]; -for (var i = 0; i < 8; i++) { - var rawf = replaceU(a, i); - var f = x => SIMD.Uint16x8.fromInt16x8Bits(rawf(x)) - var b = a.slice(0); - b[i] = 1000; - assertEqVecArr(f(1000), b); -} - -function replaceB(a, i) { - return asmLink(asmCompile('glob', USE_ASM + B16x8 + B16x8REP + - `function f(v) {v=v|0; var x=b16x8(${a.join(',')}); return b16x8rep(x,${i},v); } return f`), this); -} -a = [1,1,0,1,1,0,0,0]; -for (var i = 0; i < 8; i++) { - var f = replaceB(a, i); - var b = a.slice(0); - let v = 1 - a[i]; - b[i] = v; - assertEqVecArr(f(v), b.map(x => !!x)); -} - - -// Test select. -selectI = asmLink(asmCompile('glob', USE_ASM + I16x8 + B16x8 + B16x8CHK + - 'var select = i16x8.select;' + - 'var a = i16x8(-1,2,-3,4,-5, 6,-7, 8);' + - 'var b = i16x8( 5,6, 7,8, 9,10,11,12);' + - 'function f(x) { x = b16x8chk(x); return select(x, a, b); } return f'), this); -assertEqVecArr(selectI(SIMD.Bool16x8( 0,0, 1,0, 1,1, 1, 0)), - [ 5,6,-3,8,-5,6,-7,12]); - -selectU = asmLink(asmCompile('glob', USE_ASM + I16x8 + B16x8 + B16x8CHK + U16x8 + I16x8U16x8 + U16x8I16x8 + - 'var select = u16x8.select;' + - 'var a = i16x8(-1,2,-3,4,-5, 6,-7, 8);' + - 'var b = i16x8( 5,6, 7,8, 9,10,11,12);' + - 'function f(x) { x = b16x8chk(x); return i16x8u16x8(select(x, u16x8i16x8(a), u16x8i16x8(b))); } return f'), this); -assertEqVecArr(selectU(SIMD.Bool16x8( 0,0, 1,0, 1,1, 1, 0)), - [ 5,6,-3,8,-5,6,-7,12]); - -// Test swizzle. -function swizzle(vec, lanes) { - let r = []; - for (let i = 0; i < 8; i++) - r.push(vec[lanes[i]]); - return r; -} - -function swizzleI(lanes) { - let asm = asmLink(asmCompile('glob', USE_ASM + I16x8 + I16x8CHK + - 'var swz = i16x8.swizzle;' + - `function f(a) { a = i16x8chk(a); return swz(a, ${lanes.join()}); } return f`), this); - let a1 = [ -1,2, -3,0x8000,0x7f,6,-7, 8].map(x => x << 16 >> 16); - let a2 = [0x8000,2,0x8000,0x7fff, 0,0, 8,-9].map(x => x << 16 >> 16); - let v1 = SIMD.Int16x8(...a1); - let v2 = SIMD.Int16x8(...a2); - assertEqVecArr(asm(v1), swizzle(a1, lanes)); - assertEqVecArr(asm(v2), swizzle(a2, lanes)); -} - -swizzleI([3, 4, 7, 1, 4, 3, 1, 2]); -swizzleI([0, 0, 0, 0, 0, 0, 0, 0]); -swizzleI([7, 7, 7, 7, 7, 7, 7, 7]); - -function swizzleU(lanes) { - let asm = asmLink(asmCompile('glob', USE_ASM + I16x8 + I16x8CHK + U16x8 + U16x8I16x8 + I16x8U16x8 + - 'var swz = u16x8.swizzle;' + - `function f(a) { a = i16x8chk(a); return i16x8u16x8(swz(u16x8i16x8(a), ${lanes.join()})); } return f`), this); - let a1 = [ -1,2, -3,0x8000,0x7f,6,-7, 8].map(x => x << 16 >> 16); - let a2 = [0x8000,2,0x8000,0x7fff, 0,0, 8,-9].map(x => x << 16 >> 16); - let v1 = SIMD.Int16x8(...a1); - let v2 = SIMD.Int16x8(...a2); - assertEqVecArr(asm(v1), swizzle(a1, lanes)); - assertEqVecArr(asm(v2), swizzle(a2, lanes)); -} - -swizzleU([3, 4, 7, 1, 4, 3, 1, 2]); -swizzleU([0, 0, 0, 0, 0, 0, 0, 0]); -swizzleU([7, 7, 7, 7, 7, 7, 7, 7]); - -// Out-of-range lane indexes. -assertAsmTypeFail('glob', USE_ASM + I16x8 + 'var swz = i16x8.swizzle; ' + - 'function f() { var x=i16x8(0,0,0,0,0,0,0,0); swz(x,1,2,3,4,5,6,7,8); } return f'); -assertAsmTypeFail('glob', USE_ASM + U16x8 + 'var swz = u16x8.swizzle; ' + - 'function f() { var x=u16x8(0,0,0,0,0,0,0,0); swz(x,1,2,3,4,5,6,7,8); } return f'); -// Missing lane indexes. -assertAsmTypeFail('glob', USE_ASM + I16x8 + 'var swz = i16x8.swizzle; ' + - 'function f() { var x=i16x8(0,0,0,0,0,0,0,0); swz(x,1,2,3,4,5,6,7); } return f'); -assertAsmTypeFail('glob', USE_ASM + U16x8 + 'var swz = u16x8.swizzle; ' + - 'function f() { var x=u16x8(0,0,0,0,0,0,0,0); swz(x,1,2,3,4,5,6,7); } return f'); - - -// Test shuffle. -function shuffle(vec1, vec2, lanes) { - let r = []; - let vec = vec1.concat(vec2) - for (let i = 0; i < 8; i++) - r.push(vec[lanes[i]]); - return r; -} - -function shuffleI(lanes) { - let asm = asmLink(asmCompile('glob', USE_ASM + I16x8 + I16x8CHK + - 'var shuf = i16x8.shuffle;' + - `function f(a1, a2) { a1 = i16x8chk(a1); a2 = i16x8chk(a2); return shuf(a1, a2, ${lanes.join()}); } return f`), this); - let a1 = [ -1,2, -3,0x8000,0x7f,6,-7, 8].map(x => x << 16 >> 16); - let a2 = [0x8000,2,0x8000,0x7fff, 0,0, 8,-9].map(x => x << 16 >> 16); - let v1 = SIMD.Int16x8(...a1); - let v2 = SIMD.Int16x8(...a2); - assertEqVecArr(asm(v1, v2), shuffle(a1, a2, lanes)); -} - -function shuffleU(lanes) { - let asm = asmLink(asmCompile('glob', USE_ASM + I16x8 + I16x8CHK + U16x8 + U16x8I16x8 + I16x8U16x8 + - 'var shuf = u16x8.shuffle;' + - 'function f(a1, a2) { a1 = i16x8chk(a1); a2 = i16x8chk(a2); ' + - `return i16x8u16x8(shuf(u16x8i16x8(a1), u16x8i16x8(a2), ${lanes.join()})); } return f`), this); - let a1 = [ -1,2, -3,0x8000,0x7f,6,-7, 8].map(x => x << 16 >> 16); - let a2 = [0x8000,2,0x8000,0x7fff, 0,0, 8,-9].map(x => x << 16 >> 16); - let v1 = SIMD.Int16x8(...a1); - let v2 = SIMD.Int16x8(...a2); - assertEqVecArr(asm(v1, v2), shuffle(a1, a2, lanes)); -} - -shuffleI([0, 0, 0, 0, 0, 0, 0, 0]) -shuffleI([15, 15, 15, 15, 15, 15, 15, 15]) -shuffleI([6, 2, 0, 14, 6, 10, 11, 1]) - -shuffleU([7, 7, 7, 7, 7, 7, 7, 7]) -shuffleU([8, 15, 15, 15, 15, 15, 15, 15]) -shuffleU([6, 2, 0, 14, 6, 10, 11, 1]) - -// Test unary operators. -function unaryI(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + I16x8 + I16x8CHK + - `var fut = i16x8.${opname};` + - 'function f(v) { v = i16x8chk(v); return fut(v); } return f'), this); - let a = [65000-1,2,65000-3,4,65000-5,6,65000-7,65000-9]; - let v = SIMD.Int16x8(...a); - assertEqVecArr(simdfunc(v), a.map(lanefunc)); -} - -function unaryU(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + U16x8 + I16x8 + I16x8CHK + U16x8I16x8 + I16x8U16x8 + - `var fut = u16x8.${opname};` + - 'function f(v) { v = i16x8chk(v); return i16x8u16x8(fut(u16x8i16x8(v))); } return f'), this); - let a = [65000-1,2,65000-3,4,65000-5,6,65000-7,65000-9]; - let v = SIMD.Int16x8(...a); - assertEqVecArr(SIMD.Uint16x8.fromInt16x8Bits(simdfunc(v)), a.map(lanefunc)); -} - -function unaryB(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + B16x8 + B16x8CHK + - `var fut = b16x8.${opname};` + - 'function f(v) { v = b16x8chk(v); return fut(v); } return f'), this); - let a = [1,1,0,1,1,0,0,0]; - let v = SIMD.Bool16x8(...a); - assertEqVecArr(simdfunc(v), a.map(lanefunc)); -} - -unaryI('not', x => ~x << 16 >> 16); -unaryU('not', x => ~x << 16 >>> 16); -unaryB('not', x => !x); -unaryI('neg', x => -x << 16 >> 16); -unaryU('neg', x => -x << 16 >>> 16); - - -// Test binary operators. -function zipmap(a1, a2, f) { - assertEq(a1.length, a2.length); - let r = []; - for (var i = 0; i < a1.length; i++) - r.push(f(a1[i], a2[i])); - return r -} - -function binaryI(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + I16x8 + I16x8CHK + - `var fut = i16x8.${opname};` + - 'function f(v1, v2) { v1 = i16x8chk(v1); v2 = i16x8chk(v2); return fut(v1, v2); } return f'), this); - let a1 = [ -1,2, -3,0x8000,0x7f,6,-7, 8].map(x => x << 16 >> 16); - let a2 = [0x8000,2,0x8000,0x7fff, 0,0, 8,-9].map(x => x << 16 >> 16); - let ref = zipmap(a1, a2, lanefunc); - let v1 = SIMD.Int16x8(...a1); - let v2 = SIMD.Int16x8(...a2); - assertEqVecArr(simdfunc(v1, v2), ref); -} - -function binaryU(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + U16x8 + I16x8 + I16x8CHK + U16x8I16x8 + I16x8U16x8 + - `var fut = u16x8.${opname};` + - 'function f(v1, v2) { v1 = i16x8chk(v1); v2 = i16x8chk(v2); return i16x8u16x8(fut(u16x8i16x8(v1), u16x8i16x8(v2))); } return f'), this); - let a1 = [ -1,2, -3,0x8000,0x7f,6,-7, 8].map(x => x << 16 >>> 16); - let a2 = [0x8000,2,0x8000,0x7fff, 0,0, 8,-9].map(x => x << 16 >>> 16); - let ref = zipmap(a1, a2, lanefunc); - let v1 = SIMD.Int16x8(...a1); - let v2 = SIMD.Int16x8(...a2); - let res = SIMD.Uint16x8.fromInt16x8Bits(simdfunc(v1, v2)); - assertEqVecArr(res, ref); -} - -function binaryB(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + B16x8 + B16x8CHK + - `var fut = b16x8.${opname};` + - 'function f(v1, v2) { v1 = b16x8chk(v1); v2 = b16x8chk(v2); return fut(v1, v2); } return f'), this); - let a = [1,1,0,1,1,0,0,0]; - let v = SIMD.Bool16x8(...a); - assertEqVecArr(simdfunc(v), a.map(lanefunc)); -} - -binaryI('add', (x, y) => (x + y) << 16 >> 16); -binaryI('sub', (x, y) => (x - y) << 16 >> 16); -binaryI('mul', (x, y) => (x * y) << 16 >> 16); -binaryU('add', (x, y) => (x + y) << 16 >>> 16); -binaryU('sub', (x, y) => (x - y) << 16 >>> 16); -binaryU('mul', (x, y) => (x * y) << 16 >>> 16); - -binaryI('and', (x, y) => (x & y) << 16 >> 16); -binaryI('or', (x, y) => (x | y) << 16 >> 16); -binaryI('xor', (x, y) => (x ^ y) << 16 >> 16); -binaryU('and', (x, y) => (x & y) << 16 >>> 16); -binaryU('or', (x, y) => (x | y) << 16 >>> 16); -binaryU('xor', (x, y) => (x ^ y) << 16 >>> 16); - -function sat(x, lo, hi) { - if (x < lo) return lo; - if (x > hi) return hi; - return x -} -function isat(x) { return sat(x, -32768, 32767); } -function usat(x) { return sat(x, 0, 0xffff); } - -binaryI('addSaturate', (x, y) => isat(x + y)) -binaryI('subSaturate', (x, y) => isat(x - y)) -binaryU('addSaturate', (x, y) => usat(x + y)) -binaryU('subSaturate', (x, y) => usat(x - y)) - - -// Test shift operators. -function zip1map(a, s, f) { - return a.map(x => f(x, s)); -} - -function shiftI(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + I16x8 + I16x8CHK + - `var fut = i16x8.${opname};` + - 'function f(v, s) { v = i16x8chk(v); s = s|0; return fut(v, s); } return f'), this); - let a = [-1,2,-3,0x80,0x7f,6,0x8000,0x7fff]; - let v = SIMD.Int16x8(...a); - for (let s of [0, 1, 2, 6, 7, 8, 9, 10, 16, 255, -1, -8, -7, -1000]) { - let ref = zip1map(a, s, lanefunc); - // 1. Test dynamic shift amount. - assertEqVecArr(simdfunc(v, s), ref); - - // 2. Test constant shift amount. - let cstf = asmLink(asmCompile('glob', USE_ASM + I16x8 + I16x8CHK + - `var fut = i16x8.${opname};` + - `function f(v) { v = i16x8chk(v); return fut(v, ${s}); } return f`), this); - assertEqVecArr(cstf(v, s), ref); - } -} - -function shiftU(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + U16x8 + I16x8 + I16x8CHK + U16x8I16x8 + I16x8U16x8 + - `var fut = u16x8.${opname};` + - 'function f(v, s) { v = i16x8chk(v); s = s|0; return i16x8u16x8(fut(u16x8i16x8(v), s)); } return f'), this); - let a = [-1,2,-3,0x80,0x7f,6,0x8000,0x7fff]; - let v = SIMD.Int16x8(...a); - for (let s of [0, 1, 2, 6, 7, 8, 9, 10, 16, 255, -1, -8, -7, -1000]) { - let ref = zip1map(a, s, lanefunc); - // 1. Test dynamic shift amount. - assertEqVecArr(SIMD.Uint16x8.fromInt16x8Bits(simdfunc(v, s)), ref); - - // 2. Test constant shift amount. - let cstf = asmLink(asmCompile('glob', USE_ASM + U16x8 + I16x8 + I16x8CHK + U16x8I16x8 + I16x8U16x8 + - `var fut = u16x8.${opname};` + - `function f(v) { v = i16x8chk(v); return i16x8u16x8(fut(u16x8i16x8(v), ${s})); } return f`), this); - assertEqVecArr(SIMD.Uint16x8.fromInt16x8Bits(cstf(v, s)), ref); - } -} - -shiftI('shiftLeftByScalar', (x,s) => (x << (s & 15)) << 16 >> 16); -shiftU('shiftLeftByScalar', (x,s) => (x << (s & 15)) << 16 >>> 16); -shiftI('shiftRightByScalar', (x,s) => ((x << 16 >> 16) >> (s & 15)) << 16 >> 16); -shiftU('shiftRightByScalar', (x,s) => ((x << 16 >>> 16) >>> (s & 15)) << 16 >>> 16); - - -// Comparisons. -function compareI(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + I16x8 + I16x8CHK + - `var fut = i16x8.${opname};` + - 'function f(v1, v2) { v1 = i16x8chk(v1); v2 = i16x8chk(v2); return fut(v1, v2); } return f'), this); - let a1 = [ -1,2, -3,0x8000,0x7f,6,-7, 8].map(x => x << 16 >> 16); - let a2 = [0x8000,2,0x8000,0x7fff, 0,0, 8,-9].map(x => x << 16 >> 16); - let ref = zipmap(a1, a2, lanefunc); - let v1 = SIMD.Int16x8(...a1); - let v2 = SIMD.Int16x8(...a2); - assertEqVecArr(simdfunc(v1, v2), ref); -} - -function compareU(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + I16x8 + I16x8CHK + U16x8 + U16x8I16x8 + - `var fut = u16x8.${opname};` + - 'function f(v1, v2) { v1 = i16x8chk(v1); v2 = i16x8chk(v2); return fut(u16x8i16x8(v1), u16x8i16x8(v2)); } return f'), this); - let a1 = [ -1,2, -3,0x8000,0x7f,6,-7, 8].map(x => x << 16 >>> 16); - let a2 = [0x8000,2,0x8000,0x7fff, 0,0, 8,-9].map(x => x << 16 >>> 16); - let ref = zipmap(a1, a2, lanefunc); - let v1 = SIMD.Int16x8(...a1); - let v2 = SIMD.Int16x8(...a2); - assertEqVecArr(simdfunc(v1, v2), ref); -} - -compareI("equal", (x,y) => x == y); -compareU("equal", (x,y) => x == y); -compareI("notEqual", (x,y) => x != y); -compareU("notEqual", (x,y) => x != y); -compareI("lessThan", (x,y) => x < y); -compareU("lessThan", (x,y) => x < y); -compareI("lessThanOrEqual", (x,y) => x <= y); -compareU("lessThanOrEqual", (x,y) => x <= y); -compareI("greaterThan", (x,y) => x > y); -compareU("greaterThan", (x,y) => x > y); -compareI("greaterThanOrEqual", (x,y) => x >= y); -compareU("greaterThanOrEqual", (x,y) => x >= y); diff --git a/js/src/jit-test/tests/asm.js/testSIMD-8x16.js b/js/src/jit-test/tests/asm.js/testSIMD-8x16.js deleted file mode 100644 index 160da82a8e..0000000000 --- a/js/src/jit-test/tests/asm.js/testSIMD-8x16.js +++ /dev/null @@ -1,524 +0,0 @@ -load(libdir + "asm.js"); -load(libdir + "simd.js"); -load(libdir + "asserts.js"); - -// Set to true to see more JS debugging spew. -const DEBUG = false; - -if (!isSimdAvailable()) { - DEBUG && print("won't run tests as simd extensions aren't activated yet"); - quit(0); -} - -// Tests for 8x16 SIMD types: Int8x16, Uint8x16, Bool8x16. - -const I8x16 = 'var i8x16 = glob.SIMD.Int8x16;' -const I8x16CHK = 'var i8x16chk = i8x16.check;' -const I8x16EXT = 'var i8x16ext = i8x16.extractLane;' -const I8x16REP = 'var i8x16rep = i8x16.replaceLane;' -const I8x16U8x16 = 'var i8x16u8x16 = i8x16.fromUint8x16Bits;' - -const U8x16 = 'var u8x16 = glob.SIMD.Uint8x16;' -const U8x16CHK = 'var u8x16chk = u8x16.check;' -const U8x16EXT = 'var u8x16ext = u8x16.extractLane;' -const U8x16REP = 'var u8x16rep = u8x16.replaceLane;' -const U8x16I8x16 = 'var u8x16i8x16 = u8x16.fromInt8x16Bits;' - -const B8x16 = 'var b8x16 = glob.SIMD.Bool8x16;' -const B8x16CHK = 'var b8x16chk = b8x16.check;' -const B8x16EXT = 'var b8x16ext = b8x16.extractLane;' -const B8x16REP = 'var b8x16rep = b8x16.replaceLane;' - -const INT8_MAX = 127 -const INT8_MIN = -128 -const UINT8_MAX = 255 - -// Linking -assertEq(asmLink(asmCompile('glob', USE_ASM + I8x16 + "function f() {} return f"), {SIMD:{Int8x16: SIMD.Int8x16}})(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + U8x16 + "function f() {} return f"), {SIMD:{Uint8x16: SIMD.Uint8x16}})(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + B8x16 + "function f() {} return f"), {SIMD:{Bool8x16: SIMD.Bool8x16}})(), undefined); - -// Local variable of Int8x16 type. -assertAsmTypeFail('glob', USE_ASM + "function f() {var x=Int8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);} return f"); -assertAsmTypeFail('glob', USE_ASM + I8x16 + "function f() {var x=i8x16;} return f"); -assertAsmTypeFail('glob', USE_ASM + I8x16 + "function f() {var x=i8x16();} return f"); -assertAsmTypeFail('glob', USE_ASM + I8x16 + "function f() {var x=i8x16(1);} return f"); -assertAsmTypeFail('glob', USE_ASM + I8x16 + "function f() {var x=i8x16(1,2,3,4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I8x16 + "function f() {var x=i8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16.0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I8x16 + "function f() {var x=i8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17);} return f"); -assertAsmTypeFail('glob', USE_ASM + I8x16 + "function f() {var x=i8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16|0);} return f"); -assertEq(asmLink(asmCompile('glob', USE_ASM + I8x16 + "function f() {var x=i8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);} return f"), this)(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + I8x16 + "function f() {var x=i8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15," + (INT8_MAX + 1) + ");} return f"), this)(), undefined); - -// Local variable of Uint8x16 type. -assertAsmTypeFail('glob', USE_ASM + "function f() {var x=Uint8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);} return f"); -assertAsmTypeFail('glob', USE_ASM + U8x16 + "function f() {var x=u8x16;} return f"); -assertAsmTypeFail('glob', USE_ASM + U8x16 + "function f() {var x=u8x16();} return f"); -assertAsmTypeFail('glob', USE_ASM + U8x16 + "function f() {var x=u8x16(1);} return f"); -assertAsmTypeFail('glob', USE_ASM + U8x16 + "function f() {var x=u8x16(1,2,3,4);} return f"); -assertAsmTypeFail('glob', USE_ASM + U8x16 + "function f() {var x=u8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16.0);} return f"); -assertAsmTypeFail('glob', USE_ASM + U8x16 + "function f() {var x=u8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17);} return f"); -assertAsmTypeFail('glob', USE_ASM + U8x16 + "function f() {var x=u8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16|0);} return f"); -assertEq(asmLink(asmCompile('glob', USE_ASM + U8x16 + "function f() {var x=u8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);} return f"), this)(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + U8x16 + "function f() {var x=u8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15," + (UINT8_MAX + 1) + ");} return f"), this)(), undefined); - -// Local variable of Bool8x16 type. -assertAsmTypeFail('glob', USE_ASM + "function f() {var x=Bool8x16(1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1);} return f"); -assertAsmTypeFail('glob', USE_ASM + B8x16 + "function f() {var x=b8x16;} return f"); -assertAsmTypeFail('glob', USE_ASM + B8x16 + "function f() {var x=b8x16();} return f"); -assertAsmTypeFail('glob', USE_ASM + B8x16 + "function f() {var x=b8x16(1);} return f"); -assertAsmTypeFail('glob', USE_ASM + B8x16 + "function f() {var x=b8x16(1,0,0,0);} return f"); -assertAsmTypeFail('glob', USE_ASM + B8x16 + "function f() {var x=b8x16(1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1.0);} return f"); -assertAsmTypeFail('glob', USE_ASM + B8x16 + "function f() {var x=b8x16(1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1|0);} return f"); -assertAsmTypeFail('glob', USE_ASM + B8x16 + "function f() {var x=b8x16(1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1);} return f"); -assertEq(asmLink(asmCompile('glob', USE_ASM + B8x16 + "function f() {var x=b8x16(1,0,0,0,0,0,0,0,0,1,-1,2,-2,1,1,1);} return f"), this)(), undefined); - -// Only signed Int8x16 allowed as return value. -assertEqVecArr(asmLink(asmCompile('glob', USE_ASM + I8x16 + "function f() {return i8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);} return f"), this)(), - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); -assertEqVecArr(asmLink(asmCompile('glob', USE_ASM + I8x16 + I8x16CHK + "function f() {return i8x16chk(i8x16(1,2,3,132,5,6,7,8,9,10,11,12,13,14,15,16));} return f"), this)(), - [1, 2, 3, -124, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); -assertAsmTypeFail('glob', USE_ASM + U8x16 + "function f() {return u8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);} return f"); -assertAsmTypeFail('glob', USE_ASM + U8x16 + U8x16CHK + "function f() {return u8x16chk(u8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16));} return f"); - -// Test splat. -function splat(x) { - let r = [] - for (let i = 0; i < 16; i++) - r.push(x); - return r -} - -splatB = asmLink(asmCompile('glob', USE_ASM + B8x16 + - 'var splat = b8x16.splat;' + - 'function f(x) { x = x|0; return splat(x); } return f'), this); -assertEqVecArr(splatB(true), splat(true)); -assertEqVecArr(splatB(false), splat(false)); - - -splatB0 = asmLink(asmCompile('glob', USE_ASM + B8x16 + - 'var splat = b8x16.splat;' + - 'function f() { var x = 0; return splat(x); } return f'), this); -assertEqVecArr(splatB0(), splat(false)); -splatB1 = asmLink(asmCompile('glob', USE_ASM + B8x16 + - 'var splat = b8x16.splat;' + - 'function f() { var x = 1; return splat(x); } return f'), this); -assertEqVecArr(splatB1(), splat(true)); - -splatI = asmLink(asmCompile('glob', USE_ASM + I8x16 + - 'var splat = i8x16.splat;' + - 'function f(x) { x = x|0; return splat(x); } return f'), this); -for (let x of [0, 1, -1, 0x1234, 0x12, 1000, -1000000]) { - assertEqVecArr(splatI(x), splat(x << 24 >> 24)); -} - -splatIc = asmLink(asmCompile('glob', USE_ASM + I8x16 + - 'var splat = i8x16.splat;' + - 'function f() { var x = 100; return splat(x); } return f'), this); -assertEqVecArr(splatIc(), splat(100)) - -splatU = asmLink(asmCompile('glob', USE_ASM + U8x16 + I8x16 + I8x16U8x16 + - 'var splat = u8x16.splat;' + - 'function f(x) { x = x|0; return i8x16u8x16(splat(x)); } return f'), this); -for (let x of [0, 1, -1, 0x1234, 0x12, 1000, -1000000]) { - assertEqVecArr(SIMD.Uint8x16.fromInt8x16Bits(splatI(x)), splat(x << 24 >>> 24)); -} - -splatUc = asmLink(asmCompile('glob', USE_ASM + U8x16 + I8x16 + I8x16U8x16 + - 'var splat = u8x16.splat;' + - 'function f() { var x = 200; return i8x16u8x16(splat(x)); } return f'), this); -assertEqVecArr(SIMD.Uint8x16.fromInt8x16Bits(splatUc()), splat(200)) - - -// Test extractLane. -// -// The lane index must be a literal int, and we generate different code for -// different lanes. -function extractI(a, i) { - return asmLink(asmCompile('glob', USE_ASM + I8x16 + I8x16EXT + - `function f() {var x=i8x16(${a.join(',')}); return i8x16ext(x, ${i})|0; } return f`), this)(); -} -a = [-1,2,-3,4,-5,6,-7,8,-9,10,-11,12,-13,-14,-15,-16]; -for (var i = 0; i < 16; i++) - assertEq(extractI(a, i), a[i]); -a = a.map(x => -x); -for (var i = 0; i < 16; i++) - assertEq(extractI(a, i), a[i]); - -function extractU(a, i) { - return asmLink(asmCompile('glob', USE_ASM + U8x16 + U8x16EXT + - `function f() {var x=u8x16(${a.join(',')}); return u8x16ext(x, ${i})|0; } return f`), this)(); -} -a = [1,255,12,13,14,150,200,3,4,5,6,7,8,9,10,16]; -for (var i = 0; i < 16; i++) - assertEq(extractU(a, i), a[i]); -a = a.map(x => 255-x); -for (var i = 0; i < 16; i++) - assertEq(extractU(a, i), a[i]); - -function extractB(a, i) { - return asmLink(asmCompile('glob', USE_ASM + B8x16 + B8x16EXT + - `function f() {var x=b8x16(${a.join(',')}); return b8x16ext(x, ${i})|0; } return f`), this)(); -} -a = [1,1,0,1,1,0,0,0,1,1,1,1,0,0,0,1]; -for (var i = 0; i < 16; i++) - assertEq(extractB(a, i), a[i]); -a = a.map(x => 1-x); -for (var i = 0; i < 16; i++) - assertEq(extractB(a, i), a[i]); - -// Test replaceLane. -function replaceI(a, i) { - return asmLink(asmCompile('glob', USE_ASM + I8x16 + I8x16REP + - `function f(v) {v=v|0; var x=i8x16(${a.join(',')}); return i8x16rep(x,${i},v); } return f`), this); -} -a = [-1,2,-3,4,-5,6,-7,8,-9,10,-11,12,-13,-14,-15,-16]; -for (var i = 0; i < 16; i++) { - var f = replaceI(a, i); - var b = a.slice(0); - b[i] = -20; - assertEqVecArr(f(-20), b); -} - -function replaceU(a, i) { - return asmLink(asmCompile('glob', USE_ASM + U8x16 + U8x16REP + I8x16 + I8x16U8x16 + - `function f(v) {v=v|0; var x=u8x16(${a.join(',')}); x=u8x16rep(x,${i},v); return i8x16u8x16(x); } return f`), this); -} -a = [256-1,2,256-3,4,256-5,6,256-7,8,256-9,10,256-11,12,256-13,256-14,256-15,256-16]; -for (var i = 0; i < 16; i++) { - // Result returned as Int8x16, convert back. - var rawf = replaceU(a, i); - var f = x => SIMD.Uint8x16.fromInt8x16Bits(rawf(x)); - var b = a.slice(0); - b[i] = 100; - assertEqVecArr(f(100), b); -} - -function replaceB(a, i) { - return asmLink(asmCompile('glob', USE_ASM + B8x16 + B8x16REP + - `function f(v) {v=v|0; var x=b8x16(${a.join(',')}); return b8x16rep(x,${i},v); } return f`), this); -} -a = [1,1,0,1,1,0,0,0,1,1,1,1,0,0,0,1]; -for (var i = 0; i < 16; i++) { - var f = replaceB(a, i); - var b = a.slice(0); - v = 1 - a[i]; - b[i] = v; - assertEqVecArr(f(v), b.map(x => !!x)); -} - - -// Test select. -selectI = asmLink(asmCompile('glob', USE_ASM + I8x16 + B8x16 + B8x16CHK + - 'var select = i8x16.select;' + - 'var a = i8x16(-1,2,-3,4,-5, 6,-7, 8,-9,10,-11,12,-13,-14,-15,-16);' + - 'var b = i8x16( 5,6, 7,8, 9,10,11,12,13,14, 15,16,-77, 45, 32, 0);' + - 'function f(x) { x = b8x16chk(x); return select(x, a, b); } return f'), this); -assertEqVecArr(selectI(SIMD.Bool8x16( 0,0, 1,0, 1,1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1)), - [ 5,6,-3,8,-5,6,-7,12,-9,10,15,16,-13,-14,32,-16]); - -selectU = asmLink(asmCompile('glob', USE_ASM + I8x16 + B8x16 + B8x16CHK + U8x16 + I8x16U8x16 + U8x16I8x16 + - 'var select = u8x16.select;' + - 'var a = i8x16(-1,2,-3,4,-5, 6,-7, 8,-9,10,-11,12,-13,-14,-15,-16);' + - 'var b = i8x16( 5,6, 7,8, 9,10,11,12,13,14, 15,16,-77, 45, 32, 0);' + - 'function f(x) { x = b8x16chk(x); return i8x16u8x16(select(x, u8x16i8x16(a), u8x16i8x16(b))); } return f'), this); -assertEqVecArr(selectU(SIMD.Bool8x16( 0,0, 1,0, 1,1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1)), - [ 5,6,-3,8,-5,6,-7,12,-9,10,15,16,-13,-14,32,-16]); - - -// Test swizzle. -function swizzle(vec, lanes) { - let r = []; - for (let i = 0; i < 16; i++) - r.push(vec[lanes[i]]); - return r; -} - -function swizzleI(lanes) { - let asm = asmLink(asmCompile('glob', USE_ASM + I8x16 + I8x16CHK + - 'var swz = i8x16.swizzle;' + - `function f(a) { a = i8x16chk(a); return swz(a, ${lanes.join()}); } return f`), this); - let a1 = [ -1,2, -3,-128,0x7f,6,-7, 8,-9, 10,-11, 12,-13,-14,-15, -16]; - let a2 = [-128,2,-128,0x7f, 0,0, 8,-9,10,-11, 12,-13,-14,-15,-16, -1]; - let v1 = SIMD.Int8x16(...a1); - let v2 = SIMD.Int8x16(...a2); - assertEqVecArr(asm(v1), swizzle(a1, lanes)); - assertEqVecArr(asm(v2), swizzle(a2, lanes)); -} - -swizzleI([10, 1, 7, 5, 1, 2, 6, 8, 5, 13, 0, 6, 2, 8, 0, 9]); -swizzleI([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); -swizzleI([15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15]); - -function swizzleU(lanes) { - let asm = asmLink(asmCompile('glob', USE_ASM + I8x16 + I8x16CHK + U8x16 + U8x16I8x16 + I8x16U8x16 + - 'var swz = u8x16.swizzle;' + - `function f(a) { a = i8x16chk(a); return i8x16u8x16(swz(u8x16i8x16(a), ${lanes.join()})); } return f`), this); - let a1 = [ -1,2, -3,-128,0x7f,6,-7, 8,-9, 10,-11, 12,-13,-14,-15, -16]; - let a2 = [-128,2,-128,0x7f, 0,0, 8,-9,10,-11, 12,-13,-14,-15,-16, -1]; - let v1 = SIMD.Int8x16(...a1); - let v2 = SIMD.Int8x16(...a2); - assertEqVecArr(asm(v1), swizzle(a1, lanes)); - assertEqVecArr(asm(v2), swizzle(a2, lanes)); -} - -swizzleU([10, 1, 7, 5, 1, 2, 6, 8, 5, 13, 0, 6, 2, 8, 0, 9]); -swizzleU([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); -swizzleU([15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15]); - -// Out-of-range lane indexes. -assertAsmTypeFail('glob', USE_ASM + I8x16 + 'var swz = i8x16.swizzle; ' + - 'function f() { var x=i8x16(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); swz(x,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16); } return f'); -assertAsmTypeFail('glob', USE_ASM + U8x16 + 'var swz = u8x16.swizzle; ' + - 'function f() { var x=u8x16(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); swz(x,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16); } return f'); -// Missing lane indexes. -assertAsmTypeFail('glob', USE_ASM + I8x16 + 'var swz = i8x16.swizzle; ' + - 'function f() { var x=i8x16(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); swz(x,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); } return f'); -assertAsmTypeFail('glob', USE_ASM + U8x16 + 'var swz = u8x16.swizzle; ' + - 'function f() { var x=u8x16(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); swz(x,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); } return f'); - - -// Test shuffle. -function shuffle(vec1, vec2, lanes) { - let r = []; - let vec = vec1.concat(vec2); - for (let i = 0; i < 16; i++) - r.push(vec[lanes[i]]); - return r; -} - -function shuffleI(lanes) { - let asm = asmLink(asmCompile('glob', USE_ASM + I8x16 + I8x16CHK + - 'var shuf = i8x16.shuffle;' + - `function f(a1, a2) { a1 = i8x16chk(a1); a2 = i8x16chk(a2); return shuf(a1, a2, ${lanes.join()}); } return f`), this); - let a1 = [ -1,2, -3,-128,0x7f,6,-7, 8,-9, 10,-11, 12,-13,-14,-15, -16]; - let a2 = [-128,2,-128,0x7f, 0,0, 8,-9,10,-11, 12,-13,-14,-15,-16, -1]; - let v1 = SIMD.Int8x16(...a1); - let v2 = SIMD.Int8x16(...a2); - assertEqVecArr(asm(v1, v2), shuffle(a1, a2, lanes)); -} - -shuffleI([31, 9, 5, 4, 29, 12, 19, 10, 16, 22, 10, 9, 6, 18, 9, 8]); -shuffleI([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); -shuffleI([31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31]); - -function shuffleU(lanes) { - let asm = asmLink(asmCompile('glob', USE_ASM + I8x16 + I8x16CHK + U8x16 + U8x16I8x16 + I8x16U8x16 + - 'var shuf = u8x16.shuffle;' + - 'function f(a1, a2) { a1 = i8x16chk(a1); a2 = i8x16chk(a2); ' + - `return i8x16u8x16(shuf(u8x16i8x16(a1), u8x16i8x16(a2), ${lanes.join()})); } return f`), this); - let a1 = [ -1,2, -3,-128,0x7f,6,-7, 8,-9, 10,-11, 12,-13,-14,-15, -16]; - let a2 = [-128,2,-128,0x7f, 0,0, 8,-9,10,-11, 12,-13,-14,-15,-16, -1]; - let v1 = SIMD.Int8x16(...a1); - let v2 = SIMD.Int8x16(...a2); - assertEqVecArr(asm(v1, v2), shuffle(a1, a2, lanes)); -} - -shuffleU([31, 9, 5, 4, 29, 12, 19, 10, 16, 22, 10, 9, 6, 18, 9, 8]); -shuffleU([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); -shuffleU([31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31]); - - -// Out-of-range lane indexes. -assertAsmTypeFail('glob', USE_ASM + I8x16 + 'var shuf = i8x16.shuffle; ' + - 'function f() { var x=i8x16(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); shuf(x,x,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,32); } return f'); -assertAsmTypeFail('glob', USE_ASM + U8x16 + 'var shuf = u8x16.shuffle; ' + - 'function f() { var x=u8x16(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); shuf(x,x,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,32); } return f'); -// Missing lane indexes. -assertAsmTypeFail('glob', USE_ASM + I8x16 + 'var shuf = i8x16.shuffle; ' + - 'function f() { var x=i8x16(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); shuf(x,x,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); } return f'); -assertAsmTypeFail('glob', USE_ASM + U8x16 + 'var shuf = u8x16.shuffle; ' + - 'function f() { var x=u8x16(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); shuf(x,x,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); } return f'); - - -// Test unary operators. -function unaryI(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + I8x16 + I8x16CHK + - `var fut = i8x16.${opname};` + - 'function f(v) { v = i8x16chk(v); return fut(v); } return f'), this); - let a = [-1,2,-3,4,-5,6,-7,8,-9,10,-11,12,-13,-14,-15,-16]; - let v = SIMD.Int8x16(...a); - assertEqVecArr(simdfunc(v), a.map(lanefunc)); -} - -function unaryU(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + U8x16 + I8x16 + I8x16CHK + U8x16I8x16 + I8x16U8x16 + - `var fut = u8x16.${opname};` + - 'function f(v) { v = i8x16chk(v); return i8x16u8x16(fut(u8x16i8x16(v))); } return f'), this); - let a = [256-1,2,256-3,4,256-5,6,256-7,8,256-9,10,256-11,12,256-13,256-14,256-15,256-16]; - let v = SIMD.Int8x16(...a); - assertEqVecArr(SIMD.Uint8x16.fromInt8x16Bits(simdfunc(v)), a.map(lanefunc)); -} - -function unaryB(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + B8x16 + B8x16CHK + - `var fut = b8x16.${opname};` + - 'function f(v) { v = b8x16chk(v); return fut(v); } return f'), this); - let a = [1,1,0,1,1,0,0,0,1,1,1,1,0,0,0,1]; - let v = SIMD.Bool8x16(...a); - assertEqVecArr(simdfunc(v), a.map(lanefunc)); -} - -unaryI('not', x => ~x << 24 >> 24); -unaryU('not', x => ~x << 24 >>> 24); -unaryB('not', x => !x); -unaryI('neg', x => -x << 24 >> 24); -unaryU('neg', x => -x << 24 >>> 24); - - -// Test binary operators. -function zipmap(a1, a2, f) { - assertEq(a1.length, a2.length); - let r = []; - for (var i = 0; i < a1.length; i++) - r.push(f(a1[i], a2[i])); - return r -} - -function binaryI(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + I8x16 + I8x16CHK + - `var fut = i8x16.${opname};` + - 'function f(v1, v2) { v1 = i8x16chk(v1); v2 = i8x16chk(v2); return fut(v1, v2); } return f'), this); - let a1 = [ -1,2, -3,-128,0x7f,6,-7, 8,-9, 10,-11, 12,-13,-14,-15, -16]; - let a2 = [-128,2,-128,0x7f, 0,0, 8,-9,10,-11, 12,-13,-14,-15,-16, -1]; - let ref = zipmap(a1, a2, lanefunc); - let v1 = SIMD.Int8x16(...a1); - let v2 = SIMD.Int8x16(...a2); - assertEqVecArr(simdfunc(v1, v2), ref); -} - -function binaryU(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + U8x16 + I8x16 + I8x16CHK + U8x16I8x16 + I8x16U8x16 + - `var fut = u8x16.${opname};` + - 'function f(v1, v2) { v1 = i8x16chk(v1); v2 = i8x16chk(v2); return i8x16u8x16(fut(u8x16i8x16(v1), u8x16i8x16(v2))); } return f'), this); - let a1 = [ -1,2, -3,0x80,0x7f,6,-7, 8,-9, 10,-11, 12,-13,-14,-15, -16].map(x => x & 0xff); - let a2 = [0x80,2,0x80,0x7f, 0,0, 8,-9,10,-11, 12,-13,-14,-15,-16,0xff].map(x => x & 0xff); - let ref = zipmap(a1, a2, lanefunc); - let v1 = SIMD.Int8x16(...a1); - let v2 = SIMD.Int8x16(...a2); - let res = SIMD.Uint8x16.fromInt8x16Bits(simdfunc(v1, v2)); - assertEqVecArr(res, ref); -} - -function binaryB(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + B8x16 + B8x16CHK + - `var fut = b8x16.${opname};` + - 'function f(v1, v2) { v1 = b8x16chk(v1); v2 = b8x16chk(v2); return fut(v1, v2); } return f'), this); - let a = [1,1,0,1,1,0,0,0,1,1,1,1,0,0,0,1]; - let v = SIMD.Bool8x16(...a); - assertEqVecArr(simdfunc(v), a.map(lanefunc)); -} - -binaryI('add', (x, y) => (x + y) << 24 >> 24); -binaryI('sub', (x, y) => (x - y) << 24 >> 24); -binaryI('mul', (x, y) => (x * y) << 24 >> 24); -binaryU('add', (x, y) => (x + y) << 24 >>> 24); -binaryU('sub', (x, y) => (x - y) << 24 >>> 24); -binaryU('mul', (x, y) => (x * y) << 24 >>> 24); - -binaryI('and', (x, y) => (x & y) << 24 >> 24); -binaryI('or', (x, y) => (x | y) << 24 >> 24); -binaryI('xor', (x, y) => (x ^ y) << 24 >> 24); -binaryU('and', (x, y) => (x & y) << 24 >>> 24); -binaryU('or', (x, y) => (x | y) << 24 >>> 24); -binaryU('xor', (x, y) => (x ^ y) << 24 >>> 24); - -function sat(x, lo, hi) { - if (x < lo) return lo; - if (x > hi) return hi; - return x -} -function isat(x) { return sat(x, -128, 127); } -function usat(x) { return sat(x, 0, 255); } - -binaryI('addSaturate', (x, y) => isat(x + y)) -binaryI('subSaturate', (x, y) => isat(x - y)) -binaryU('addSaturate', (x, y) => usat(x + y)) -binaryU('subSaturate', (x, y) => usat(x - y)) - -// Test shift operators. -function zip1map(a, s, f) { - return a.map(x => f(x, s)); -} - -function shiftI(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + I8x16 + I8x16CHK + - `var fut = i8x16.${opname};` + - 'function f(v, s) { v = i8x16chk(v); s = s|0; return fut(v, s); } return f'), this); - let a = [0x80,2,0x80,0x7f, 0,0, 8,-9,10,-11, 12,-13,-14,-15,-16,0xff]; - let v = SIMD.Int8x16(...a); - for (let s of [0, 1, 2, 6, 7, 8, 9, 10, 16, 255, -1, -8, -7, -1000]) { - let ref = zip1map(a, s, lanefunc); - // 1. Test dynamic shift amount. - assertEqVecArr(simdfunc(v, s), ref); - - // 2. Test constant shift amount. - let cstf = asmLink(asmCompile('glob', USE_ASM + I8x16 + I8x16CHK + - `var fut = i8x16.${opname};` + - `function f(v) { v = i8x16chk(v); return fut(v, ${s}); } return f`), this); - assertEqVecArr(cstf(v, s), ref); - } -} - -function shiftU(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + U8x16 + I8x16 + I8x16CHK + U8x16I8x16 + I8x16U8x16 + - `var fut = u8x16.${opname};` + - 'function f(v, s) { v = i8x16chk(v); s = s|0; return i8x16u8x16(fut(u8x16i8x16(v), s)); } return f'), this); - let a = [0x80,2,0x80,0x7f, 0,0, 8,-9,10,-11, 12,-13,-14,-15,-16,0xff]; - let v = SIMD.Int8x16(...a); - for (let s of [0, 1, 2, 6, 7, 8, 9, 10, 16, 255, -1, -8, -7, -1000]) { - let ref = zip1map(a, s, lanefunc); - // 1. Test dynamic shift amount. - assertEqVecArr(SIMD.Uint8x16.fromInt8x16Bits(simdfunc(v, s)), ref); - - // 2. Test constant shift amount. - let cstf = asmLink(asmCompile('glob', USE_ASM + U8x16 + I8x16 + I8x16CHK + U8x16I8x16 + I8x16U8x16 + - `var fut = u8x16.${opname};` + - `function f(v) { v = i8x16chk(v); return i8x16u8x16(fut(u8x16i8x16(v), ${s})); } return f`), this); - assertEqVecArr(SIMD.Uint8x16.fromInt8x16Bits(cstf(v, s)), ref); - } -} - -shiftI('shiftLeftByScalar', (x,s) => (x << (s & 7)) << 24 >> 24); -shiftU('shiftLeftByScalar', (x,s) => (x << (s & 7)) << 24 >>> 24); -shiftI('shiftRightByScalar', (x,s) => ((x << 24 >> 24) >> (s & 7)) << 24 >> 24); -shiftU('shiftRightByScalar', (x,s) => ((x << 24 >>> 24) >>> (s & 7)) << 24 >>> 24); - - -// Comparisons. -function compareI(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + I8x16 + I8x16CHK + - `var fut = i8x16.${opname};` + - 'function f(v1, v2) { v1 = i8x16chk(v1); v2 = i8x16chk(v2); return fut(v1, v2); } return f'), this); - let a1 = [ -1,2, -3,-128,0x7f,6,-7, 8,-9, 10,-11, 12,-13,-14,-15, -16]; - let a2 = [-128,2,-128,0x7f, 0,0, 8,-9,10,-11, 12,-13,-14,-15,-16, -1]; - let ref = zipmap(a1, a2, lanefunc); - let v1 = SIMD.Int8x16(...a1); - let v2 = SIMD.Int8x16(...a2); - assertEqVecArr(simdfunc(v1, v2), ref); -} - -function compareU(opname, lanefunc) { - let simdfunc = asmLink(asmCompile('glob', USE_ASM + I8x16 + I8x16CHK + U8x16 + U8x16I8x16 + - `var fut = u8x16.${opname};` + - 'function f(v1, v2) { v1 = i8x16chk(v1); v2 = i8x16chk(v2); return fut(u8x16i8x16(v1), u8x16i8x16(v2)); } return f'), this); - let a1 = [ -1,2, -3,-128,0x7f,6,-7, 8,-9, 10,-11, 12,-13,-14,-15, -16].map(x => x << 24 >>> 24); - let a2 = [-128,2,-128,0x7f, 0,0, 8,-9,10,-11, 12,-13,-14,-15,-16, -1].map(x => x << 24 >>> 24); - let ref = zipmap(a1, a2, lanefunc); - let v1 = SIMD.Int8x16(...a1); - let v2 = SIMD.Int8x16(...a2); - assertEqVecArr(simdfunc(v1, v2), ref); -} - -compareI("equal", (x,y) => x == y); -compareU("equal", (x,y) => x == y); -compareI("notEqual", (x,y) => x != y); -compareU("notEqual", (x,y) => x != y); -compareI("lessThan", (x,y) => x < y); -compareU("lessThan", (x,y) => x < y); -compareI("lessThanOrEqual", (x,y) => x <= y); -compareU("lessThanOrEqual", (x,y) => x <= y); -compareI("greaterThan", (x,y) => x > y); -compareU("greaterThan", (x,y) => x > y); -compareI("greaterThanOrEqual", (x,y) => x >= y); -compareU("greaterThanOrEqual", (x,y) => x >= y); diff --git a/js/src/jit-test/tests/asm.js/testSIMD-bitcasts.js b/js/src/jit-test/tests/asm.js/testSIMD-bitcasts.js deleted file mode 100644 index c5a5fb2bca..0000000000 --- a/js/src/jit-test/tests/asm.js/testSIMD-bitcasts.js +++ /dev/null @@ -1,84 +0,0 @@ -load(libdir + "asm.js"); -load(libdir + "simd.js"); -load(libdir + "asserts.js"); - -// Set to true to see more JS debugging spew. -const DEBUG = false; - -if (!isSimdAvailable()) { - DEBUG && print("won't run tests as simd extensions aren't activated yet"); - quit(0); -} - -// Test all bit-casts and normal loads and stores. -var heap = new ArrayBuffer(BUF_MIN); -var asU8 = new Uint8Array(heap); -var allTypes = [ - "Int8x16", - "Int16x8", - "Int32x4", - "Uint8x16", - "Uint16x8", - "Uint32x4", - "Float32x4" -]; - -// Generate a load bit-cast store test function that performs: -// -// function f(a, b) { -// vec = src.load(H, a); -// cast = dst.from«src»Bits(vec); -// store(H, b, cast); -// } -// -// Here, `H` is the heap provided by `heap`. -function test_func(src, dst) { - text = ` - "use asm"; - var src = glob.SIMD.${src}; - var dst = glob.SIMD.${dst}; - var ld = src.load; - var st = dst.store; - var bc = dst.from${src}Bits; - - var H = new glob.Uint8Array(heap); - - function f(a, b) { - a = a|0; - b = b|0; - - st(H, b, bc(ld(H, a))); - } - - return f; - `; - return asmLink(asmCompile('glob', 'ffi', 'heap', text), this, null, heap); -} - -function assertBuf16(a, b) { - for (let i=0; i < 16; i++) { - assertEq(asU8[a+i], asU8[b+i]); - } -} - -for (let src of allTypes) { - for (let dst of allTypes) { - // Skip identity conversions. - if (src == dst) continue; - - print(src, dst); - let f = test_func(src, dst); - // Initialize with pseudo-random data. - for (let i = 0; i < 64; i++) { - asU8[i] = (i + 17) * 97; - } - - // Aligned load/store. - f(0, 16); - assertBuf16(0, 16); - - // Unaligned access. - f(1, 27); - assertBuf16(1, 27); - } -} diff --git a/js/src/jit-test/tests/asm.js/testSIMD-load-store.js b/js/src/jit-test/tests/asm.js/testSIMD-load-store.js deleted file mode 100644 index d826c106ba..0000000000 --- a/js/src/jit-test/tests/asm.js/testSIMD-load-store.js +++ /dev/null @@ -1,457 +0,0 @@ -// |jit-test| -load(libdir + "asm.js"); -load(libdir + "simd.js"); -load(libdir + "asserts.js"); - -// Avoid pathological --ion-eager compile times due to bails in loops -setJitCompilerOption('ion.warmup.trigger', 1000000); - -// Set to true to see more JS debugging spew -const DEBUG = false; - -if (!isSimdAvailable() || typeof SIMD === 'undefined' || !isAsmJSCompilationAvailable()) { - DEBUG && print("won't run tests as simd extensions aren't activated yet"); - quit(0); -} - -const RuntimeError = WebAssembly.RuntimeError; - -const INT32_MAX = Math.pow(2, 31) - 1; -const INT32_MIN = INT32_MAX + 1 | 0; - -try { - -// Load / Store -var IMPORTS = USE_ASM + 'var H=new glob.Uint8Array(heap); var i4=glob.SIMD.Int32x4; var ci4=i4.check; var load=i4.load; var store=i4.store;'; - -// Bad number of args -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){load();} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){load(3);} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){load(3, 4, 5);} return f"); - -// Bad type of args -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){load(3, 5);} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){load(H, 5.0);} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){var i=0.;load(H, i);} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "var H2=new glob.Int32Array(heap); function f(){var i=0;load(H2, i)} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "var H2=42; function f(){var i=0;load(H2, i)} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){var i=0;load(H2, i)} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "var f4=glob.SIMD.Float32x4; function f(){var i=0;var vec=f4(1,2,3,4); store(H, i, vec)} return f"); - -// Bad coercions of returned values -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){var i=0;return load(H, i)|0;} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){var i=0;return +load(H, i);} return f"); - -// Literal index constants -var buf = new ArrayBuffer(BUF_MIN); -var SIZE_TA = BUF_MIN >> 2 -var asI32 = new Int32Array(buf); -asI32[SIZE_TA - 4] = 4; -asI32[SIZE_TA - 3] = 3; -asI32[SIZE_TA - 2] = 2; -asI32[SIZE_TA - 1] = 1; - -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){load(H, -1);} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){load(H, " + (INT32_MAX + 1) + ");} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){load(H, " + (INT32_MAX + 1 - 15) + ");} return f"); -asmCompile('glob', 'ffi', 'heap', IMPORTS + "function f(){load(H, " + (INT32_MAX + 1 - 16) + ");} return f"); - -assertAsmLinkFail(asmCompile('glob', 'ffi', 'heap', IMPORTS + "function f() {return ci4(load(H, " + (BUF_MIN - 15) + "));} return f"), this, {}, buf); -assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', IMPORTS + "function f() {return ci4(load(H, " + (BUF_MIN - 16) + "));} return f"), this, {}, buf)(), [4, 3, 2, 1]); -assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', IMPORTS + "function f() {return ci4(load(H, " + BUF_MIN + " - 16 | 0));} return f"), this, {}, buf)(), [4, 3, 2, 1]); - -var CONSTANT_INDEX = 42; -var CONSTANT_BYTE_INDEX = CONSTANT_INDEX << 2; - -var loadStoreCode = ` - "use asm"; - - var H = new glob.Uint8Array(heap); - - var i4 = glob.SIMD.Int32x4; - var i4load = i4.load; - var i4store = i4.store; - var ci4 = i4.check; - - var f4 = glob.SIMD.Float32x4; - var f4load = f4.load; - var f4store = f4.store; - var cf4 = f4.check; - - function f32l(i) { i=i|0; return cf4(f4load(H, i|0)); } - function f32lcst() { return cf4(f4load(H, ${CONSTANT_BYTE_INDEX})); } - function f32s(i, vec) { i=i|0; vec=cf4(vec); f4store(H, i|0, vec); } - function f32scst(vec) { vec=cf4(vec); f4store(H, ${CONSTANT_BYTE_INDEX}, vec); } - - function i32l(i) { i=i|0; return ci4(i4load(H, i|0)); } - function i32lcst() { return ci4(i4load(H, ${CONSTANT_BYTE_INDEX})); } - function i32s(i, vec) { i=i|0; vec=ci4(vec); i4store(H, i|0, vec); } - function i32scst(vec) { vec=ci4(vec); i4store(H, ${CONSTANT_BYTE_INDEX}, vec); } - - function f32lbndcheck(i) { - i=i|0; - if ((i|0) > ${CONSTANT_BYTE_INDEX}) i=${CONSTANT_BYTE_INDEX}; - if ((i|0) < 0) i = 0; - return cf4(f4load(H, i|0)); - } - function f32sbndcheck(i, vec) { - i=i|0; - vec=cf4(vec); - if ((i|0) > ${CONSTANT_BYTE_INDEX}) i=${CONSTANT_BYTE_INDEX}; - if ((i|0) < 0) i = 0; - return cf4(f4store(H, i|0, vec)); - } - - return { - f32l: f32l, - f32lcst: f32lcst, - f32s: f32s, - f32scst: f32scst, - f32lbndcheck: f32lbndcheck, - f32sbndcheck: f32sbndcheck, - i32l: i32l, - i32lcst: i32lcst, - i32s: i32s, - i32scst: i32scst - } -`; - -const SIZE = 0x8000; - -var F32 = new Float32Array(SIZE); -var reset = function() { - for (var i = 0; i < SIZE; i++) - F32[i] = i + 1; -}; -reset(); - -var buf = F32.buffer; -var m = asmLink(asmCompile('glob', 'ffi', 'heap', loadStoreCode), this, null, buf); - -function slice(TA, i, n) { return Array.prototype.slice.call(TA, i, i + n); } - -// Float32x4.load -function f32l(n) { return m.f32l((n|0) << 2 | 0); }; - -// Correct accesses -assertEqX4(f32l(0), slice(F32, 0, 4)); -assertEqX4(f32l(1), slice(F32, 1, 4)); -assertEqX4(f32l(SIZE - 4), slice(F32, SIZE - 4, 4)); - -assertEqX4(m.f32lcst(), slice(F32, CONSTANT_INDEX, 4)); -assertEqX4(m.f32lbndcheck(CONSTANT_BYTE_INDEX), slice(F32, CONSTANT_INDEX, 4)); - -// OOB -assertThrowsInstanceOf(() => f32l(-1), RuntimeError); -assertThrowsInstanceOf(() => f32l(SIZE), RuntimeError); -assertThrowsInstanceOf(() => f32l(SIZE - 1), RuntimeError); -assertThrowsInstanceOf(() => f32l(SIZE - 2), RuntimeError); -assertThrowsInstanceOf(() => f32l(SIZE - 3), RuntimeError); - -var code = ` - "use asm"; - var f4 = glob.SIMD.Float32x4; - var f4l = f4.load; - var u8 = new glob.Uint8Array(heap); - - function g(x) { - x = x|0; - // set a constraint on the size of the heap - var ptr = 0; - ptr = u8[0xFFFF] | 0; - // give a precise range to x - x = (x>>0) > 5 ? 5 : x; - x = (x>>0) < 0 ? 0 : x; - // ptr value gets a precise range but the bounds check shouldn't get - // eliminated. - return f4l(u8, 0xFFFA + x | 0); - } - - return g; -`; -assertThrowsInstanceOf(() => asmLink(asmCompile('glob', 'ffi', 'heap', code), this, {}, new ArrayBuffer(0x10000))(0), RuntimeError); - -// Float32x4.store -function f32s(n, v) { return m.f32s((n|0) << 2 | 0, v); }; - -var vec = SIMD.Float32x4(5,6,7,8); -var vec2 = SIMD.Float32x4(0,1,2,3); -var vecWithNaN = SIMD.Float32x4(NaN, 2, NaN, 4); - -reset(); -f32s(0, vec); -assertEqX4(vec, slice(F32, 0, 4)); - -reset(); -f32s(0, vec2); -assertEqX4(vec2, slice(F32, 0, 4)); - -reset(); -f32s(4, vec); -assertEqX4(vec, slice(F32, 4, 4)); - -reset(); -f32s(4, vecWithNaN); -assertEqX4(vecWithNaN, slice(F32, 4, 4)); - -reset(); -m.f32scst(vec2); -assertEqX4(vec2, slice(F32, CONSTANT_INDEX, 4)); - -reset(); -m.f32sbndcheck(CONSTANT_BYTE_INDEX, vec); -assertEqX4(vec, slice(F32, CONSTANT_INDEX, 4)); - -// OOB -reset(); -assertThrowsInstanceOf(() => f32s(SIZE - 3, vec), RuntimeError); -assertThrowsInstanceOf(() => f32s(SIZE - 2, vec), RuntimeError); -assertThrowsInstanceOf(() => f32s(SIZE - 1, vec), RuntimeError); -assertThrowsInstanceOf(() => f32s(SIZE, vec), RuntimeError); -for (var i = 0; i < SIZE; i++) - assertEq(F32[i], i + 1); - -// Int32x4.load -var I32 = new Int32Array(buf); -reset = function () { - for (var i = 0; i < SIZE; i++) - I32[i] = i + 1; -}; -reset(); - -function i32(n) { return m.i32l((n|0) << 2 | 0); }; - -// Correct accesses -assertEqX4(i32(0), slice(I32, 0, 4)); -assertEqX4(i32(1), slice(I32, 1, 4)); -assertEqX4(i32(SIZE - 4), slice(I32, SIZE - 4, 4)); - -assertEqX4(m.i32lcst(), slice(I32, CONSTANT_INDEX, 4)); - -// OOB -assertThrowsInstanceOf(() => i32(-1), RuntimeError); -assertThrowsInstanceOf(() => i32(SIZE), RuntimeError); -assertThrowsInstanceOf(() => i32(SIZE - 1), RuntimeError); -assertThrowsInstanceOf(() => i32(SIZE - 2), RuntimeError); -assertThrowsInstanceOf(() => i32(SIZE - 3), RuntimeError); - -// Int32x4.store -function i32s(n, v) { return m.i32s((n|0) << 2 | 0, v); }; - -var vec = SIMD.Int32x4(5,6,7,8); -var vec2 = SIMD.Int32x4(0,1,2,3); - -reset(); -i32s(0, vec); -assertEqX4(vec, slice(I32, 0, 4)); - -reset(); -i32s(0, vec2); -assertEqX4(vec2, slice(I32, 0, 4)); - -reset(); -i32s(4, vec); -assertEqX4(vec, slice(I32, 4, 4)); - -reset(); -m.i32scst(vec2); -assertEqX4(vec2, slice(I32, CONSTANT_INDEX, 4)); - -// OOB -reset(); -assertThrowsInstanceOf(() => i32s(SIZE - 3, vec), RuntimeError); -assertThrowsInstanceOf(() => i32s(SIZE - 2, vec), RuntimeError); -assertThrowsInstanceOf(() => i32s(SIZE - 1, vec), RuntimeError); -assertThrowsInstanceOf(() => i32s(SIZE - 0, vec), RuntimeError); -for (var i = 0; i < SIZE; i++) - assertEq(I32[i], i + 1); - -// Partial loads and stores -(function() { - -// Variable indexes -function MakeCodeFor(typeName) { - return ` - "use asm"; - var type = glob.SIMD.${typeName}; - var c = type.check; - - var l1 = type.load1; - var l2 = type.load2; - - var s1 = type.store1; - var s2 = type.store2; - - var u8 = new glob.Uint8Array(heap); - - function load1(i) { i=i|0; return l1(u8, i); } - function load2(i) { i=i|0; return l2(u8, i); } - - function loadCst1() { return l1(u8, 41 << 2); } - function loadCst2() { return l2(u8, 41 << 2); } - - function store1(i, x) { i=i|0; x=c(x); return s1(u8, i, x); } - function store2(i, x) { i=i|0; x=c(x); return s2(u8, i, x); } - - function storeCst1(x) { x=c(x); return s1(u8, 41 << 2, x); } - function storeCst2(x) { x=c(x); return s2(u8, 41 << 2, x); } - - return { - load1: load1, - load2: load2, - loadCst1: loadCst1, - loadCst2: loadCst2, - store1: store1, - store2: store2, - storeCst1: storeCst1, - storeCst2: storeCst2, - } -`; -} - -var SIZE = 0x10000; - -function TestPartialLoads(m, typedArray, x, y, z, w) { - // Fill array with predictable values - for (var i = 0; i < SIZE; i += 4) { - typedArray[i] = x(i); - typedArray[i + 1] = y(i); - typedArray[i + 2] = z(i); - typedArray[i + 3] = w(i); - } - - // Test correct loads - var i = 0, j = 0; // i in elems, j in bytes - assertEqX4(m.load1(j), [x(i), 0, 0, 0]); - assertEqX4(m.load2(j), [x(i), y(i), 0, 0]); - - j += 4; - assertEqX4(m.load1(j), [y(i), 0, 0, 0]); - assertEqX4(m.load2(j), [y(i), z(i), 0, 0]); - - j += 4; - assertEqX4(m.load1(j), [z(i), 0, 0, 0]); - assertEqX4(m.load2(j), [z(i), w(i), 0, 0]); - - j += 4; - assertEqX4(m.load1(j), [w(i), 0, 0, 0]); - assertEqX4(m.load2(j), [w(i), x(i+4), 0, 0]); - - j += 4; - i += 4; - assertEqX4(m.load1(j), [x(i), 0, 0, 0]); - assertEqX4(m.load2(j), [x(i), y(i), 0, 0]); - - // Test loads with constant indexes (41) - assertEqX4(m.loadCst1(), [y(40), 0, 0, 0]); - assertEqX4(m.loadCst2(), [y(40), z(40), 0, 0]); - - // Test limit and OOB accesses - assertEqX4(m.load1((SIZE - 1) << 2), [w(SIZE - 4), 0, 0, 0]); - assertThrowsInstanceOf(() => m.load1(((SIZE - 1) << 2) + 1), RuntimeError); - - assertEqX4(m.load2((SIZE - 2) << 2), [z(SIZE - 4), w(SIZE - 4), 0, 0]); - assertThrowsInstanceOf(() => m.load2(((SIZE - 2) << 2) + 1), RuntimeError); -} - -// Partial stores -function TestPartialStores(m, typedArray, typeName, x, y, z, w) { - var val = SIMD[typeName](x, y, z, w); - - function Reset() { - for (var i = 0; i < SIZE; i++) - typedArray[i] = i + 1; - } - function CheckNotModified(low, high) { - for (var i = low; i < high; i++) - assertEq(typedArray[i], i + 1); - } - - function TestStore1(i) { - m.store1(i, val); - CheckNotModified(0, i >> 2); - assertEq(typedArray[i >> 2], x); - CheckNotModified((i >> 2) + 1, SIZE); - typedArray[i >> 2] = (i >> 2) + 1; - } - - function TestStore2(i) { - m.store2(i, val); - CheckNotModified(0, i >> 2); - assertEq(typedArray[i >> 2], x); - assertEq(typedArray[(i >> 2) + 1], y); - CheckNotModified((i >> 2) + 2, SIZE); - typedArray[i >> 2] = (i >> 2) + 1; - typedArray[(i >> 2) + 1] = (i >> 2) + 2; - } - - function TestOOBStore(f) { - assertThrowsInstanceOf(f, RuntimeError); - CheckNotModified(0, SIZE); - } - - Reset(); - - TestStore1(0); - TestStore1(1 << 2); - TestStore1(2 << 2); - TestStore1(3 << 2); - TestStore1(1337 << 2); - - var i = (SIZE - 1) << 2; - TestStore1(i); - TestOOBStore(() => m.store1(i + 1, val)); - TestOOBStore(() => m.store1(-1, val)); - - TestStore2(0); - TestStore2(1 << 2); - TestStore2(2 << 2); - TestStore2(3 << 2); - TestStore2(1337 << 2); - - var i = (SIZE - 2) << 2; - TestStore2(i); - TestOOBStore(() => m.store2(i + 1, val)); - TestOOBStore(() => m.store2(-1, val)); - - // Constant indexes (41) - m.storeCst1(val); - CheckNotModified(0, 41); - assertEq(typedArray[41], x); - CheckNotModified(42, SIZE); - typedArray[41] = 42; - - m.storeCst2(val); - CheckNotModified(0, 41); - assertEq(typedArray[41], x); - assertEq(typedArray[42], y); - CheckNotModified(43, SIZE); - typedArray[41] = 42; - typedArray[42] = 43; -} - -var f32 = new Float32Array(SIZE); -var mFloat32x4 = asmLink(asmCompile('glob', 'ffi', 'heap', MakeCodeFor('Float32x4')), this, null, f32.buffer); - -TestPartialLoads(mFloat32x4, f32, - (i) => i + 1, - (i) => Math.fround(13.37), - (i) => Math.fround(1/i), - (i) => Math.fround(Math.sqrt(0x2000 - i))); - -TestPartialStores(mFloat32x4, f32, 'Float32x4', 42, -0, NaN, 0.1337); - -var i32 = new Int32Array(f32.buffer); -var mInt32x4 = asmLink(asmCompile('glob', 'ffi', 'heap', MakeCodeFor('Int32x4')), this, null, i32.buffer); - -TestPartialLoads(mInt32x4, i32, - (i) => i + 1 | 0, - (i) => -i | 0, - (i) => i * 2 | 0, - (i) => 42); - -TestPartialStores(mInt32x4, i32, 'Int32x4', 42, -3, 13, 37); - -})(); - -} catch (e) { print('stack: ', e.stack); throw e } diff --git a/js/src/jit-test/tests/asm.js/testSIMD.js b/js/src/jit-test/tests/asm.js/testSIMD.js deleted file mode 100644 index 29786bc52c..0000000000 --- a/js/src/jit-test/tests/asm.js/testSIMD.js +++ /dev/null @@ -1,1575 +0,0 @@ -load(libdir + "asm.js"); -load(libdir + "simd.js"); -load(libdir + "asserts.js"); -var heap = new ArrayBuffer(0x10000); - -// Avoid pathological --ion-eager compile times due to bails in loops -setJitCompilerOption('ion.warmup.trigger', 1000000); - -// Set to true to see more JS debugging spew -const DEBUG = false; - -if (!isSimdAvailable() || typeof SIMD === 'undefined' || !isAsmJSCompilationAvailable()) { - DEBUG && print("won't run tests as simd extensions aren't activated yet"); - quit(0); -} - -const I32 = 'var i4 = glob.SIMD.Int32x4;' -const CI32 = 'var ci4 = i4.check;' -const I32A = 'var i4a = i4.add;' -const I32S = 'var i4s = i4.sub;' -const I32M = 'var i4m = i4.mul;' -const I32U32 = 'var i4u4 = i4.fromUint32x4Bits;' - -const U32 = 'var u4 = glob.SIMD.Uint32x4;' -const CU32 = 'var cu4 = u4.check;' -const U32A = 'var u4a = u4.add;' -const U32S = 'var u4s = u4.sub;' -const U32M = 'var u4m = u4.mul;' -const U32I32 = 'var u4i4 = u4.fromInt32x4Bits;' - -const F32 = 'var f4 = glob.SIMD.Float32x4;' -const CF32 = 'var cf4 = f4.check;' -const F32A = 'var f4a = f4.add;' -const F32S = 'var f4s = f4.sub;' -const F32M = 'var f4m = f4.mul;' -const F32D = 'var f4d = f4.div;' -const FROUND = 'var f32=glob.Math.fround;' -const B32 = 'var b4 = glob.SIMD.Bool32x4;' -const CB32 = 'var cb4 = b4.check;' - -const EXTI4 = 'var e = i4.extractLane;' -const EXTU4 = 'var e = u4.extractLane;' -const EXTF4 = 'var e = f4.extractLane;' -const EXTB4 = 'var e = b4.extractLane;' - -// anyTrue / allTrue on boolean vectors. -const ANYB4 = 'var anyt=b4.anyTrue;' -const ALLB4 = 'var allt=b4.allTrue;' - -const INT32_MAX = Math.pow(2, 31) - 1; -const INT32_MIN = INT32_MAX + 1 | 0; -const UINT32_MAX = Math.pow(2, 32) - 1; - -const assertEqFFI = {assertEq:assertEq}; - -function CheckI4(header, code, expected) { - // code needs to contain a local called x - header = USE_ASM + I32 + CI32 + EXTI4 + F32 + header; - var observed = asmLink(asmCompile('glob', header + ';function f() {' + code + ';return ci4(x)} return f'), this)(); - assertEqX4(observed, expected); -} - -function CheckU4(header, code, expected) { - // code needs to contain a local called x. - header = USE_ASM + U32 + CU32 + EXTU4 + I32 + CI32 + I32U32 + header; - var observed = asmLink(asmCompile('glob', header + ';function f() {' + code + ';return ci4(i4u4(x))} return f'), this)(); - // We can't return an unsigned SIMD type. Return Int32x4, convert to unsigned here. - observed = SIMD.Uint32x4.fromInt32x4Bits(observed) - assertEqX4(observed, expected); -} - -function CheckF4(header, code, expected) { - // code needs to contain a local called x - header = USE_ASM + F32 + CF32 + EXTF4 + header; - var observed = asmLink(asmCompile('glob', header + ';function f() {' + code + ';return cf4(x)} return f'), this)(); - assertEqX4(observed, expected.map(Math.fround)); -} - -function CheckB4(header, code, expected) { - // code needs to contain a local called x - header = USE_ASM + B32 + CB32 + header; - var observed = asmLink(asmCompile('glob', header + ';function f() {' + code + ';return cb4(x)} return f'), this)(); - assertEqX4(observed, expected); -} - -try { - -// 1. Constructors - -// 1.1 Compilation -assertAsmTypeFail('glob', USE_ASM + "var i4 = Int32x4 ; return {}") ; -assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.Int32x4 ; return {}") ; -assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.globglob.Int32x4 ; return {}") ; -assertAsmTypeFail('glob', USE_ASM + "var i4 = glob.Math.Int32x4 ; return {}") ; -assertAsmTypeFail('glob', USE_ASM + "var herd = glob.SIMD.ponyX4 ; return {}") ; - -// 1.2 Linking -assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: 42}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: Math.fround}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {}}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {Int32x4: 42}}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {Int32x4: Math.fround}}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {Int32x4: new Array}}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {Int32x4: SIMD.Float32x4}}); - -var [Type, int32] = [TypedObject.StructType, TypedObject.int32]; -var MyStruct = new Type({'x': int32, 'y': int32, 'z': int32, 'w': int32}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {Int32x4: MyStruct}}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + I32 + "return {}"), {SIMD: {Int32x4: new MyStruct}}); - -assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {} return f"), {SIMD:{Int32x4: SIMD.Int32x4}})(), undefined); - -assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {Float32x4: 42}}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {Float32x4: Math.fround}}); -assertAsmLinkFail(asmCompile('glob', USE_ASM + F32 + "return {}"), {SIMD: {Float32x4: new Array}}); -assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {} return f"), {SIMD:{Float32x4: SIMD.Float32x4}})(), undefined); - -// 1.3 Correctness -// 1.3.1 Local variables declarations -assertAsmTypeFail('glob', USE_ASM + "function f() {var x=Int32x4(1,2,3,4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4();} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1, 2);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1, 2, 3);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1, 2, 3, 4.0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1, 2.0, 3, 4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4a(1,2,3,4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,2+2|0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3," + (INT32_MIN - 1) + ");} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(i4(1,2,3,4));} return f"); -assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4);} return f"), this)(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3," + (INT32_MAX + 1) + ");} return f"), this)(), undefined); - -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4();} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1.,2.,3.);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1.,2.,f32(3.),4.);} return f"); -assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1.,2.,3.,4.);} return f"), this)(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4);} return f"), this)(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3," + (INT32_MIN - 1) + ");} return f"), this)(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3," + (INT32_MAX + 1) + ");} return f"), this)(), undefined); - -// Places where NumLit can creep in -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(i) {i=i|0; var z=0; switch(i|0) {case i4(1,2,3,4): z=1; break; default: z=2; break;}} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(i) {i=i|0; var z=0; return i * i4(1,2,3,4) | 0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(i) {var x=i4(1,2,3,i4(4,5,6,7))} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "function f(i) {var x=i4(1,2,3,f4(4,5,6,7))} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "function f(i) {var x=f4(1,2,3,i4(4,5,6,7))} return f"); - -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {return +i4(1,2,3,4)} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {return i4(1,2,3,4)|0} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + "function f() {return f32(i4(1,2,3,4))} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + "function f() {return cf4(i4(1,2,3,4))} return f"); - -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {return +f4(1,2,3,4)} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {return f4(1,2,3,4)|0} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + FROUND + "function f() {return f32(f4(1,2,3,4))} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + F32 + "function f() {return ci4(f4(1,2,3,4))} return f"); - -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {return i4(1,2,3,4);} return f"), this)(), [1, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f() {return ci4(i4(1,2,3,4));} return f"), this)(), [1, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {return f4(1,2,3,4);} return f"), this)(), [1, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f() {return cf4(f4(1,2,3,4));} return f"), this)(), [1, 2, 3, 4]); - -assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {i4(1,2,3,4);} return f"), this)(), undefined); -assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {f4(1,2,3,4);} return f"), this)(), undefined); - -// Int32x4 ctor should accept int? -assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + I32 + CI32 + "var i32=new glob.Int32Array(heap); function f(i) {i=i|0; return ci4(i4(i32[i>>2], 2, 3, 4))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [0, 2, 3, 4]); -// Float32x4 ctor should accept floatish (i.e. float || float? || floatish) and doublit -assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + F32 + CF32 + FROUND + "var h=new glob.Float32Array(heap); function f(i) {i=i|0; return cf4(f4(h[i>>2], f32(2), f32(3), f32(4)))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [NaN, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + FROUND + "function f(i) {i=i|0; return cf4(f4(f32(1) + f32(2), f32(2), f32(3), f32(4)))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [3, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + FROUND + "function f(i) {i=i|0; return cf4(f4(f32(1) + f32(2), 2.0, 3.0, 4.0))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [3, 2, 3, 4]); -// Bool32x4 ctor should accept int? -assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + B32 + CB32 + "var i32=new glob.Int32Array(heap); function f(i) {i=i|0; return cb4(b4(i32[i>>2], 2, 0, 4))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [false, true, false, true]); - -// 1.3.2 Getters - Reading values out of lanes -assertAsmTypeFail('glob', USE_ASM + I32 + EXTI4 + "function f() {var x=1; return e(x,1) | 0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + EXTI4 + "function f() {var x=1; return e(x + x, 1) | 0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + EXTI4 + "function f() {var x=1.; return e(x, 1) | 0;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + EXTF4 + "var f32=glob.Math.fround;" + I32 + "function f() {var x=f32(1); return e(x, 1) | 0;} return f"); - -assertAsmTypeFail('glob', USE_ASM + I32 + EXTI4 + "function f() {var x=i4(1,2,3,4); return x.length|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + EXTI4 + "function f() {var x=e(i4(1,2,3,4),1); return x|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + EXTI4 + "function f() {var x=i4(1,2,3,4); return (e(x,0) > (1>>>0)) | 0;} return f"); - -assertAsmTypeFail('glob', USE_ASM + I32 + EXTI4 + "function f() {var x=i4(1,2,3,4); return e(x,-1) | 0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + EXTI4 + "function f() {var x=i4(1,2,3,4); return e(x,4) | 0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + EXTI4 + "function f() {var x=i4(1,2,3,4); return e(x,.5) | 0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + EXTI4 + "function f() {var x=i4(1,2,3,4); return e(x,x) | 0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + EXTF4 + "function f() {var x=i4(1,2,3,4); return e(x,0) | 0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + EXTI4 + "function f() {var x=i4(1,2,3,4); var i=0; return e(x,i) | 0;} return f"); - -// The signMask property is no longer supported. Replaced by allTrue / anyTrue. -assertAsmTypeFail('glob', USE_ASM + "function f() {var x=42; return x.signMask;} return f"); -assertAsmTypeFail('glob', USE_ASM + "function f() {var x=42.; return x.signMask;} return f"); -assertAsmTypeFail('glob', USE_ASM + FROUND + "function f() {var x=f32(42.); return x.signMask;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + 'function f() { var x=i4(1,2,3,4); return x.signMask | 0 } return f'); -assertAsmTypeFail('glob', USE_ASM + U32 + 'function f() { var x=u4(1,2,3,4); return x.signMask | 0 } return f'); -assertAsmTypeFail('glob', USE_ASM + F32 + FROUND + 'var Infinity = glob.Infinity; function f() { var x=f4(0,0,0,0); x=f4(f32(1), f32(-13.37), f32(42), f32(-Infinity)); return x.signMask | 0 } return f'); - -// Check lane extraction. -function CheckLanes(innerBody, type, expected) { - var coerceBefore, coerceAfter, extractLane; - - if (type === SIMD.Int32x4) { - coerceBefore = ''; - coerceAfter = '|0'; - extractLane = 'ei'; - } else if (type === SIMD.Uint32x4) { - // Coerce Uint32 lanes to double so they can be legally returned. - coerceBefore = '+'; - coerceAfter = ''; - extractLane = 'eu'; - } else if (type === SIMD.Float32x4) { - coerceBefore = '+'; - coerceAfter = ''; - extractLane = 'ef'; - expected = expected.map(Math.fround); - } else if (type === SIMD.Bool32x4) { - coerceBefore = ''; - coerceAfter = '|0'; - extractLane = 'eb'; - } else throw "unexpected type in CheckLanes"; - - for (var i = 0; i < 4; i++) { - var lane = i; - var laneCheckCode = `"use asm"; - var i4=glob.SIMD.Int32x4; - var u4=glob.SIMD.Uint32x4; - var f4=glob.SIMD.Float32x4; - var b4=glob.SIMD.Bool32x4; - var ei=i4.extractLane; - var eu=u4.extractLane; - var ef=f4.extractLane; - var eb=b4.extractLane; - function f() {${innerBody}; return ${coerceBefore}${extractLane}(x, ${lane})${coerceAfter} } - return f;`; - assertEq(asmLink(asmCompile('glob', laneCheckCode), this)(), expected[i]); - } -} -function CheckLanesI4(innerBody, expected) { return CheckLanes(innerBody, SIMD.Int32x4, expected); } -function CheckLanesU4(innerBody, expected) { return CheckLanes(innerBody, SIMD.Uint32x4, expected); } -function CheckLanesF4(innerBody, expected) { return CheckLanes(innerBody, SIMD.Float32x4, expected); } -function CheckLanesB4(innerBody, expected) { return CheckLanes(innerBody, SIMD.Bool32x4, expected); } - -CheckLanesI4('var x=i4(0,0,0,0);', [0,0,0,0]); -CheckLanesI4('var x=i4(1,2,3,4);', [1,2,3,4]); -CheckLanesI4('var x=i4(' + INT32_MIN + ',2,3,' + INT32_MAX + ')', [INT32_MIN,2,3,INT32_MAX]); -CheckLanesI4('var x=i4(1,2,3,4); var y=i4(5,6,7,8)', [1,2,3,4]); -CheckLanesI4('var a=1; var b=i4(9,8,7,6); var c=13.37; var x=i4(1,2,3,4); var y=i4(5,6,7,8)', [1,2,3,4]); -CheckLanesI4('var y=i4(5,6,7,8); var x=i4(1,2,3,4)', [1,2,3,4]); - -CheckLanesU4('var x=u4(0,0,0,0);', [0,0,0,0]); -CheckLanesU4('var x=u4(1,2,3,4000000000);', [1,2,3,4000000000]); -CheckLanesU4('var x=u4(' + INT32_MIN + ',2,3,' + UINT32_MAX + ')', [INT32_MIN>>>0,2,3,UINT32_MAX]); -CheckLanesU4('var x=u4(1,2,3,4); var y=u4(5,6,7,8)', [1,2,3,4]); -CheckLanesU4('var a=1; var b=u4(9,8,7,6); var c=13.37; var x=u4(1,2,3,4); var y=u4(5,6,7,8)', [1,2,3,4]); -CheckLanesU4('var y=u4(5,6,7,8); var x=u4(1,2,3,4)', [1,2,3,4]); - -CheckLanesF4('var x=f4(' + INT32_MAX + ', 2, 3, ' + INT32_MIN + ')', [INT32_MAX, 2, 3, INT32_MIN]); -CheckLanesF4('var x=f4(' + (INT32_MAX + 1) + ', 2, 3, 4)', [INT32_MAX + 1, 2, 3, 4]); -CheckLanesF4('var x=f4(1.3, 2.4, 3.5, 98.76)', [1.3, 2.4, 3.5, 98.76]); -CheckLanesF4('var x=f4(13.37, 2., 3., -0)', [13.37, 2, 3, -0]); - -CheckLanesB4('var x=b4(0,0,0,0);', [0,0,0,0]); -CheckLanesB4('var x=b4(0,1,0,0);', [0,1,0,0]); -CheckLanesB4('var x=b4(0,2,0,0);', [0,1,0,0]); -CheckLanesB4('var x=b4(-1,0,1,-1);', [1,0,1,1]); - -// 1.3.3. Variable assignments -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4();} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2, 3);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1.0, 2, 3, 4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2.0, 3, 4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2, 3.0, 4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2, 3, 4.0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4(1, 2, 3, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); var c=4.0; x=i4(1, 2, 3, +c);} return f"); - -assertAsmTypeFail('glob', 'ffi', 'heap', USE_ASM + I32 + "var i32=new glob.Int32Array(heap); function f() {var x=i4(1,2,3,4); i32[0] = x;} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', USE_ASM + I32 + "var i32=new glob.Int32Array(heap); function f() {var x=i4(1,2,3,4); x = i32[0];} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', USE_ASM + F32 + "var f32=new glob.Float32Array(heap); function f() {var x=f4(1,2,3,4); f32[0] = x;} return f"); -assertAsmTypeFail('glob', 'ffi', 'heap', USE_ASM + F32 + "var f32=new glob.Int32Array(heap); function f() {var x=f4(1,2,3,4); x = f32[0];} return f"); - -CheckI4('', 'var x=i4(1,2,3,4); x=i4(5,6,7,8)', [5, 6, 7, 8]); -CheckI4('', 'var x=i4(1,2,3,4); var c=6; x=i4(5,c|0,7,8)', [5, 6, 7, 8]); -CheckI4('', 'var x=i4(8,7,6,5); x=i4(e(x,3)|0,e(x,2)|0,e(x,1)|0,e(x,0)|0)', [5, 6, 7, 8]); - -CheckU4('', 'var x=u4(1,2,3,4); x=u4(5,6,7,4000000000)', [5, 6, 7, 4000000000]); -CheckU4('', 'var x=u4(1,2,3,4); var c=6; x=u4(5,c|0,7,8)', [5, 6, 7, 8]); -CheckU4('', 'var x=u4(8,7,6,5); x=u4(e(x,3)|0,e(x,2)|0,e(x,1)|0,e(x,0)|0)', [5, 6, 7, 8]); - -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var c=4; x=f4(1,2,3,c);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var c=4; x=f4(1.,2.,3.,c);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var c=4.; x=f4(1,2,3,c);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var c=4.; x=f4(1.,2.,3.,c);} return f"); - -CheckF4(FROUND, 'var x=f4(1,2,3,4); var y=f32(7.); x=f4(f32(5),f32(6),y,f32(8))', [5, 6, 7, 8]); -CheckF4(FROUND, 'var x=f4(1,2,3,4); x=f4(f32(5),f32(6),f32(7),f32(8))', [5, 6, 7, 8]); -CheckF4(FROUND, 'var x=f4(1,2,3,4); x=f4(f32(5.),f32(6.),f32(7.),f32(8.))', [5, 6, 7, 8]); -CheckF4('', 'var x=f4(1.,2.,3.,4.); x=f4(5.,6.,7.,8.)', [5, 6, 7, 8]); -CheckF4('', 'var x=f4(1.,2.,3.,4.); x=f4(1,2,3,4)', [1, 2, 3, 4]); -CheckF4(FROUND, 'var x=f4(1.,2.,3.,4.); var y=f32(7.); x=f4(9, 4, 2, 1)', [9, 4, 2, 1]); -CheckF4('', 'var x=f4(8.,7.,6.,5.); x=f4(e(x,3),e(x,2),e(x,1),e(x,0))', [5, 6, 7, 8]); - -// Optimization for all lanes from the same definition. -CheckI4('', 'var x=i4(1,2,3,4); var c=6; x=i4(c|0,c|0,c|0,c|0)', [6, 6, 6, 6]); -CheckF4(FROUND, 'var x=f4(1,2,3,4); var y=f32(7.); x=f4(y,y,y,y)', [7, 7, 7, 7]); -CheckI4('', 'var x=i4(1,2,3,4); var c=0; c=e(x,3)|0; x=i4(c,c,c,c)', [4, 4, 4, 4]); -CheckF4(FROUND, 'var x=f4(1,2,3,4); var y=f32(0); y=e(x,2); x=f4(y,y,y,y)', [3, 3, 3, 3]); -CheckI4('', 'var x=i4(1,2,3,4); var c=0; var d=0; c=e(x,3)|0; d=e(x,3)|0; x=i4(c,d,d,c)', [4, 4, 4, 4]); -CheckF4(FROUND, 'var x=f4(1,2,3,4); var y=f32(0); var z=f32(0); y=e(x,2); z=e(x,2); x=f4(y,z,y,z)', [3, 3, 3, 3]); - -// Uses in ternary conditionals -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var c=4; c=x?c:c;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var c=4; x=1?x:c;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var c=4; x=1?c:x;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "function f() {var x=f4(1,2,3,4); var y=i4(1,2,3,4); x=1?x:y;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "function f() {var x=f4(1,2,3,4); var y=i4(1,2,3,4); x=1?y:y;} return f"); -assertAsmTypeFail('glob', USE_ASM + B32 + I32 + "function f() {var x=b4(1,2,3,4); var y=i4(1,2,3,4); x=1?y:y;} return f"); -assertAsmTypeFail('glob', USE_ASM + U32 + I32 + "function f() {var x=u4(1,2,3,4); var y=i4(1,2,3,4); x=1?y:y;} return f"); -assertAsmTypeFail('glob', USE_ASM + U32 + I32 + "function f() {var x=i4(1,2,3,4); var y=u4(1,2,3,4); x=1?y:y;} return f"); - -CheckF4('', 'var x=f4(1,2,3,4); var y=f4(4,3,2,1); x=3?y:x', [4, 3, 2, 1]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=x|0; var v=f4(1,2,3,4); var w=f4(5,6,7,8); return cf4(x?w:v);} return f"), this)(1), [5,6,7,8]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(v) {v=cf4(v); var w=f4(5,6,7,8); return cf4(4?w:v);} return f"), this)(SIMD.Float32x4(1,2,3,4)), [5,6,7,8]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(v, x) {v=cf4(v); x=x|0; var w=f4(5,6,7,8); return cf4(x?w:v);} return f"), this)(SIMD.Float32x4(1,2,3,4), 0), [1,2,3,4]); - -CheckI4('', 'var x=i4(1,2,3,4); var y=i4(4,3,2,1); x=e(x,0)?y:x', [4, 3, 2, 1]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(x) {x=x|0; var v=i4(1,2,3,4); var w=i4(5,6,7,8); return ci4(x?w:v);} return f"), this)(1), [5,6,7,8]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(v) {v=ci4(v); var w=i4(5,6,7,8); return ci4(4?w:v);} return f"), this)(SIMD.Int32x4(1,2,3,4)), [5,6,7,8]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(v, x) {v=ci4(v); x=x|0; var w=i4(5,6,7,8); return ci4(x?w:v);} return f"), this)(SIMD.Int32x4(1,2,3,4), 0), [1,2,3,4]); - -// Unsigned SIMD types can't be function arguments or return values. -assertAsmTypeFail('glob', USE_ASM + U32 + CU32 + "function f(x) {x=cu4(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + U32 + CU32 + "function f() {x=u4(0,0,0,0); return cu4(x);} return f"); - -// 1.3.4 Return values -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {var x=1; return ci4(x)} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {var x=1; return ci4(x + x)} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {var x=1.; return ci4(x)} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + FROUND + "function f() {var x=f32(1.); return ci4(x)} return f"); - -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f() {var x=i4(1,2,3,4); return ci4(x)} return f"), this)(), [1,2,3,4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f() {var x=f4(1,2,3,4); return cf4(x)} return f"), this)(), [1,2,3,4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + "function f() {var x=b4(1,2,0,4); return cb4(x)} return f"), this)(), [true,true,false,true]); - -// 1.3.5 Coerce and pass arguments -// Via check -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {ci4();} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x); ci4(x, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {ci4(1);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {ci4(1.);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + FROUND + "function f() {ci4(f32(1.));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + F32 + CF32 + "function f(x) {x=cf4(x); ci4(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x); return 1 + ci4(x) | 0;} return f"); - -var i32x4 = SIMD.Int32x4(1, 3, 3, 7); -assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x)} return f"), this)(i32x4), undefined); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x); return ci4(x);} return f"), this)(i32x4), [1,3,3,7]); - -assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + "function f() {cf4();} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x); cf4(x, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + "function f() {cf4(1);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + "function f() {cf4(1.);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + FROUND + "function f() {cf4(f32(1.));} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + F32 + CF32 + "function f(x) {x=cf4(x); cf4(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x); return 1 + cf4(x) | 0;} return f"); - -var f32x4 = SIMD.Float32x4(13.37, 42.42, -0, NaN); -assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x)} return f"), this)(f32x4), undefined); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x); return cf4(x);} return f"), this)(f32x4), [13.37, 42.42, -0, NaN].map(Math.fround)); - -var b32x4 = SIMD.Bool32x4(true, false, false, true); -assertEq(asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + "function f(x) {x=cb4(x)} return f"), this)(b32x4), undefined); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + "function f(x) {x=cb4(x); return cb4(x);} return f"), this)(b32x4), [true, false, false, true]); - -// Legacy coercions -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {x=i4();} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {x=i4(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {x=i4(1,2,3,4);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x,y) {x=i4(y);y=+y} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x); return i4(x);} return f"); - -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {return +i4(1,2,3,4)} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {return 0|i4(1,2,3,4)} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + "function f(x) {return f32(i4(1,2,3,4))} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "function f(x) {return f4(i4(1,2,3,4))} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x); return f4(x);} return f"); - - -function assertCaught(f) { - var caught = false; - try { - f.apply(null, Array.prototype.slice.call(arguments, 1)); - } catch (e) { - DEBUG && print('Assert caught: ', e, '\n', e.stack); - assertEq(e instanceof TypeError, true); - caught = true; - } - assertEq(caught, true); -} - -var f = asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x); return cf4(x);} return f"), this); -assertCaught(f); -assertCaught(f, 1); -assertCaught(f, {}); -assertCaught(f, "I sincerely am a SIMD typed object."); -assertCaught(f, SIMD.Int32x4(1,2,3,4)); -assertCaught(f, SIMD.Bool32x4(true, true, false, true)); - -var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x); return ci4(x);} return f"), this); -assertCaught(f); -assertCaught(f, 1); -assertCaught(f, {}); -assertCaught(f, "I sincerely am a SIMD typed object."); -assertCaught(f, SIMD.Float32x4(4,3,2,1)); -assertCaught(f, SIMD.Bool32x4(true, true, false, true)); - -var f = asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + "function f(x) {x=cb4(x); return cb4(x);} return f"), this); -assertCaught(f); -assertCaught(f, 1); -assertCaught(f, {}); -assertCaught(f, "I sincerely am a SIMD typed object."); -assertCaught(f, SIMD.Int32x4(1,2,3,4)); -assertCaught(f, SIMD.Float32x4(4,3,2,1)); - -// 1.3.6 Globals -// 1.3.6.1 Local globals -// Read -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); function f() {var x=4; x=g|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); function f() {var x=4.; x=+g;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); var f32=glob.Math.fround; function f() {var x=f32(4.); x=f32(g);} return f"); - -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f() {var x=4; x=g|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f() {var x=4.; x=+g;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); var f32=glob.Math.fround; function f() {var x=f32(4.); x=f32(g);} return f"); - -assertAsmTypeFail('glob', USE_ASM + F32 + I32 + CI32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); x=ci4(g);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); x=cf4(g);} return f"); -assertAsmTypeFail('glob', USE_ASM + U32 + I32 + CI32 + "var g=u4(1,2,3,4); function f() {var x=i4(1,2,3,4); x=ci4(g);} return f"); - -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=0; function f() {var x=i4(1,2,3,4); x=g|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=0.; function f() {var x=i4(1,2,3,4); x=+g;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var f32=glob.Math.fround; var g=f32(0.); function f() {var x=i4(1,2,3,4); x=f32(g);} return f"); - -// Unsigned SIMD globals are not allowed. -assertAsmTypeFail('glob', USE_ASM + U32 + "var g=u4(0,0,0,0); function f() {var x=u4(1,2,3,4); x=g;} return f"); - -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=0; function f() {var x=f4(0.,0.,0.,0.); x=g|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=0.; function f() {var x=f4(0.,0.,0.,0.); x=+g;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "var f32=glob.Math.fround; var g=f32(0.); function f() {var x=f4(0.,0.,0.,0.); x=f32(g);} return f"); - -CheckI4('var x=i4(1,2,3,4)', '', [1, 2, 3, 4]); -CheckI4('var _=42; var h=i4(5,5,5,5); var __=13.37; var x=i4(4,7,9,2);', '', [4,7,9,2]); - -CheckF4('var x=f4(1.,2.,3.,4.)', '', [1, 2, 3, 4]); -CheckF4('var _=42; var h=f4(5.,5.,5.,5.); var __=13.37; var x=f4(4.,13.37,9.,-0.);', '', [4, 13.37, 9, -0]); -CheckF4('var x=f4(1,2,3,4)', '', [1, 2, 3, 4]); - -CheckB4('var x=b4(1,0,3,0)', '', [true, false, true, false]); -CheckB4('var _=42; var h=b4(5,0,5,5); var __=13.37; var x=b4(0,0,9,2);', '', [false, false, true, true]); - -// Write -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); function f() {var x=4; g=x|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); function f() {var x=4.; g=+x;} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); var f32=glob.Math.fround; function f() {var x=f32(4.); g=f32(x);} return f"); - -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f() {var x=4; g=x|0;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f() {var x=4.; g=+x;} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); var f32=glob.Math.fround; function f() {var x=f32(4.); g=f32(x);} return f"); - -assertAsmTypeFail('glob', USE_ASM + F32 + I32 + CI32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); g=ci4(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + I32 + CF32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); g=cf4(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); g=cf4(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); g=ci4(x);} return f"); - -CheckI4('var x=i4(0,0,0,0);', 'x=i4(1,2,3,4)', [1,2,3,4]); -CheckF4('var x=f4(0.,0.,0.,0.);', 'x=f4(5.,3.,4.,2.)', [5,3,4,2]); -CheckB4('var x=b4(0,0,0,0);', 'x=b4(0,0,1,1)', [false, false, true, true]); - -CheckI4('var x=i4(0,0,0,0); var y=42; var z=3.9; var w=13.37', 'x=i4(1,2,3,4); y=24; z=4.9; w=23.10;', [1,2,3,4]); -CheckF4('var x=f4(0,0,0,0); var y=42; var z=3.9; var w=13.37', 'x=f4(1,2,3,4); y=24; z=4.9; w=23.10;', [1,2,3,4]); -CheckB4('var x=b4(0,0,0,0); var y=42; var z=3.9; var w=13.37', 'x=b4(1,0,0,0); y=24; z=4.9; w=23.10;', [true, false, false, false]); - -// 1.3.6.2 Imported globals -// Read -var Int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + CI32 + "var g=ci4(ffi.g); function f() {return ci4(g)} return f"), this, {g: SIMD.Int32x4(1,2,3,4)})(); -assertEq(SIMD.Int32x4.extractLane(Int32x4, 0), 1); -assertEq(SIMD.Int32x4.extractLane(Int32x4, 1), 2); -assertEq(SIMD.Int32x4.extractLane(Int32x4, 2), 3); -assertEq(SIMD.Int32x4.extractLane(Int32x4, 3), 4); - -for (var v of [1, {}, "totally legit SIMD variable", SIMD.Float32x4(1,2,3,4)]) - assertCaught(asmCompile('glob', 'ffi', USE_ASM + I32 + CI32 + "var g=ci4(ffi.g); function f() {return ci4(g)} return f"), this, {g: v}); - -// Unsigned SIMD globals are not allowed. -assertAsmTypeFail('glob', 'ffi', USE_ASM + U32 + CU32 + "var g=cu4(ffi.g); function f() {} return f"); - -var Float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + CF32 + "var g=cf4(ffi.g); function f() {return cf4(g)} return f"), this, {g: SIMD.Float32x4(1,2,3,4)})(); -assertEq(SIMD.Float32x4.extractLane(Float32x4, 0), 1); -assertEq(SIMD.Float32x4.extractLane(Float32x4, 1), 2); -assertEq(SIMD.Float32x4.extractLane(Float32x4, 2), 3); -assertEq(SIMD.Float32x4.extractLane(Float32x4, 3), 4); - -for (var v of [1, {}, "totally legit SIMD variable", SIMD.Int32x4(1,2,3,4)]) - assertCaught(asmCompile('glob', 'ffi', USE_ASM + F32 + CF32 + "var g=cf4(ffi.g); function f() {return cf4(g)} return f"), this, {g: v}); - -var Bool32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + B32 + CB32 + "var g=cb4(ffi.g); function f() {return cb4(g)} return f"), this, {g: SIMD.Bool32x4(false, false, false, true)})(); -assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 0), false); -assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 1), false); -assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 2), false); -assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 3), true); - -for (var v of [1, {}, "totally legit SIMD variable", SIMD.Int32x4(1,2,3,4)]) - assertCaught(asmCompile('glob', 'ffi', USE_ASM + B32 + CB32 + "var g=cb4(ffi.g); function f() {return cb4(g)} return f"), this, {g: v}); - -// Write -var Int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + CI32 + "var g=ci4(ffi.g); function f() {g=i4(4,5,6,7); return ci4(g)} return f"), this, {g: SIMD.Int32x4(1,2,3,4)})(); -assertEq(SIMD.Int32x4.extractLane(Int32x4, 0), 4); -assertEq(SIMD.Int32x4.extractLane(Int32x4, 1), 5); -assertEq(SIMD.Int32x4.extractLane(Int32x4, 2), 6); -assertEq(SIMD.Int32x4.extractLane(Int32x4, 3), 7); - -var Float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + CF32 + "var g=cf4(ffi.g); function f() {g=f4(4.,5.,6.,7.); return cf4(g)} return f"), this, {g: SIMD.Float32x4(1,2,3,4)})(); -assertEq(SIMD.Float32x4.extractLane(Float32x4, 0), 4); -assertEq(SIMD.Float32x4.extractLane(Float32x4, 1), 5); -assertEq(SIMD.Float32x4.extractLane(Float32x4, 2), 6); -assertEq(SIMD.Float32x4.extractLane(Float32x4, 3), 7); - -var Bool32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + B32 + CB32 + "var g=cb4(ffi.g); function f() {g=b4(1,1,0,0); return cb4(g)} return f"), this, {g: SIMD.Bool32x4(1,1,1,0)})(); -assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 0), true); -assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 1), true); -assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 2), false); -assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 3), false); - -// 2. SIMD operations -// 2.1 Compilation -assertAsmTypeFail('glob', USE_ASM + "var add = Int32x4.add; return {}"); -assertAsmTypeFail('glob', USE_ASM + I32A + I32 + "return {}"); -assertAsmTypeFail('glob', USE_ASM + "var g = 3; var add = g.add; return {}"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var func = i4.doTheHarlemShake; return {}"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var div = i4.div; return {}"); -assertAsmTypeFail('glob', USE_ASM + "var f32 = glob.Math.fround; var i4a = f32.add; return {}"); -// Operation exists, but in a different type. -assertAsmTypeFail('glob', USE_ASM + I32 + "var func = i4.fromUint32x4; return {}"); - -// 2.2 Linking -assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + I32 + I32A + "function f() {} return f"), {}); -assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + I32 + I32A + "function f() {} return f"), {SIMD: Math.fround}); - -var oldInt32x4Add = SIMD.Int32x4.add; -var code = asmCompile('glob', USE_ASM + I32 + I32A + "return {}"); -for (var v of [42, Math.fround, SIMD.Float32x4.add, function(){}, SIMD.Int32x4.mul]) { - SIMD.Int32x4.add = v; - assertAsmLinkFail(code, {SIMD: {Int32x4: SIMD.Int32x4}}); -} -SIMD.Int32x4.add = oldInt32x4Add; // finally replace the add function with the original one -assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + I32A + "function f() {} return f"), {SIMD: {Int32x4: SIMD.Int32x4}})(), undefined); - -// 2.3. Binary arithmetic operations -// 2.3.1 Additions -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a();} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(x, x, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(13, 37);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(23.10, 19.89);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(x, 42);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4a(x, 13.37);} return f"); - -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); var y=4; x=i4a(x, y);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(0,0,0,0); var y=4; x=i4a(y, y);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(0,0,0,0); var y=4; y=i4a(x, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + U32 + "function f() {var x=i4(0,0,0,0); var y=u4(1,2,3,4); y=i4a(x, y);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); x=i4a(x, y);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=i4a(x, y);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=i4a(x, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=f4a(x, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=f4a(x, y);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); x=f4a(y, y);} return f"); - -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + 'function f() {var x=i4(1,2,3,4); var y=0; y=i4a(x,x)|0} return f'); -assertAsmTypeFail('glob', USE_ASM + I32 + I32A + 'function f() {var x=i4(1,2,3,4); var y=0.; y=+i4a(x,x)} return f'); - -CheckI4(I32A, 'var z=i4(1,2,3,4); var y=i4(0,1,0,3); var x=i4(0,0,0,0); x=i4a(z,y)', [1,3,3,7]); -CheckI4(I32A, 'var x=i4(2,3,4,5); var y=i4(0,1,0,3); x=i4a(x,y)', [2,4,4,8]); -CheckI4(I32A, 'var x=i4(1,2,3,4); x=i4a(x,x)', [2,4,6,8]); -CheckI4(I32A, 'var x=i4(' + INT32_MAX + ',2,3,4); var y=i4(1,1,0,3); x=i4a(x,y)', [INT32_MIN,3,3,7]); -CheckI4(I32A, 'var x=i4(' + INT32_MAX + ',2,3,4); var y=i4(1,1,0,3); x=ci4(i4a(x,y))', [INT32_MIN,3,3,7]); - -CheckU4(U32A, 'var z=u4(1,2,3,4); var y=u4(0,1,0,3); var x=u4(0,0,0,0); x=u4a(z,y)', [1,3,3,7]); -CheckU4(U32A, 'var x=u4(2,3,4,5); var y=u4(0,1,0,3); x=u4a(x,y)', [2,4,4,8]); -CheckU4(U32A, 'var x=u4(1,2,3,4); x=u4a(x,x)', [2,4,6,8]); - -CheckF4(F32A, 'var x=f4(1,2,3,4); x=f4a(x,x)', [2,4,6,8]); -CheckF4(F32A, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4a(x,y)', [5,5,8,6]); -CheckF4(F32A, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4a(x,y)', [Math.fround(13.37) + 4,5,8,6]); -CheckF4(F32A, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=cf4(f4a(x,y))', [Math.fround(13.37) + 4,5,8,6]); - -// 2.3.2. Subtracts -CheckI4(I32S, 'var x=i4(1,2,3,4); var y=i4(-1,1,0,2); x=i4s(x,y)', [2,1,3,2]); -CheckI4(I32S, 'var x=i4(5,4,3,2); var y=i4(1,2,3,4); x=i4s(x,y)', [4,2,0,-2]); -CheckI4(I32S, 'var x=i4(1,2,3,4); x=i4s(x,x)', [0,0,0,0]); -CheckI4(I32S, 'var x=i4(' + INT32_MIN + ',2,3,4); var y=i4(1,1,0,3); x=i4s(x,y)', [INT32_MAX,1,3,1]); -CheckI4(I32S, 'var x=i4(' + INT32_MIN + ',2,3,4); var y=i4(1,1,0,3); x=ci4(i4s(x,y))', [INT32_MAX,1,3,1]); - -CheckU4(U32S, 'var x=u4(1,2,3,4); var y=u4(-1,1,0,2); x=u4s(x,y)', [2,1,3,2]); -CheckU4(U32S, 'var x=u4(5,4,3,2); var y=u4(1,2,3,4); x=u4s(x,y)', [4,2,0,-2>>>0]); -CheckU4(U32S, 'var x=u4(1,2,3,4); x=u4s(x,x)', [0,0,0,0]); -CheckU4(U32S, 'var x=u4(' + INT32_MIN + ',2,3,4); var y=u4(1,1,0,3); x=u4s(x,y)', [INT32_MAX,1,3,1]); -CheckU4(U32S, 'var x=u4(' + INT32_MIN + ',2,3,4); var y=u4(1,1,0,3); x=cu4(u4s(x,y))', [INT32_MAX,1,3,1]); - -CheckF4(F32S, 'var x=f4(1,2,3,4); x=f4s(x,x)', [0,0,0,0]); -CheckF4(F32S, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4s(x,y)', [-3,-1,-2,2]); -CheckF4(F32S, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4s(x,y)', [Math.fround(13.37) - 4,-1,-2,2]); -CheckF4(F32S, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=cf4(f4s(x,y))', [Math.fround(13.37) - 4,-1,-2,2]); - -{ - // Bug 1216099 - let code = ` - "use asm"; - var f4 = global.SIMD.Float32x4; - var f4sub = f4.sub; - const zerox4 = f4(0.0, 0.0, 0.0, 0.0); - function f() { - var newVelx4 = f4(0.0, 0.0, 0.0, 0.0); - var newVelTruex4 = f4(0.0,0.0,0.0,0.0); - newVelTruex4 = f4sub(zerox4, newVelx4); - } - // return statement voluntarily missing - `; - assertAsmTypeFail('global', code); -} - -// 2.3.3. Multiplications / Divisions -assertAsmTypeFail('glob', USE_ASM + I32 + "var f4d=i4.div; function f() {} return f"); - -CheckI4(I32M, 'var x=i4(1,2,3,4); var y=i4(-1,1,0,2); x=i4m(x,y)', [-1,2,0,8]); -CheckI4(I32M, 'var x=i4(5,4,3,2); var y=i4(1,2,3,4); x=i4m(x,y)', [5,8,9,8]); -CheckI4(I32M, 'var x=i4(1,2,3,4); x=i4m(x,x)', [1,4,9,16]); -(function() { - var m = INT32_MIN, M = INT32_MAX, imul = Math.imul; - CheckI4(I32M, `var x=i4(${m},${m}, ${M}, ${M}); var y=i4(2,-3,4,-5); x=i4m(x,y)`, - [imul(m, 2), imul(m, -3), imul(M, 4), imul(M, -5)]); - CheckI4(I32M, `var x=i4(${m},${m}, ${M}, ${M}); var y=i4(${m}, ${M}, ${m}, ${M}); x=i4m(x,y)`, - [imul(m, m), imul(m, M), imul(M, m), imul(M, M)]); -})(); - -CheckF4(F32M, 'var x=f4(1,2,3,4); x=f4m(x,x)', [1,4,9,16]); -CheckF4(F32M, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4m(x,y)', [4,6,15,8]); -CheckF4(F32M, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4m(x,y)', [Math.fround(13.37) * 4,6,15,8]); -CheckF4(F32M, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=cf4(f4m(x,y))', [Math.fround(13.37) * 4,6,15,8]); - -var f32x4 = SIMD.Float32x4(0, NaN, -0, NaN); -var another = SIMD.Float32x4(NaN, -1, -0, NaN); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32M + CF32 + "function f(x, y) {x=cf4(x); y=cf4(y); x=f4m(x,y); return cf4(x);} return f"), this)(f32x4, another), [NaN, NaN, 0, NaN]); - -CheckF4(F32D, 'var x=f4(1,2,3,4); x=f4d(x,x)', [1,1,1,1]); -CheckF4(F32D, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4d(x,y)', [1/4,2/3,3/5,2]); -CheckF4(F32D, 'var x=f4(13.37,1,1,4); var y=f4(4,0,-0.,2); x=f4d(x,y)', [Math.fround(13.37) / 4,+Infinity,-Infinity,2]); - -var f32x4 = SIMD.Float32x4(0, 0, -0, NaN); -var another = SIMD.Float32x4(0, -0, 0, 0); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32D + CF32 + "function f(x,y) {x=cf4(x); y=cf4(y); x=f4d(x,y); return cf4(x);} return f"), this)(f32x4, another), [NaN, NaN, NaN, NaN]); - -// Unary arithmetic operators -function CheckUnaryF4(op, checkFunc, assertFunc) { - var _ = asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + 'var op=f4.' + op + '; function f(x){x=cf4(x); return cf4(op(x)); } return f'), this); - return function(input) { - var simd = SIMD.Float32x4(input[0], input[1], input[2], input[3]); - - var exp = input.map(Math.fround).map(checkFunc).map(Math.fround); - var obs = _(simd); - assertEqX4(obs, exp, assertFunc); - } -} - -function CheckUnaryI4(op, checkFunc) { - var _ = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + 'var op=i4.' + op + '; function f(x){x=ci4(x); return ci4(op(x)); } return f'), this); - return function(input) { - var simd = SIMD.Int32x4(input[0], input[1], input[2], input[3]); - assertEqX4(_(simd), input.map(checkFunc).map(function(x) { return x | 0})); - } -} - -function CheckUnaryU4(op, checkFunc) { - var _ = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32U32 + U32 + U32I32 + - 'var op=u4.' + op + '; function f(x){x=ci4(x); return ci4(i4u4(op(u4i4(x)))); } return f'), this); - return function(input) { - var simd = SIMD.Int32x4(input[0], input[1], input[2], input[3]); - var res = SIMD.Uint32x4.fromInt32x4Bits(_(simd)); - assertEqX4(res, input.map(checkFunc).map(function(x) { return x >>> 0 })); - } -} - -function CheckUnaryB4(op, checkFunc) { - var _ = asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + 'var op=b4.' + op + '; function f(x){x=cb4(x); return cb4(op(x)); } return f'), this); - return function(input) { - var simd = SIMD.Bool32x4(input[0], input[1], input[2], input[3]); - assertEqX4(_(simd), input.map(checkFunc).map(function(x) { return !!x})); - } -} - -CheckUnaryI4('neg', function(x) { return -x })([1, -2, INT32_MIN, INT32_MAX]); -CheckUnaryI4('not', function(x) { return ~x })([1, -2, INT32_MIN, INT32_MAX]); - -CheckUnaryU4('neg', function(x) { return -x })([1, -2, INT32_MIN, INT32_MAX]); -CheckUnaryU4('not', function(x) { return ~x })([1, -2, INT32_MIN, INT32_MAX]); - -var CheckNotB = CheckUnaryB4('not', function(x) { return !x }); -CheckNotB([true, false, true, true]); -CheckNotB([true, true, true, true]); -CheckNotB([false, false, false, false]); - -var CheckAbs = CheckUnaryF4('abs', Math.abs); -CheckAbs([1, 42.42, 0.63, 13.37]); -CheckAbs([NaN, -Infinity, Infinity, 0]); - -var CheckNegF = CheckUnaryF4('neg', function(x) { return -x }); -CheckNegF([1, 42.42, 0.63, 13.37]); -CheckNegF([NaN, -Infinity, Infinity, 0]); - -var CheckSqrt = CheckUnaryF4('sqrt', function(x) { return Math.sqrt(x); }); -CheckSqrt([1, 42.42, 0.63, 13.37]); -CheckSqrt([NaN, -Infinity, Infinity, 0]); - -// ReciprocalApproximation and reciprocalSqrtApproximation give approximate results -function assertNear(a, b) { - if (a !== a && b === b) - throw 'Observed NaN, expected ' + b; - if (Math.abs(a - b) > 1e-3) - throw 'More than 1e-3 between ' + a + ' and ' + b; -} -var CheckRecp = CheckUnaryF4('reciprocalApproximation', function(x) { return 1 / x; }, assertNear); -CheckRecp([1, 42.42, 0.63, 13.37]); -CheckRecp([NaN, -Infinity, Infinity, 0]); - -var CheckRecp = CheckUnaryF4('reciprocalSqrtApproximation', function(x) { return 1 / Math.sqrt(x); }, assertNear); -CheckRecp([1, 42.42, 0.63, 13.37]); -CheckRecp([NaN, -Infinity, Infinity, 0]); - -// Min/Max -assertAsmTypeFail('glob', USE_ASM + I32 + "var f4m=i4.min; function f() {} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var f4d=i4.max; function f() {} return f"); - -const F32MIN = 'var min = f4.min;' -const F32MAX = 'var max = f4.max;' - -CheckF4(F32MIN, 'var x=f4(1,2,3,4); x=min(x,x)', [1,2,3,4]); -CheckF4(F32MIN, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=min(x,y)', [4,2,3,2]); -CheckF4(F32MIN + FROUND + 'var Infinity = glob.Infinity;', 'var x=f4(0,0,0,0); var y=f4(2310,3,5,0); x=f4(f32(+Infinity),f32(-Infinity),f32(3),f32(-0.)); x=min(x,y)', [2310,-Infinity,3,-0]); - -CheckF4(F32MIN, 'var x=f4(0,0,-0,-0); var y=f4(0,-0,0,-0); x=min(x,y)', [0,-0,-0,-0]); -CheckF4(F32MIN + FROUND + 'var NaN = glob.NaN;', 'var x=f4(0,0,0,0); var y=f4(0,0,0,0); var n=f32(0); n=f32(NaN); x=f4(n,0.,n,0.); y=f4(n,n,0.,0.); x=min(x,y)', [NaN, NaN, NaN, 0]); - -CheckF4(F32MAX, 'var x=f4(1,2,3,4); x=max(x,x)', [1,2,3,4]); -CheckF4(F32MAX, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=max(x,y)', [13.37, 3, 5, 4]); -CheckF4(F32MAX + FROUND + 'var Infinity = glob.Infinity;', 'var x=f4(0,0,0,0); var y=f4(2310,3,5,0); x=f4(f32(+Infinity),f32(-Infinity),f32(3),f32(-0.)); x=max(x,y)', [+Infinity,3,5,0]); - -CheckF4(F32MAX, 'var x=f4(0,0,-0,-0); var y=f4(0,-0,0,-0); x=max(x,y)', [0,0,0,-0]); -CheckF4(F32MAX + FROUND + 'var NaN = glob.NaN;', 'var x=f4(0,0,0,0); var y=f4(0,0,0,0); var n=f32(0); n=f32(NaN); x=f4(n,0.,n,0.); y=f4(n,n,0.,0.); x=max(x,y)', [NaN, NaN, NaN, 0]); - -const F32MINNUM = 'var min = f4.minNum;' -const F32MAXNUM = 'var max = f4.maxNum;' - -CheckF4(F32MINNUM, 'var x=f4(1,2,3,4); x=min(x,x)', [1,2,3,4]); -CheckF4(F32MINNUM, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=min(x,y)', [4,2,3,2]); -CheckF4(F32MINNUM + FROUND + 'var Infinity = glob.Infinity;', 'var x=f4(0,0,0,0); var y=f4(2310,3,5,0); x=f4(f32(+Infinity),f32(-Infinity),f32(3),f32(-0.)); x=min(x,y)', [2310,-Infinity,3,-0]); - -CheckF4(F32MINNUM, 'var x=f4(0,0,-0,-0); var y=f4(0,-0,0,-0); x=min(x,y)', [0,-0,-0,-0]); -CheckF4(F32MINNUM + FROUND + 'var NaN = glob.NaN;', 'var x=f4(0,0,0,0); var y=f4(0,0,0,0); var n=f32(0); n=f32(NaN); x=f4(n,0.,n,0.); y=f4(n,n,0.,0.); x=min(x,y)', [NaN, 0, 0, 0]); - -CheckF4(F32MAXNUM, 'var x=f4(1,2,3,4); x=max(x,x)', [1,2,3,4]); -CheckF4(F32MAXNUM, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=max(x,y)', [13.37, 3, 5, 4]); -CheckF4(F32MAXNUM + FROUND + 'var Infinity = glob.Infinity;', 'var x=f4(0,0,0,0); var y=f4(2310,3,5,0); x=f4(f32(+Infinity),f32(-Infinity),f32(3),f32(-0.)); x=max(x,y)', [+Infinity,3,5,0]); - -CheckF4(F32MAXNUM, 'var x=f4(0,0,-0,-0); var y=f4(0,-0,0,-0); x=max(x,y)', [0,0,0,-0]); -CheckF4(F32MAXNUM + FROUND + 'var NaN = glob.NaN;', 'var x=f4(0,0,0,0); var y=f4(0,0,0,0); var n=f32(0); n=f32(NaN); x=f4(n,0.,n,0.); y=f4(n,n,0.,0.); x=max(x,y)', [NaN, 0, 0, 0]); - -// ReplaceLane -const RLF = 'var r = f4.replaceLane;'; - -assertAsmTypeFail('glob', USE_ASM + F32 + RLF + "function f() {var x = f4(1,2,3,4); x = r(x, 0, 1);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + RLF + "function f() {var x = f4(1,2,3,4); x = r(x, 0, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(x, 4, f32(1));} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(x, f32(0), f32(1));} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(1, 0, f32(1));} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(1, 0., f32(1));} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); x = r(f32(1), 0, f32(1));} return f"); -assertAsmTypeFail('glob', USE_ASM + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); var l = 0; x = r(x, l, f32(1));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + RLF + FROUND + "function f() {var x = f4(1,2,3,4); var y = i4(1,2,3,4); x = r(y, 0, f32(1));} return f"); - -CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 0, f32(13.37));', [Math.fround(13.37), 2, 3, 4]); -CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 1, f32(13.37));', [1, Math.fround(13.37), 3, 4]); -CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 2, f32(13.37));', [1, 2, Math.fround(13.37), 4]); -CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 3, f32(13.37));', [1, 2, 3, Math.fround(13.37)]); -CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 3, f32(13.37) + f32(6.63));', [1, 2, 3, Math.fround(Math.fround(13.37) + Math.fround(6.63))]); - -CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 0, 13.37);', [Math.fround(13.37), 2, 3, 4]); -CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 1, 13.37);', [1, Math.fround(13.37), 3, 4]); -CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 2, 13.37);', [1, 2, Math.fround(13.37), 4]); -CheckF4(RLF + FROUND, 'var x = f4(1,2,3,4); x = r(x, 3, 13.37);', [1, 2, 3, Math.fround(13.37)]); - -const RLI = 'var r = i4.replaceLane;'; -CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 0, 42);', [42, 2, 3, 4]); -CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 1, 42);', [1, 42, 3, 4]); -CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 2, 42);', [1, 2, 42, 4]); -CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 3, 42);', [1, 2, 3, 42]); - -const RLU = 'var r = u4.replaceLane;'; -CheckU4(RLU, 'var x = u4(1,2,3,4); x = r(x, 0, 42);', [42, 2, 3, 4]); -CheckU4(RLU, 'var x = u4(1,2,3,4); x = r(x, 1, 42);', [1, 42, 3, 4]); -CheckU4(RLU, 'var x = u4(1,2,3,4); x = r(x, 2, 42);', [1, 2, 42, 4]); -CheckU4(RLU, 'var x = u4(1,2,3,4); x = r(x, 3, 42);', [1, 2, 3, 42]); - -const RLB = 'var r = b4.replaceLane;'; -CheckB4(RLB, 'var x = b4(1,1,0,0); x = r(x, 0, 0);', [false, true, false, false]); -CheckB4(RLB, 'var x = b4(1,1,0,0); x = r(x, 1, 0);', [true, false, false, false]); -CheckB4(RLB, 'var x = b4(1,1,0,0); x = r(x, 2, 2);', [true, true, true, false]); -CheckB4(RLB, 'var x = b4(1,1,0,0); x = r(x, 3, 1);', [true, true, false, true]); - -// Comparisons -// Comparison operators produce Bool32x4 vectors. -const T = true; -const F = false; - -const EQI32 = 'var eq = i4.equal'; -const NEI32 = 'var ne = i4.notEqual'; -const LTI32 = 'var lt = i4.lessThan;'; -const LEI32 = 'var le = i4.lessThanOrEqual'; -const GTI32 = 'var gt = i4.greaterThan;'; -const GEI32 = 'var ge = i4.greaterThanOrEqual'; - -CheckB4(I32+EQI32, 'var x=b4(0,0,0,0); var a=i4(1,2,3,4); var b=i4(-1,1,0,2); x=eq(a,b)', [F, F, F, F]); -CheckB4(I32+EQI32, 'var x=b4(0,0,0,0); var a=i4(-1,1,0,2); var b=i4(1,2,3,4); x=eq(a,b)', [F, F, F, F]); -CheckB4(I32+EQI32, 'var x=b4(0,0,0,0); var a=i4(1,0,3,4); var b=i4(1,1,7,0); x=eq(a,b)', [T, F, F, F]); - -CheckB4(I32+NEI32, 'var x=b4(0,0,0,0); var a=i4(1,2,3,4); var b=i4(-1,1,0,2); x=ne(a,b)', [T, T, T, T]); -CheckB4(I32+NEI32, 'var x=b4(0,0,0,0); var a=i4(-1,1,0,2); var b=i4(1,2,3,4); x=ne(a,b)', [T, T, T, T]); -CheckB4(I32+NEI32, 'var x=b4(0,0,0,0); var a=i4(1,0,3,4); var b=i4(1,1,7,0); x=ne(a,b)', [F, T, T, T]); - -CheckB4(I32+LTI32, 'var x=b4(0,0,0,0); var a=i4(1,2,3,4); var b=i4(-1,1,0,2); x=lt(a,b)', [F, F, F, F]); -CheckB4(I32+LTI32, 'var x=b4(0,0,0,0); var a=i4(-1,1,0,2); var b=i4(1,2,3,4); x=lt(a,b)', [T, T, T, T]); -CheckB4(I32+LTI32, 'var x=b4(0,0,0,0); var a=i4(1,0,3,4); var b=i4(1,1,7,0); x=lt(a,b)', [F, T, T, F]); - -CheckB4(I32+LEI32, 'var x=b4(0,0,0,0); var a=i4(1,2,3,4); var b=i4(-1,1,0,2); x=le(a,b)', [F, F, F, F]); -CheckB4(I32+LEI32, 'var x=b4(0,0,0,0); var a=i4(-1,1,0,2); var b=i4(1,2,3,4); x=le(a,b)', [T, T, T, T]); -CheckB4(I32+LEI32, 'var x=b4(0,0,0,0); var a=i4(1,0,3,4); var b=i4(1,1,7,0); x=le(a,b)', [T, T, T, F]); - -CheckB4(I32+GTI32, 'var x=b4(0,0,0,0); var a=i4(1,2,3,4); var b=i4(-1,1,0,2); x=gt(a,b)', [T, T, T, T]); -CheckB4(I32+GTI32, 'var x=b4(0,0,0,0); var a=i4(-1,1,0,2); var b=i4(1,2,3,4); x=gt(a,b)', [F, F, F, F]); -CheckB4(I32+GTI32, 'var x=b4(0,0,0,0); var a=i4(1,0,3,4); var b=i4(1,1,7,0); x=gt(a,b)', [F, F, F, T]); - -CheckB4(I32+GEI32, 'var x=b4(0,0,0,0); var a=i4(1,2,3,4); var b=i4(-1,1,0,2); x=ge(a,b)', [T, T, T, T]); -CheckB4(I32+GEI32, 'var x=b4(0,0,0,0); var a=i4(-1,1,0,2); var b=i4(1,2,3,4); x=ge(a,b)', [F, F, F, F]); -CheckB4(I32+GEI32, 'var x=b4(0,0,0,0); var a=i4(1,0,3,4); var b=i4(1,1,7,0); x=ge(a,b)', [T, F, F, T]); - -const EQU32 = 'var eq = u4.equal'; -const NEU32 = 'var ne = u4.notEqual'; -const LTU32 = 'var lt = u4.lessThan;'; -const LEU32 = 'var le = u4.lessThanOrEqual'; -const GTU32 = 'var gt = u4.greaterThan;'; -const GEU32 = 'var ge = u4.greaterThanOrEqual'; - -CheckB4(U32+EQU32, 'var x=b4(0,0,0,0); var a=u4(1,2,3,4); var b=u4(-1,1,0,2); x=eq(a,b)', [F, F, F, F]); -CheckB4(U32+EQU32, 'var x=b4(0,0,0,0); var a=u4(-1,1,0,2); var b=u4(1,2,3,4); x=eq(a,b)', [F, F, F, F]); -CheckB4(U32+EQU32, 'var x=b4(0,0,0,0); var a=u4(1,0,3,4); var b=u4(1,1,7,0); x=eq(a,b)', [T, F, F, F]); - -CheckB4(U32+NEU32, 'var x=b4(0,0,0,0); var a=u4(1,2,3,4); var b=u4(-1,1,0,2); x=ne(a,b)', [T, T, T, T]); -CheckB4(U32+NEU32, 'var x=b4(0,0,0,0); var a=u4(-1,1,0,2); var b=u4(1,2,3,4); x=ne(a,b)', [T, T, T, T]); -CheckB4(U32+NEU32, 'var x=b4(0,0,0,0); var a=u4(1,0,3,4); var b=u4(1,1,7,0); x=ne(a,b)', [F, T, T, T]); - -CheckB4(U32+LTU32, 'var x=b4(0,0,0,0); var a=u4(1,2,3,4); var b=u4(-1,1,0,2); x=lt(a,b)', [T, F, F, F]); -CheckB4(U32+LTU32, 'var x=b4(0,0,0,0); var a=u4(-1,1,0,2); var b=u4(1,2,3,4); x=lt(a,b)', [F, T, T, T]); -CheckB4(U32+LTU32, 'var x=b4(0,0,0,0); var a=u4(1,0,3,4); var b=u4(1,1,7,0); x=lt(a,b)', [F, T, T, F]); - -CheckB4(U32+LEU32, 'var x=b4(0,0,0,0); var a=u4(1,2,3,4); var b=u4(-1,1,0,2); x=le(a,b)', [T, F, F, F]); -CheckB4(U32+LEU32, 'var x=b4(0,0,0,0); var a=u4(-1,1,0,2); var b=u4(1,2,3,4); x=le(a,b)', [F, T, T, T]); -CheckB4(U32+LEU32, 'var x=b4(0,0,0,0); var a=u4(1,0,3,4); var b=u4(1,1,7,0); x=le(a,b)', [T, T, T, F]); - -CheckB4(U32+GTU32, 'var x=b4(0,0,0,0); var a=u4(1,2,3,4); var b=u4(-1,1,0,2); x=gt(a,b)', [F, T, T, T]); -CheckB4(U32+GTU32, 'var x=b4(0,0,0,0); var a=u4(-1,1,0,2); var b=u4(1,2,3,4); x=gt(a,b)', [T, F, F, F]); -CheckB4(U32+GTU32, 'var x=b4(0,0,0,0); var a=u4(1,0,3,4); var b=u4(1,1,7,0); x=gt(a,b)', [F, F, F, T]); - -CheckB4(U32+GEU32, 'var x=b4(0,0,0,0); var a=u4(1,2,3,4); var b=u4(-1,1,0,2); x=ge(a,b)', [F, T, T, T]); -CheckB4(U32+GEU32, 'var x=b4(0,0,0,0); var a=u4(-1,1,0,2); var b=u4(1,2,3,4); x=ge(a,b)', [T, F, F, F]); -CheckB4(U32+GEU32, 'var x=b4(0,0,0,0); var a=u4(1,0,3,4); var b=u4(1,1,7,0); x=ge(a,b)', [T, F, F, T]); - -const LTF32 = 'var lt=f4.lessThan;'; -const LEF32 = 'var le=f4.lessThanOrEqual;'; -const GTF32 = 'var gt=f4.greaterThan;'; -const GEF32 = 'var ge=f4.greaterThanOrEqual;'; -const EQF32 = 'var eq=f4.equal;'; -const NEF32 = 'var ne=f4.notEqual;'; - -assertAsmTypeFail('glob', USE_ASM + F32 + "var lt=f4.lessThan; function f() {var x=f4(1,2,3,4); var y=f4(5,6,7,8); x=lt(x,y);} return f"); - -CheckB4(F32+LTF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=b4(0,0,0,0); x=lt(y,z)', [F, F, F, F]); -CheckB4(F32+LTF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=b4(0,0,0,0); x=lt(y,z)', [T, T, T, T]); -CheckB4(F32+LTF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=b4(0,0,0,0); x=lt(y,z)', [F, T, T, F]); -CheckB4(F32+LTF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=b4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=lt(y,z);', [F, F, F, F]); - -CheckB4(F32+LEF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=b4(0,0,0,0); x=le(y,z)', [F, F, F, F]); -CheckB4(F32+LEF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=b4(0,0,0,0); x=le(y,z)', [T, T, T, T]); -CheckB4(F32+LEF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=b4(0,0,0,0); x=le(y,z)', [T, T, T, F]); -CheckB4(F32+LEF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=b4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=le(y,z);', [T, T, F, F]); - -CheckB4(F32+EQF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=b4(0,0,0,0); x=eq(y,z)', [F, F, F, F]); -CheckB4(F32+EQF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=b4(0,0,0,0); x=eq(y,z)', [F, F, F, F]); -CheckB4(F32+EQF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=b4(0,0,0,0); x=eq(y,z)', [T, F, F, F]); -CheckB4(F32+EQF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=b4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=eq(y,z);', [T, T, F, F]); - -CheckB4(F32+NEF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=b4(0,0,0,0); x=ne(y,z)', [T, T, T, T]); -CheckB4(F32+NEF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=b4(0,0,0,0); x=ne(y,z)', [T, T, T, T]); -CheckB4(F32+NEF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=b4(0,0,0,0); x=ne(y,z)', [F, T, T, T]); -CheckB4(F32+NEF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=b4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=ne(y,z);', [F, F, T, T]); - -CheckB4(F32+GTF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=b4(0,0,0,0); x=gt(y,z)', [T, T, T, T]); -CheckB4(F32+GTF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=b4(0,0,0,0); x=gt(y,z)', [F, F, F, F]); -CheckB4(F32+GTF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=b4(0,0,0,0); x=gt(y,z)', [F, F, F, T]); -CheckB4(F32+GTF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=b4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=gt(y,z);', [F, F, F, F]); - -CheckB4(F32+GEF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=b4(0,0,0,0); x=ge(y,z)', [T, T, T, T]); -CheckB4(F32+GEF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=b4(0,0,0,0); x=ge(y,z)', [F, F, F, F]); -CheckB4(F32+GEF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=b4(0,0,0,0); x=ge(y,z)', [T, F, F, T]); -CheckB4(F32+GEF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=b4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=ge(y,z);', [T, T, F, F]); - -var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + LTI32 + B32 + ANYB4 + 'function f(x){x=ci4(x); var y=i4(-1,0,4,5); var b=b4(0,0,0,0); b=lt(x,y); return anyt(b)|0;} return f'), this); -assertEq(f(SIMD.Int32x4(1,2,3,4)), 1); -assertEq(f(SIMD.Int32x4(1,2,4,5)), 0); -assertEq(f(SIMD.Int32x4(1,2,3,5)), 1); - -var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + LTI32 + B32 + ALLB4 + 'function f(x){x=ci4(x); var y=i4(-1,0,4,5); var b=b4(0,0,0,0); b=lt(x,y); return allt(b)|0;} return f'), this); -assertEq(f(SIMD.Int32x4(-2,-2,3,4)), 1); -assertEq(f(SIMD.Int32x4(1,2,4,5)), 0); -assertEq(f(SIMD.Int32x4(1,2,3,5)), 0); - -// Conversions operators -const CVTIF = 'var cvt=f4.fromInt32x4;'; -const CVTFI = 'var cvt=i4.fromFloat32x4;'; -const CVTUF = 'var cvt=f4.fromUint32x4;'; -const CVTFU = 'var cvt=u4.fromFloat32x4;'; - -assertAsmTypeFail('glob', USE_ASM + I32 + "var cvt=i4.fromInt32x4; return {}"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var cvt=i4.fromUint32x4; return {}"); -assertAsmTypeFail('glob', USE_ASM + U32 + "var cvt=u4.fromInt32x4; return {}"); -assertAsmTypeFail('glob', USE_ASM + U32 + "var cvt=u4.fromUint32x4; return {}"); -assertAsmTypeFail('glob', USE_ASM + F32 + "var cvt=f4.fromFloat32x4; return {}"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIF + "function f() {var x=i4(1,2,3,4); x=cvt(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIF + "function f() {var x=f4(1,2,3,4); x=cvt(x);} return f"); - -var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + CI32 + CVTIF + 'function f(x){x=ci4(x); var y=f4(0,0,0,0); y=cvt(x); return cf4(y);} return f'), this); -assertEqX4(f(SIMD.Int32x4(1,2,3,4)), [1, 2, 3, 4]); -assertEqX4(f(SIMD.Int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, Math.fround(INT32_MIN), Math.fround(INT32_MAX), -1]); - -var f = asmLink(asmCompile('glob', USE_ASM + I32 + U32 + U32I32 + F32 + CF32 + CI32 + CVTUF + - 'function f(x){x=ci4(x); var y=f4(0,0,0,0); y=cvt(u4i4(x)); return cf4(y);} return f'), this); -assertEqX4(f(SIMD.Int32x4(1,2,3,4)), [1, 2, 3, 4]); -assertEqX4(f(SIMD.Int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, Math.fround(INT32_MAX+1), Math.fround(INT32_MAX), Math.fround(UINT32_MAX)]); - -var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + F32 + CF32 + CVTFI + 'function f(x){x=cf4(x); var y=i4(0,0,0,0); y=cvt(x); return ci4(y);} return f'), this); -assertEqX4(f(SIMD.Float32x4(1,2,3,4)), [1, 2, 3, 4]); -// Test that INT32_MIN (exactly representable as an float32) and the first -// integer representable as an float32 can be converted. -assertEqX4(f(SIMD.Float32x4(INT32_MIN, INT32_MAX - 64, -0, 0)), [INT32_MIN, INT32_MAX - 64, 0, 0].map(Math.fround)); -// Test boundaries: first integer less than INT32_MIN and representable as a float32 -assertThrowsInstanceOf(() => f(SIMD.Float32x4(INT32_MIN - 129, 0, 0, 0)), RangeError); -// INT_MAX + 1 -assertThrowsInstanceOf(() => f(SIMD.Float32x4(Math.pow(2, 31), 0, 0, 0)), RangeError); -// Special values -assertThrowsInstanceOf(() => f(SIMD.Float32x4(NaN, 0, 0, 0)), RangeError); -assertThrowsInstanceOf(() => f(SIMD.Float32x4(Infinity, 0, 0, 0)), RangeError); -assertThrowsInstanceOf(() => f(SIMD.Float32x4(-Infinity, 0, 0, 0)), RangeError); - -var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + U32 + I32U32 + F32 + CF32 + CVTFU + - 'function f(x){x=cf4(x); var y=u4(0,0,0,0); y=cvt(x); return ci4(i4u4(y));} return f'), this); -assertEqX4(f(SIMD.Float32x4(1,2,3,4)), [1, 2, 3, 4]); -// TODO: Test negative numbers > -1. They should truncate to 0. See https://github.com/tc39/ecmascript_simd/issues/315 -assertEqX4(SIMD.Uint32x4.fromInt32x4Bits(f(SIMD.Float32x4(0xffffff00, INT32_MAX+1, -0, 0))), - [0xffffff00, INT32_MAX+1, 0, 0].map(Math.fround)); -// Test boundaries: -1 or less. -assertThrowsInstanceOf(() => f(SIMD.Float32x4(-1, 0, 0, 0)), RangeError); -assertThrowsInstanceOf(() => f(SIMD.Float32x4(Math.pow(2, 32), 0, 0, 0)), RangeError); -// Special values -assertThrowsInstanceOf(() => f(SIMD.Float32x4(NaN, 0, 0, 0)), RangeError); -assertThrowsInstanceOf(() => f(SIMD.Float32x4(Infinity, 0, 0, 0)), RangeError); -assertThrowsInstanceOf(() => f(SIMD.Float32x4(-Infinity, 0, 0, 0)), RangeError); - -// Cast operators -const CVTIFB = 'var cvt=f4.fromInt32x4Bits;'; -const CVTFIB = 'var cvt=i4.fromFloat32x4Bits;'; - -var cast = (function() { - var i32 = new Int32Array(1); - var f32 = new Float32Array(i32.buffer); - - function fromInt32Bits(x) { - i32[0] = x; - return f32[0]; - } - - function fromFloat32Bits(x) { - f32[0] = x; - return i32[0]; - } - - return { - fromInt32Bits, - fromFloat32Bits - } -})(); - -assertAsmTypeFail('glob', USE_ASM + I32 + "var cvt=i4.fromInt32x4; return {}"); -assertAsmTypeFail('glob', USE_ASM + F32 + "var cvt=f4.fromFloat32x4; return {}"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIFB + "function f() {var x=i4(1,2,3,4); x=cvt(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIFB + "function f() {var x=f4(1,2,3,4); x=cvt(x);} return f"); - -var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CVTIFB + CF32 + CI32 + 'function f(x){x=ci4(x); var y=f4(0,0,0,0); y=cvt(x); return cf4(y);} return f'), this); -assertEqX4(f(SIMD.Int32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromInt32Bits)); -assertEqX4(f(SIMD.Int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, INT32_MIN, INT32_MAX, -1].map(cast.fromInt32Bits)); - -var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32A + CVTIFB + CF32 + CI32 + 'function f(x){x=ci4(x); var y=f4(0,0,0,0); var z=f4(1,1,1,1); y=cvt(x); y=f4a(y, z); return cf4(y)} return f'), this); -assertEqX4(f(SIMD.Int32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromInt32Bits).map((x) => x+1)); -assertEqX4(f(SIMD.Int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, INT32_MIN, INT32_MAX, -1].map(cast.fromInt32Bits).map((x) => x+1)); - -var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + F32 + CF32 + CVTFIB + 'function f(x){x=cf4(x); var y=i4(0,0,0,0); y=cvt(x); return ci4(y);} return f'), this); -assertEqX4(f(SIMD.Float32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromFloat32Bits)); -assertEqX4(f(SIMD.Float32x4(-0,NaN,+Infinity,-Infinity)), [-0, NaN, +Infinity, -Infinity].map(cast.fromFloat32Bits)); - -var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + F32 + CF32 + I32A + CVTFIB + 'function f(x){x=cf4(x); var y=i4(0,0,0,0); var z=i4(1,1,1,1); y=cvt(x); y=i4a(y,z); return ci4(y);} return f'), this); -assertEqX4(f(SIMD.Float32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromFloat32Bits).map((x) => x+1)); -assertEqX4(f(SIMD.Float32x4(-0,NaN,+Infinity,-Infinity)), [-0, NaN, +Infinity, -Infinity].map(cast.fromFloat32Bits).map((x) => x+1)); - -// Bitwise ops -const ANDI32 = 'var andd=i4.and;'; -const ORI32 = 'var orr=i4.or;'; -const XORI32 = 'var xorr=i4.xor;'; - -CheckI4(ANDI32, 'var x=i4(42,1337,-1,13); var y=i4(2, 4, 7, 15); x=andd(x,y)', [42 & 2, 1337 & 4, -1 & 7, 13 & 15]); -CheckI4(ORI32, ' var x=i4(42,1337,-1,13); var y=i4(2, 4, 7, 15); x=orr(x,y)', [42 | 2, 1337 | 4, -1 | 7, 13 | 15]); -CheckI4(XORI32, 'var x=i4(42,1337,-1,13); var y=i4(2, 4, 7, 15); x=xorr(x,y)', [42 ^ 2, 1337 ^ 4, -1 ^ 7, 13 ^ 15]); - -const ANDU32 = 'var andd=u4.and;'; -const ORU32 = 'var orr=u4.or;'; -const XORU32 = 'var xorr=u4.xor;'; - -CheckU4(ANDU32, 'var x=u4(42,1337,-1,13); var y=u4(2, 4, 7, 15); x=andd(x,y)', [42 & 2, 1337 & 4, (-1 & 7) >>> 0, 13 & 15]); -CheckU4(ORU32, ' var x=u4(42,1337,-1,13); var y=u4(2, 4, 7, 15); x=orr(x,y)', [42 | 2, 1337 | 4, (-1 | 7) >>> 0, 13 | 15]); -CheckU4(XORU32, 'var x=u4(42,1337,-1,13); var y=u4(2, 4, 7, 15); x=xorr(x,y)', [42 ^ 2, 1337 ^ 4, (-1 ^ 7) >>> 0, 13 ^ 15]); - -const ANDB32 = 'var andd=b4.and;'; -const ORB32 = 'var orr=b4.or;'; -const XORB32 = 'var xorr=b4.xor;'; - -CheckB4(ANDB32, 'var x=b4(1,0,1,0); var y=b4(1,1,0,0); x=andd(x,y)', [true, false, false, false]); -CheckB4(ORB32, ' var x=b4(1,0,1,0); var y=b4(1,1,0,0); x=orr(x,y)', [true, true, true, false]); -CheckB4(XORB32, 'var x=b4(1,0,1,0); var y=b4(1,1,0,0); x=xorr(x,y)', [false, true, true, false]); - -// No bitwise ops on Float32x4. -const ANDF32 = 'var andd=f4.and;'; -const ORF32 = 'var orr=f4.or;'; -const XORF32 = 'var xorr=f4.xor;'; -const NOTF32 = 'var nott=f4.not;'; - -assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + ANDF32 + 'function f() {var x=f4(42, 13.37,-1.42, 23.10); var y=f4(19.89, 2.4, 8.15, 16.36); x=andd(x,y);} return f'); -assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + ORF32 + 'function f() {var x=f4(42, 13.37,-1.42, 23.10); var y=f4(19.89, 2.4, 8.15, 16.36); x=orr(x,y);} return f'); -assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + XORF32 + 'function f() {var x=f4(42, 13.37,-1.42, 23.10); var y=f4(19.89, 2.4, 8.15, 16.36); x=xorr(x,y);} return f'); -assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + NOTF32 + 'function f() {var x=f4(42, 13.37,-1.42, 23.10); x=nott(x);} return f'); - -// Logical ops -const LSHI = 'var lsh=i4.shiftLeftByScalar;' -const RSHI = 'var rsh=i4.shiftRightByScalar;' - -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + F32 + FROUND + LSHI + "function f() {var x=f4(1,2,3,4); return ci4(lsh(x,f32(42)));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + F32 + FROUND + LSHI + "function f() {var x=f4(1,2,3,4); return ci4(lsh(x,42));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + FROUND + LSHI + "function f() {var x=i4(1,2,3,4); return ci4(lsh(x,42.0));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + FROUND + LSHI + "function f() {var x=i4(1,2,3,4); return ci4(lsh(x,f32(42)));} return f"); - -var input = 'i4(0, 1, ' + INT32_MIN + ', ' + INT32_MAX + ')'; -var vinput = [0, 1, INT32_MIN, INT32_MAX]; - -function Lsh(i) { return function(x) { return (x << (i & 31)) | 0 } } -function Rsh(i) { return function(x) { return (x >> (i & 31)) | 0 } } - -var asmLsh = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + LSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(lsh(v, x+y))} return f;'), this) -var asmRsh = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + RSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(rsh(v, x+y))} return f;'), this) - -for (var i = 1; i < 64; i++) { - CheckI4(LSHI, 'var x=' + input + '; x=lsh(x, ' + i + ')', vinput.map(Lsh(i))); - CheckI4(RSHI, 'var x=' + input + '; x=rsh(x, ' + i + ')', vinput.map(Rsh(i))); - - assertEqX4(asmLsh(i, 3), vinput.map(Lsh(i + 3))); - assertEqX4(asmRsh(i, 3), vinput.map(Rsh(i + 3))); -} - -// Same thing for Uint32x4. -const LSHU = 'var lsh=u4.shiftLeftByScalar;' -const RSHU = 'var rsh=u4.shiftRightByScalar;' - -input = 'u4(0, 1, 0x80008000, ' + INT32_MAX + ')'; -vinput = [0, 1, 0x80008000, INT32_MAX]; - -function uLsh(i) { return function(x) { return (x << (i & 31)) >>> 0 } } -function uRsh(i) { return function(x) { return (x >>> (i & 31)) } } - -// Need to bitcast to Int32x4 before returning result. -asmLsh = asmLink(asmCompile('glob', USE_ASM + U32 + CU32 + LSHU + I32 + CI32 + I32U32 + - 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(i4u4(lsh(v, x+y)));} return f;'), this) -asmRsh = asmLink(asmCompile('glob', USE_ASM + U32 + CU32 + RSHU + I32 + CI32 + I32U32 + - 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(i4u4(rsh(v, x+y)));} return f;'), this) - -for (var i = 1; i < 64; i++) { - // Constant shifts. - CheckU4(LSHU, 'var x=' + input + '; x=lsh(x, ' + i + ')', vinput.map(uLsh(i))); - CheckU4(RSHU, 'var x=' + input + '; x=rsh(x, ' + i + ')', vinput.map(uRsh(i))); - - // Dynamically computed shifts. The asm function returns a Int32x4. - assertEqX4(SIMD.Uint32x4.fromInt32x4Bits(asmLsh(i, 3)), vinput.map(uLsh(i + 3))); - assertEqX4(SIMD.Uint32x4.fromInt32x4Bits(asmRsh(i, 3)), vinput.map(uRsh(i + 3))); -} - -// Select -const I32SEL = 'var i4sel = i4.select;' -const U32SEL = 'var u4sel = u4.select;' -const F32SEL = 'var f4sel = f4.select;' - -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var x=f4(1,2,3,4); return ci4(i4sel(x,x,x));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=f4(1,2,3,4); var x=i4(1,2,3,4); return ci4(i4sel(m,x,x));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=f4(1,2,3,4); var x=f4(1,2,3,4); return ci4(i4sel(m,x,x));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); return ci4(i4sel(m,x,x));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=i4(1,2,3,4); return ci4(i4sel(m,x,x));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=b4(1,2,3,4); var x=f4(1,2,3,4); return ci4(i4sel(m,x,x));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=b4(1,2,3,4); var x=f4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=b4(1,2,3,4); var x=i4(1,2,3,4); var y=f4(5,6,7,8); return ci4(i4sel(m,x,y));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=b4(1,2,3,4); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return ci4(i4sel(m,x,y));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=b4(1,2,3,4); var x=i4(1,2,3,4); var y=b4(5,6,7,8); return ci4(i4sel(m,x,y));} return f"); - -assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + F32SEL + "function f() {var m=f4(1,2,3,4); return cf4(f4sel(x,x,x));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=f4(1,2,3,4); var x=i4(1,2,3,4); return cf4(f4sel(m,x,x));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=f4(1,2,3,4); var x=f4(1,2,3,4); return cf4(f4sel(m,x,x));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); var y=i4(5,6,7,8); return cf4(f4sel(m,x,y));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(1,2,3,4); var x=i4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y));} return f"); - -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + CI32 + I32SEL + "function f() {var m=b4(0,0,0,0); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + CI32 + I32SEL + "function f() {var m=b4(1,1,1,1); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + CI32 + I32SEL + "function f() {var m=b4(0,1,0,1); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + CI32 + I32SEL + "function f() {var m=b4(0,0,1,1); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]); - -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + F32 + CF32 + F32SEL + "function f() {var m=b4(0,0,0,0); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + F32 + CF32 + F32SEL + "function f() {var m=b4(1,1,1,1); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + F32 + CF32 + F32SEL + "function f() {var m=b4(0,1,0,1); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + F32 + CF32 + F32SEL + "function f() {var m=b4(0,0,1,1); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]); - -CheckU4(B32 + U32SEL, "var m=b4(0,0,0,0); var x=u4(1,2,3,4); var y=u4(5,6,7,8); x=u4sel(m,x,y);", [5, 6, 7, 8]); -CheckU4(B32 + U32SEL, "var m=b4(1,1,1,1); var x=u4(1,2,3,4); var y=u4(5,6,7,8); x=u4sel(m,x,y);", [1, 2, 3, 4]); -CheckU4(B32 + U32SEL, "var m=b4(0,1,0,1); var x=u4(1,2,3,4); var y=u4(5,6,7,8); x=u4sel(m,x,y);", [5, 2, 7, 4]); -CheckU4(B32 + U32SEL, "var m=b4(0,0,1,1); var x=u4(1,2,3,4); var y=u4(5,6,7,8); x=u4sel(m,x,y);", [5, 6, 3, 4]); - -// Splat -const I32SPLAT = 'var splat=i4.splat;' -const U32SPLAT = 'var splat=u4.splat;' -const F32SPLAT = 'var splat=f4.splat;' -const B32SPLAT = 'var splat=b4.splat;' - -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32SPLAT + "function f() {var m=i4(1,2,3,4); var p=f4(1.,2.,3.,4.); p=splat(f32(1));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + "function f() {var m=i4(1,2,3,4); m=splat(1, 2)} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + "function f() {var m=i4(1,2,3,4); m=splat()} return f"); - -assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + "function f() {var m=i4(1,2,3,4); m=splat(m);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + "function f() {var m=i4(1,2,3,4); m=splat(1.0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + FROUND + "function f() {var m=i4(1,2,3,4); m=splat(f32(1.0));} return f"); - -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SPLAT + 'function f(){return ci4(splat(42));} return f'), this)(), [42, 42, 42, 42]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + B32SPLAT + 'function f(){return cb4(splat(42));} return f'), this)(), [true, true, true, true]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + B32SPLAT + 'function f(){return cb4(splat(0));} return f'), this)(), [false, false, false, false]); -CheckU4(B32 + U32SPLAT, "var x=u4(1,2,3,4); x=splat(0);", [0, 0, 0, 0]); -CheckU4(B32 + U32SPLAT, "var x=u4(1,2,3,4); x=splat(0xaabbccdd);", [0xaabbccdd, 0xaabbccdd, 0xaabbccdd, 0xaabbccdd]); - -const l33t = Math.fround(13.37); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + F32SPLAT + FROUND + 'function f(){return cf4(splat(f32(1)));} return f'), this)(), [1, 1, 1, 1]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + F32SPLAT + FROUND + 'function f(){return cf4(splat(1.0));} return f'), this)(), [1, 1, 1, 1]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + F32SPLAT + FROUND + 'function f(){return cf4(splat(f32(1 >>> 0)));} return f'), this)(), [1, 1, 1, 1]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + F32SPLAT + FROUND + 'function f(){return cf4(splat(f32(13.37)));} return f'), this)(), [l33t, l33t, l33t, l33t]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + F32SPLAT + FROUND + 'function f(){return cf4(splat(13.37));} return f'), this)(), [l33t, l33t, l33t, l33t]); - -var i32view = new Int32Array(heap); -var f32view = new Float32Array(heap); -i32view[0] = 42; -assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + I32 + CI32 + I32SPLAT + 'var i32=new glob.Int32Array(heap); function f(){return ci4(splat(i32[0]));} return f'), this, {}, heap)(), [42, 42, 42, 42]); -f32view[0] = 42; -assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + F32 + CF32 + F32SPLAT + 'var f32=new glob.Float32Array(heap); function f(){return cf4(splat(f32[0]));} return f'), this, {}, heap)(), [42, 42, 42, 42]); -assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + F32 + CF32 + F32SPLAT + FROUND + 'function f(){return cf4(splat(f32(1) + f32(2)));} return f'), this, {}, heap)(), [3, 3, 3, 3]); - -// Dead code -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + 'function f(){var x=i4(1,2,3,4); return ci4(x); x=i4(5,6,7,8); return ci4(x);} return f'), this)(), [1, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + EXTI4 + 'function f(){var x=i4(1,2,3,4); var c=0; return ci4(x); c=e(x,0)|0; return ci4(x);} return f'), this)(), [1, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32A + 'function f(){var x=i4(1,2,3,4); var c=0; return ci4(x); x=i4a(x,x); return ci4(x);} return f'), this)(), [1, 2, 3, 4]); -assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32S + 'function f(){var x=i4(1,2,3,4); var c=0; return ci4(x); x=i4s(x,x); return ci4(x);} return f'), this)(), [1, 2, 3, 4]); - -// Swizzle -assertAsmTypeFail('glob', USE_ASM + I32 + "var swizzle=i4.swizzle; function f() {var x=i4(1,2,3,4); x=swizzle(x, -1, 0, 0, 0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var swizzle=i4.swizzle; function f() {var x=i4(1,2,3,4); x=swizzle(x, 4, 0, 0, 0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var swizzle=i4.swizzle; function f() {var x=i4(1,2,3,4); x=swizzle(x, 0.0, 0, 0, 0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var swizzle=i4.swizzle; function f() {var x=i4(1,2,3,4); x=swizzle(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var swizzle=i4.swizzle; function f() {var x=i4(1,2,3,4); x=swizzle(x, 0, 0, 0, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var swizzle=i4.swizzle; function f() {var x=i4(1,2,3,4); var y=42; x=swizzle(x, 0, 0, 0, y);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "var swizzle=i4.swizzle; function f() {var x=f4(1,2,3,4); x=swizzle(x, 0, 0, 0, 0);} return f"); - -function swizzle(arr, lanes) { - return [arr[lanes[0]], arr[lanes[1]], arr[lanes[2]], arr[lanes[3]]]; -} - -var before = Date.now(); -for (var i = 0; i < Math.pow(4, 4); i++) { - var lanes = [i & 3, (i >> 2) & 3, (i >> 4) & 3, (i >> 6) & 3]; - CheckI4('var swizzle=i4.swizzle;', 'var x=i4(1,2,3,4); x=swizzle(x, ' + lanes.join(',') + ')', swizzle([1,2,3,4], lanes)); - CheckU4('var swizzle=u4.swizzle;', 'var x=u4(1,2,3,4); x=swizzle(x, ' + lanes.join(',') + ')', swizzle([1,2,3,4], lanes)); - CheckF4('var swizzle=f4.swizzle;', 'var x=f4(1,2,3,4); x=swizzle(x, ' + lanes.join(',') + ')', swizzle([1,2,3,4], lanes)); -} -DEBUG && print('time for checking all swizzles:', Date.now() - before); - -// Shuffle -assertAsmTypeFail('glob', USE_ASM + I32 + "var shuffle=i4.shuffle; function f() {var x=i4(1,2,3,4); var y=i4(1,2,3,4); x=shuffle(x, y, -1, 0, 0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var shuffle=i4.shuffle; function f() {var x=i4(1,2,3,4); var y=i4(1,2,3,4); x=shuffle(x, y, 8, 0, 0, 0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var shuffle=i4.shuffle; function f() {var x=i4(1,2,3,4); var y=i4(1,2,3,4); x=shuffle(x, y, 0.0, 0, 0, 0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var shuffle=i4.shuffle; function f() {var x=i4(1,2,3,4); var y=i4(1,2,3,4); x=shuffle(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var shuffle=i4.shuffle; function f() {var x=i4(1,2,3,4); var y=i4(1,2,3,4); x=shuffle(x, 0, 0, 0, 0, 0);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var shuffle=i4.shuffle; function f() {var x=i4(1,2,3,4); var y=i4(1,2,3,4); x=shuffle(x, y, 0, 0, 0, x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var shuffle=i4.shuffle; function f() {var x=i4(1,2,3,4); var y=i4(1,2,3,4); var z=42; x=shuffle(x, y, 0, 0, 0, z);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "var shuffle=i4.shuffle; function f() {var x=f4(1,2,3,4); x=shuffle(x, x, 0, 0, 0, 0);} return f"); - -function shuffle(lhs, rhs, lanes) { - return [(lanes[0] < 4 ? lhs : rhs)[lanes[0] % 4], - (lanes[1] < 4 ? lhs : rhs)[lanes[1] % 4], - (lanes[2] < 4 ? lhs : rhs)[lanes[2] % 4], - (lanes[3] < 4 ? lhs : rhs)[lanes[3] % 4]]; -} - -before = Date.now(); - -const LANE_SELECTORS = [ - // Four of lhs or four of rhs, equivalent to swizzle - [0, 1, 2, 3], - [4, 5, 6, 7], - [0, 2, 3, 1], - [4, 7, 4, 6], - // One of lhs, three of rhs - [0, 4, 5, 6], - [4, 0, 5, 6], - [4, 5, 0, 6], - [4, 5, 6, 0], - // Two of lhs, two of rhs - // in one shufps - [1, 2, 4, 5], - [4, 5, 1, 2], - // in two shufps - [7, 0, 5, 2], - [0, 7, 5, 2], - [0, 7, 2, 5], - [7, 0, 2, 5], - // Three of lhs, one of rhs - [7, 0, 1, 2], - [0, 7, 1, 2], - [0, 1, 7, 2], - [0, 1, 2, 7], - // Impl-specific special cases for swizzle - [2, 3, 2, 3], - [0, 1, 0, 1], - [0, 0, 1, 1], - [2, 2, 3, 3], - // Impl-specific special cases for shuffle (case and swapped case) - [2, 3, 6, 7], [6, 7, 2, 3], - [0, 1, 4, 5], [4, 5, 0, 1], - [0, 4, 1, 5], [4, 0, 5, 1], - [2, 6, 3, 7], [6, 2, 7, 3], - [4, 1, 2, 3], [0, 5, 6, 7], - // Insert one element from rhs into lhs keeping other elements unchanged - [7, 1, 2, 3], - [0, 7, 2, 3], - [0, 1, 7, 2], - // These are effectively vector selects - [0, 5, 2, 3], - [0, 1, 6, 3], - [4, 5, 2, 3], - [4, 1, 6, 3] -]; - -for (var lanes of LANE_SELECTORS) { - CheckI4('var shuffle=i4.shuffle;', 'var x=i4(1,2,3,4); var y=i4(5,6,7,8); x=shuffle(x, y, ' + lanes.join(',') + ')', shuffle([1,2,3,4], [5,6,7,8], lanes)); - CheckU4('var shuffle=u4.shuffle;', 'var x=u4(1,2,3,4); var y=u4(5,6,7,8); x=shuffle(x, y, ' + lanes.join(',') + ')', shuffle([1,2,3,4], [5,6,7,8], lanes)); - CheckF4('var shuffle=f4.shuffle;', 'var x=f4(1,2,3,4); var y=f4(5,6,7,8); x=shuffle(x, y, ' + lanes.join(',') + ')', shuffle([1,2,3,4], [5,6,7,8], lanes)); -} -DEBUG && print('time for checking all shuffles:', Date.now() - before); - -// 3. Function calls -// 3.1. No math builtins -assertAsmTypeFail('glob', USE_ASM + I32 + "var fround=glob.Math.fround; function f() {var x=i4(1,2,3,4); return +fround(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var sin=glob.Math.sin; function f() {var x=i4(1,2,3,4); return +sin(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var ceil=glob.Math.ceil; function f() {var x=i4(1,2,3,4); return +ceil(x);} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var pow=glob.Math.pow; function f() {var x=i4(1,2,3,4); return +pow(1.0, x);} return f"); - -assertAsmTypeFail('glob', USE_ASM + I32 + "var fround=glob.Math.fround; function f() {var x=i4(1,2,3,4); x=i4(fround(3));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var sin=glob.Math.sin; function f() {var x=i4(1,2,3,4); x=i4(sin(3.0));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var ceil=glob.Math.sin; function f() {var x=i4(1,2,3,4); x=i4(ceil(3.0));} return f"); -assertAsmTypeFail('glob', USE_ASM + I32 + "var pow=glob.Math.pow; function f() {var x=i4(1,2,3,4); x=i4(pow(1.0, 2.0));} return f"); - -// 3.2. FFI calls -// Can't pass SIMD arguments to FFI -assertAsmTypeFail('glob', 'ffi', USE_ASM + I32 + "var func=ffi.func; function f() {var x=i4(1,2,3,4); func(x);} return f"); -assertAsmTypeFail('glob', 'ffi', USE_ASM + U32 + "var func=ffi.func; function f() {var x=u4(1,2,3,4); func(x);} return f"); -assertAsmTypeFail('glob', 'ffi', USE_ASM + F32 + "var func=ffi.func; function f() {var x=f4(1,2,3,4); func(x);} return f"); -assertAsmTypeFail('glob', 'ffi', USE_ASM + B32 + "var func=ffi.func; function f() {var x=b4(1,2,3,4); func(x);} return f"); - -// Can't have FFI return SIMD values -assertAsmTypeFail('glob', 'ffi', USE_ASM + I32 + "var func=ffi.func; function f() {var x=i4(1,2,3,4); x=i4(func());} return f"); -assertAsmTypeFail('glob', 'ffi', USE_ASM + U32 + "var func=ffi.func; function f() {var x=u4(1,2,3,4); x=i4(func());} return f"); -assertAsmTypeFail('glob', 'ffi', USE_ASM + F32 + "var func=ffi.func; function f() {var x=f4(1,2,3,4); x=f4(func());} return f"); -assertAsmTypeFail('glob', 'ffi', USE_ASM + B32 + "var func=ffi.func; function f() {var x=b4(1,2,3,4); x=b4(func());} return f"); - -// 3.3 Internal calls -// asm.js -> asm.js -// Retrieving values from asm.js -var code = USE_ASM + I32 + CI32 + I32A + EXTI4 + ` - var check = ffi.check; - - function g() { - var i = 0; - var y = i4(0,0,0,0); - var tmp = i4(0,0,0,0); var z = i4(1,1,1,1); - var w = i4(5,5,5,5); - for (; (i|0) < 30; i = i + 1 |0) - y = i4a(z, y); - y = i4a(w, y); - check(e(y,0) | 0, e(y,1) | 0, e(y,2) | 0, e(y,3) | 0); - return ci4(y); - } - - function f(x) { - x = ci4(x); - var y = i4(0,0,0,0); - y = ci4(g()); - check(e(y,0) | 0, e(y,1) | 0, e(y,2) | 0, e(y,3) | 0); - return ci4(x); - } - return f; -`; - -var v4 = SIMD.Int32x4(1,2,3,4); -function check(x, y, z, w) { - assertEq(x, 35); - assertEq(y, 35); - assertEq(z, 35); - assertEq(w, 35); -} -var ffi = {check}; -assertEqX4(asmLink(asmCompile('glob', 'ffi', code), this, ffi)(v4), [1,2,3,4]); - -// Passing arguments from asm.js to asm.js -var code = USE_ASM + I32 + CI32 + I32A + EXTI4 + ` - var assertEq = ffi.assertEq; - - function internal([args]) { - [coerc] - assertEq(e([last],0) | 0, [i] | 0); - assertEq(e([last],1) | 0, [i] + 1 |0); - assertEq(e([last],2) | 0, [i] + 2 |0); - assertEq(e([last],3) | 0, [i] + 3 |0); - } - - function external() { - [decls] - internal([args]); - } - return external; -`; - -var ffi = {assertEq}; -var args = ''; -var decls = ''; -var coerc = ''; -for (var i = 1; i < 10; ++i) { - var j = i; - args += ((i > 1) ? ', ':'') + 'x' + i; - decls += 'var x' + i + ' = i4(' + j++ + ', ' + j++ + ', ' + j++ + ', ' + j++ + ');\n'; - coerc += 'x' + i + ' = ci4(x' + i + ');\n'; - last = 'x' + i; - var c = code.replace(/\[args\]/g, args) - .replace(/\[last\]/g, last) - .replace(/\[decls\]/i, decls) - .replace(/\[coerc\]/i, coerc) - .replace(/\[i\]/g, i); - asmLink(asmCompile('glob', 'ffi', c), this, ffi)(); -} - -// Bug 1240524 -assertAsmTypeFail(USE_ASM + B32 + 'var x = b4(0, 0, 0, 0); frd(x);'); - -// Passing boolean results to extern functions. -// Verify that these functions are typed correctly. -function isone(x) { return (x===1)|0 } -var f = asmLink(asmCompile('glob', 'ffi', USE_ASM + B32 + CB32 + ANYB4 + 'var isone=ffi.isone; function f(i) { i=cb4(i); return isone(anyt(i)|0)|0; } return f'), this, {isone:isone}); -assertEq(f(SIMD.Bool32x4(0,0,1,0)), 1) -assertEq(f(SIMD.Bool32x4(0,0,0,0)), 0) -assertAsmTypeFail('glob', 'ffi', USE_ASM + B32 + CB32 + ANYB4 + 'var isone=ffi.isone; function f(i) { i=cb4(i); return isone(anyt(i))|0; } return f'); - -var f = asmLink(asmCompile('glob', 'ffi', USE_ASM + B32 + CB32 + ALLB4 + 'var isone=ffi.isone; function f(i) { i=cb4(i); return isone(allt(i)|0)|0; } return f'), this, {isone:isone}); -assertEq(f(SIMD.Bool32x4(1,1,1,1)), 1) -assertEq(f(SIMD.Bool32x4(0,1,0,0)), 0) -assertAsmTypeFail('glob', 'ffi', USE_ASM + B32 + CB32 + ALLB4 + 'var isone=ffi.isone; function f(i) { i=cb4(i); return isone(allt(i))|0; } return f'); - -var f = asmLink(asmCompile('glob', 'ffi', USE_ASM + B32 + CB32 + EXTB4 + 'var isone=ffi.isone; function f(i) { i=cb4(i); return isone(e(i,2)|0)|0; } return f'), this, {isone:isone}); -assertEq(f(SIMD.Bool32x4(1,1,1,1)), 1) -assertEq(f(SIMD.Bool32x4(0,1,0,0)), 0) -assertAsmTypeFail('glob', 'ffi', USE_ASM + B32 + CB32 + EXTB4 + 'var isone=ffi.isone; function f(i) { i=cb4(i); return isone(e(i,2))|0; } return f'); - -// Stress-test for register spilling code and stack depth checks -var code = ` - "use asm"; - var i4 = glob.SIMD.Int32x4; - var i4a = i4.add; - var e = i4.extractLane; - var assertEq = ffi.assertEq; - function g() { - var x = i4(1,2,3,4); - var y = i4(2,3,4,5); - var z = i4(0,0,0,0); - z = i4a(x, y); - assertEq(e(z,0) | 0, 3); - assertEq(e(z,1) | 0, 5); - assertEq(e(z,2) | 0, 7); - assertEq(e(z,3) | 0, 9); - } - return g -` -asmLink(asmCompile('glob', 'ffi', code), this, assertEqFFI)(); - -(function() { - var code = ` - "use asm"; - var i4 = glob.SIMD.Int32x4; - var i4a = i4.add; - var e = i4.extractLane; - var assertEq = ffi.assertEq; - var one = ffi.one; - - // Function call with arguments on the stack (1 on x64, 3 on x86) - function h(x1, x2, x3, x4, x5, x6, x7) { - x1=x1|0 - x2=x2|0 - x3=x3|0 - x4=x4|0 - x5=x5|0 - x6=x6|0 - x7=x7|0 - return x1 + x2 |0 - } - - function g() { - var x = i4(1,2,3,4); - var y = i4(2,3,4,5); - var z = i4(0,0,0,0); - var w = 1; - z = i4a(x, y); - w = w + (one() | 0) | 0; - assertEq(e(z,0) | 0, 3); - assertEq(e(z,1) | 0, 5); - assertEq(e(z,2) | 0, 7); - assertEq(e(z,3) | 0, 9); - h(1, 2, 3, 4, 42, 42, 42)|0 - return w | 0; - } - return g - `; - - asmLink(asmCompile('glob', 'ffi', code), this, {assertEq: assertEq, one: () => 1})(); -})(); - -// Function calls with mixed arguments on the stack (SIMD and scalar). In the -// worst case (x64), we have 6 int arg registers and 8 float registers. -(function() { - var code = ` - "use asm"; - var i4 = glob.SIMD.Int32x4; - var e = i4.extractLane; - var ci4 = i4.check; - function h( - // In registers: - gpr1, gpr2, gpr3, gpr4, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, - // On the stack: - sint1, ssimd1, sdouble1, ssimd2, sint2, sint3, sint4, ssimd3, sdouble2 - ) - { - gpr1=gpr1|0; - gpr2=gpr2|0; - gpr3=gpr3|0; - gpr4=gpr4|0; - - xmm1=+xmm1; - xmm2=+xmm2; - xmm3=+xmm3; - xmm4=+xmm4; - xmm5=+xmm5; - xmm6=+xmm6; - xmm7=+xmm7; - xmm8=+xmm8; - - sint1=sint1|0; - ssimd1=ci4(ssimd1); - sdouble1=+sdouble1; - ssimd2=ci4(ssimd2); - sint2=sint2|0; - sint3=sint3|0; - sint4=sint4|0; - ssimd3=ci4(ssimd3); - sdouble2=+sdouble2; - - return (e(ssimd1,0)|0) + (e(ssimd2,1)|0) + (e(ssimd3,2)|0) + sint2 + gpr3 | 0; - } - - function g() { - var simd1 = i4(1,2,3,4); - var simd2 = i4(5,6,7,8); - var simd3 = i4(9,10,11,12); - return h(1, 2, 3, 4, - 1., 2., 3., 4., 5., 6., 7., 8., - 5, simd1, 9., simd2, 6, 7, 8, simd3, 10.) | 0; - } - return g - `; - - assertEq(asmLink(asmCompile('glob', 'ffi', code), this)(), 1 + 6 + 11 + 6 + 3); -})(); - -// Check that the interrupt callback doesn't erase high components of simd -// registers: - -// WARNING: must be the last test in this file -(function() { - var iters = 2000000; - var code = ` - "use asm"; - var i4 = glob.SIMD.Int32x4; - var i4a = i4.add; - var ci4 = i4.check; - function _() { - var i = 0; - var n = i4(0,0,0,0); - var one = i4(1,1,1,1); - for (; (i>>>0) < ` + iters + `; i=(i+1)>>>0) { - n = i4a(n, one); - } - return ci4(n); - } - return _;`; - // This test relies on the fact that setting the timeout will call the - // interrupt callback at fixed intervals, even before the timeout. - timeout(1000); - var x4 = asmLink(asmCompile('glob', code), this)(); - assertEq(SIMD.Int32x4.extractLane(x4,0), iters); - assertEq(SIMD.Int32x4.extractLane(x4,1), iters); - assertEq(SIMD.Int32x4.extractLane(x4,2), iters); - assertEq(SIMD.Int32x4.extractLane(x4,3), iters); -})(); - -} catch(e) { - print('Stack:', e.stack) - print('Error:', e) - throw e; -} diff --git a/js/src/jit-test/tests/asm.js/testZOOB.js b/js/src/jit-test/tests/asm.js/testZOOB.js index ae59611d6e..9874f5c1e1 100644 --- a/js/src/jit-test/tests/asm.js/testZOOB.js +++ b/js/src/jit-test/tests/asm.js/testZOOB.js @@ -95,106 +95,6 @@ function assertEqX4(observed, expected) { assertEq(observed.w, expected.w); } -function testSimdX4(ctor, shift, scale, disp, simdName, simdCtor) { - var arr = new ctor(ab); - - var c = asmCompile('glob', 'imp', 'b', - USE_ASM + - 'var arr=new glob.' + ctor.name + '(b); ' + - 'var SIMD_' + simdName + ' = glob.SIMD.' + simdName + '; ' + - 'var SIMD_' + simdName + '_check = SIMD_' + simdName + '.check; ' + - 'var SIMD_' + simdName + '_load = SIMD_' + simdName + '.load; ' + - 'var SIMD_' + simdName + '_load2 = SIMD_' + simdName + '.load2; ' + - 'var SIMD_' + simdName + '_load1 = SIMD_' + simdName + '.load1; ' + - 'var SIMD_' + simdName + '_store = SIMD_' + simdName + '.store; ' + - 'var SIMD_' + simdName + '_store2 = SIMD_' + simdName + '.store2; ' + - 'var SIMD_' + simdName + '_store1 = SIMD_' + simdName + '.store1; ' + - 'function load(i) {i=i|0; return SIMD_' + simdName + '_check(SIMD_' + simdName + '_load(arr, ((i<<' + scale + ')+' + disp + ')>>' + shift + ')) } ' + - 'function load2(i) {i=i|0; return SIMD_' + simdName + '_check(SIMD_' + simdName + '_load2(arr, ((i<<' + scale + ')+' + disp + ')>>' + shift + ')) } ' + - 'function load1(i) {i=i|0; return SIMD_' + simdName + '_check(SIMD_' + simdName + '_load1(arr, ((i<<' + scale + ')+' + disp + ')>>' + shift + ')) } ' + - 'function store(i,j) {i=i|0;j=SIMD_' + simdName + '_check(j); SIMD_' + simdName + '_store(arr, ((i<<' + scale + ')+' + disp + ')>>' + shift + ', j) } ' + - 'function store2(i,j) {i=i|0;j=SIMD_' + simdName + '_check(j); SIMD_' + simdName + '_store2(arr, ((i<<' + scale + ')+' + disp + ')>>' + shift + ', j) } ' + - 'function store1(i,j) {i=i|0;j=SIMD_' + simdName + '_check(j); SIMD_' + simdName + '_store1(arr, ((i<<' + scale + ')+' + disp + ')>>' + shift + ', j) } ' + - 'return { load: load, load2: load2, load1: load1, store: store, store2 : store2, store1 : store1 }'); - var f = asmLink(c, this, null, ab); - - const RuntimeError = WebAssembly.RuntimeError; - - for (var i of indices) { - var index = ((i<<scale)+disp)>>shift; - - var v, v2, v1; - var t = false, t2 = false, t1 = false; - try { v = simdCtor.load(arr, index); } - catch (e) { - assertEq(e instanceof RangeError, true); - t = true; - } - try { v2 = simdCtor.load2(arr, index); } - catch (e) { - assertEq(e instanceof RangeError, true); - t2 = true; - } - try { v1 = simdCtor.load1(arr, index); } - catch (e) { - assertEq(e instanceof RangeError, true); - t1 = true; - } - - // Loads - var l, l2, l1; - var r = false, r2 = false, r1 = false; - try { l = f.load(i); } - catch (e) { - assertEq(e instanceof RuntimeError, true); - r = true; - } - try { l2 = f.load2(i); } - catch (e) { - assertEq(e instanceof RuntimeError, true); - r2 = true; - } - try { l1 = f.load1(i); } - catch (e) { - assertEq(e instanceof RuntimeError, true); - r1 = true; - } - assertEq(t, r); - assertEq(t2, r2); - assertEq(t1, r1); - if (!t) assertEqX4(v, l); - if (!t2) assertEqX4(v2, l2); - if (!t1) assertEqX4(v1, l1); - - // Stores - if (!t) { - simdCtor.store(arr, index, simdCtor.neg(v)); - f.store(i, v); - assertEqX4(simdCtor.load(arr, index), v); - } else - assertThrowsInstanceOf(() => f.store(i, simdCtor()), RuntimeError); - if (!t2) { - simdCtor.store2(arr, index, simdCtor.neg(v2)); - f.store2(i, v2); - assertEqX4(simdCtor.load2(arr, index), v2); - } else - assertThrowsInstanceOf(() => f.store2(i, simdCtor()), RuntimeError); - if (!t1) { - simdCtor.store1(arr, index, simdCtor.neg(v1)); - f.store1(i, v1); - assertEqX4(simdCtor.load1(arr, index), v1); - } else - assertThrowsInstanceOf(() => f.store1(i, simdCtor()), RuntimeError); - } -} - -function testFloat32x4(ctor, shift, scale, disp) { - testSimdX4(ctor, shift, scale, disp, 'Float32x4', SIMD.Float32x4); -} -function testInt32x4(ctor, shift, scale, disp) { - testSimdX4(ctor, shift, scale, disp, 'Int32x4', SIMD.Int32x4); -} - function test(tester, ctor, shift) { var arr = new ctor(ab); for (var i = 0; i < arr.length; i++) @@ -218,15 +118,3 @@ test(testInt, Int32Array, 2); test(testInt, Uint32Array, 2); test(testFloat32, Float32Array, 2); test(testFloat64, Float64Array, 3); -if (typeof SIMD !== 'undefined' && isSimdAvailable()) { - // Avoid pathological --ion-eager compile times due to bails in loops - setJitCompilerOption('ion.warmup.trigger', 1000000); - - // Use a fresh ArrayBuffer so prepareForAsmJS can allocated a guard page - // which SIMD.js needs. Since the original ArrayBuffer was prepared for - // asm.js that didn't use SIMD.js, it has no guard page (on 32-bit). - ab = new ArrayBuffer(BUF_MIN); - - test(testInt32x4, Uint8Array, 0); - test(testFloat32x4, Uint8Array, 0); -} diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index ce27e4de19..4bcaadee47 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -1959,7 +1959,6 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo) case Bailout_NonStringInput: case Bailout_NonSymbolInput: case Bailout_NonBigIntInput: - case Bailout_UnexpectedSimdInput: case Bailout_NonSharedTypedArrayInput: case Bailout_Debugger: case Bailout_UninitializedThis: diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 600b56d096..fa02c24374 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -15,7 +15,6 @@ #include "jstypes.h" #include "builtin/Eval.h" -#include "builtin/SIMD.h" #include "gc/Policy.h" #include "jit/BaselineDebugModeOSR.h" #include "jit/BaselineJIT.h" @@ -5457,68 +5456,6 @@ TryAttachFunCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, return true; } -// Check if target is a native SIMD operation which returns a SIMD type. -// If so, set res to a template object matching the SIMD type produced and return true. -static bool -GetTemplateObjectForSimd(JSContext* cx, JSFunction* target, MutableHandleObject res) -{ - const JSJitInfo* jitInfo = target->jitInfo(); - if (!jitInfo || jitInfo->type() != JSJitInfo::InlinableNative) - return false; - - // Check if this is a native inlinable SIMD operation. - SimdType ctrlType; - switch (jitInfo->inlinableNative) { - case InlinableNative::SimdInt8x16: ctrlType = SimdType::Int8x16; break; - case InlinableNative::SimdUint8x16: ctrlType = SimdType::Uint8x16; break; - case InlinableNative::SimdInt16x8: ctrlType = SimdType::Int16x8; break; - case InlinableNative::SimdUint16x8: ctrlType = SimdType::Uint16x8; break; - case InlinableNative::SimdInt32x4: ctrlType = SimdType::Int32x4; break; - case InlinableNative::SimdUint32x4: ctrlType = SimdType::Uint32x4; break; - case InlinableNative::SimdFloat32x4: ctrlType = SimdType::Float32x4; break; - case InlinableNative::SimdBool8x16: ctrlType = SimdType::Bool8x16; break; - case InlinableNative::SimdBool16x8: ctrlType = SimdType::Bool16x8; break; - case InlinableNative::SimdBool32x4: ctrlType = SimdType::Bool32x4; break; - // This is not an inlinable SIMD operation. - default: return false; - } - - // The controlling type is not necessarily the return type. - // Check the actual operation. - SimdOperation simdOp = SimdOperation(jitInfo->nativeOp); - SimdType retType; - - switch(simdOp) { - case SimdOperation::Fn_allTrue: - case SimdOperation::Fn_anyTrue: - case SimdOperation::Fn_extractLane: - // These operations return a scalar. No template object needed. - return false; - - case SimdOperation::Fn_lessThan: - case SimdOperation::Fn_lessThanOrEqual: - case SimdOperation::Fn_equal: - case SimdOperation::Fn_notEqual: - case SimdOperation::Fn_greaterThan: - case SimdOperation::Fn_greaterThanOrEqual: - // These operations return a boolean vector with the same shape as the - // controlling type. - retType = GetBooleanSimdType(ctrlType); - break; - - default: - // All other operations return the controlling type. - retType = ctrlType; - break; - } - - // Create a template object based on retType. - RootedGlobalObject global(cx, cx->global()); - Rooted<SimdTypeDescr*> descr(cx, GlobalObject::getOrCreateSimdTypeDescr(cx, global, retType)); - res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr)); - return true; -} - static void EnsureArrayGroupAnalyzed(JSContext* cx, JSObject* obj) { @@ -5623,9 +5560,6 @@ GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs& return !!res; } - if (JitSupportsSimd() && GetTemplateObjectForSimd(cx, target, res)) - return !!res; - return true; } @@ -5639,12 +5573,6 @@ GetTemplateObjectForClassHook(JSContext* cx, JSNative hook, CallArgs& args, return !!templateObject; } - if (hook == SimdTypeDescr::call && JitSupportsSimd()) { - Rooted<SimdTypeDescr*> descr(cx, &args.callee().as<SimdTypeDescr>()); - templateObject.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr)); - return !!templateObject; - } - return true; } diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index d3b0fb71b5..4c22a1839c 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -624,25 +624,6 @@ BaselineInspector::getTemplateObjectForClassHook(jsbytecode* pc, const Class* cl return nullptr; } -JSObject* -BaselineInspector::getTemplateObjectForSimdCtor(jsbytecode* pc, SimdType simdType) -{ - if (!hasBaselineScript()) - return nullptr; - - const ICEntry& entry = icEntryFromPC(pc); - for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { - if (stub->isCall_ClassHook() && stub->toCall_ClassHook()->clasp() == &SimdTypeDescr::class_) { - JSObject* templateObj = stub->toCall_ClassHook()->templateObject(); - InlineTypedObject& typedObj = templateObj->as<InlineTypedObject>(); - if (typedObj.typeDescr().as<SimdTypeDescr>().type() == simdType) - return templateObj; - } - } - - return nullptr; -} - LexicalEnvironmentObject* BaselineInspector::templateNamedLambdaObject() { diff --git a/js/src/jit/BaselineInspector.h b/js/src/jit/BaselineInspector.h index d7c4096238..556f28ee5b 100644 --- a/js/src/jit/BaselineInspector.h +++ b/js/src/jit/BaselineInspector.h @@ -117,7 +117,6 @@ class BaselineInspector JSObject* getTemplateObject(jsbytecode* pc); JSObject* getTemplateObjectForNative(jsbytecode* pc, Native native); JSObject* getTemplateObjectForClassHook(jsbytecode* pc, const Class* clasp); - JSObject* getTemplateObjectForSimdCtor(jsbytecode* pc, SimdType simdType); // Sometimes the group a template object will have is known, even if the // object itself isn't. diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 0459592448..d427f5f7f4 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -163,7 +163,6 @@ CodeGenerator::CodeGenerator(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* : CodeGeneratorSpecific(gen, graph, masm) , ionScriptLabels_(gen->alloc()) , scriptCounts_(nullptr) - , simdRefreshTemplatesDuringLink_(0) { } @@ -5758,128 +5757,6 @@ CodeGenerator::visitNewTypedObject(LNewTypedObject* lir) masm.bind(ool->rejoin()); } -void -CodeGenerator::visitSimdBox(LSimdBox* lir) -{ - FloatRegister in = ToFloatRegister(lir->input()); - Register object = ToRegister(lir->output()); - Register temp = ToRegister(lir->temp()); - InlineTypedObject* templateObject = lir->mir()->templateObject(); - gc::InitialHeap initialHeap = lir->mir()->initialHeap(); - MIRType type = lir->mir()->input()->type(); - - registerSimdTemplate(lir->mir()->simdType()); - - MOZ_ASSERT(lir->safepoint()->liveRegs().has(in), "Save the input register across oolCallVM"); - OutOfLineCode* ool = oolCallVM(NewTypedObjectInfo, lir, - ArgList(ImmGCPtr(templateObject), Imm32(initialHeap)), - StoreRegisterTo(object)); - - masm.createGCObject(object, temp, templateObject, initialHeap, ool->entry()); - masm.bind(ool->rejoin()); - - Address objectData(object, InlineTypedObject::offsetOfDataStart()); - switch (type) { - case MIRType::Int8x16: - case MIRType::Int16x8: - case MIRType::Int32x4: - case MIRType::Bool8x16: - case MIRType::Bool16x8: - case MIRType::Bool32x4: - masm.storeUnalignedSimd128Int(in, objectData); - break; - case MIRType::Float32x4: - masm.storeUnalignedSimd128Float(in, objectData); - break; - default: - MOZ_CRASH("Unknown SIMD kind when generating code for SimdBox."); - } -} - -void -CodeGenerator::registerSimdTemplate(SimdType simdType) -{ - simdRefreshTemplatesDuringLink_ |= 1 << uint32_t(simdType); -} - -void -CodeGenerator::captureSimdTemplate(JSContext* cx) -{ - JitCompartment* jitCompartment = cx->compartment()->jitCompartment(); - while (simdRefreshTemplatesDuringLink_) { - uint32_t typeIndex = mozilla::CountTrailingZeroes32(simdRefreshTemplatesDuringLink_); - simdRefreshTemplatesDuringLink_ ^= 1 << typeIndex; - SimdType type = SimdType(typeIndex); - - // Note: the weak-reference on the template object should not have been - // garbage collected. It is either registered by IonBuilder, or verified - // before using it in the EagerSimdUnbox phase. - jitCompartment->registerSimdTemplateObjectFor(type); - } -} - -void -CodeGenerator::visitSimdUnbox(LSimdUnbox* lir) -{ - Register object = ToRegister(lir->input()); - FloatRegister simd = ToFloatRegister(lir->output()); - Register temp = ToRegister(lir->temp()); - Label bail; - - // obj->group() - masm.loadPtr(Address(object, JSObject::offsetOfGroup()), temp); - - // Guard that the object has the same representation as the one produced for - // SIMD value-type. - Address clasp(temp, ObjectGroup::offsetOfClasp()); - static_assert(!SimdTypeDescr::Opaque, "SIMD objects are transparent"); - masm.branchPtr(Assembler::NotEqual, clasp, ImmPtr(&InlineTransparentTypedObject::class_), - &bail); - - // obj->type()->typeDescr() - // The previous class pointer comparison implies that the addendumKind is - // Addendum_TypeDescr. - masm.loadPtr(Address(temp, ObjectGroup::offsetOfAddendum()), temp); - - // Check for the /Kind/ reserved slot of the TypeDescr. This is an Int32 - // Value which is equivalent to the object class check. - static_assert(JS_DESCR_SLOT_KIND < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots"); - Address typeDescrKind(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_KIND)); - masm.assertTestInt32(Assembler::Equal, typeDescrKind, - "MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_KIND).isInt32())"); - masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrKind), Imm32(js::type::Simd), &bail); - - SimdType type = lir->mir()->simdType(); - - // Check if the SimdTypeDescr /Type/ match the specialization of this - // MSimdUnbox instruction. - static_assert(JS_DESCR_SLOT_TYPE < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots"); - Address typeDescrType(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_TYPE)); - masm.assertTestInt32(Assembler::Equal, typeDescrType, - "MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_TYPE).isInt32())"); - masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrType), Imm32(int32_t(type)), &bail); - - // Load the value from the data of the InlineTypedObject. - Address objectData(object, InlineTypedObject::offsetOfDataStart()); - switch (lir->mir()->type()) { - case MIRType::Int8x16: - case MIRType::Int16x8: - case MIRType::Int32x4: - case MIRType::Bool8x16: - case MIRType::Bool16x8: - case MIRType::Bool32x4: - masm.loadUnalignedSimd128Int(objectData, simd); - break; - case MIRType::Float32x4: - masm.loadUnalignedSimd128Float(objectData, simd); - break; - default: - MOZ_CRASH("The impossible happened!"); - } - - bailoutFrom(&bail, lir->snapshot()); -} - typedef js::NamedLambdaObject* (*NewNamedLambdaObjectFn)(JSContext*, HandleFunction, gc::InitialHeap); static const VMFunction NewNamedLambdaObjectInfo = FunctionInfo<NewNamedLambdaObjectFn>(NamedLambdaObject::createTemplateObject, @@ -9548,12 +9425,6 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints) RootedScript script(cx, gen->info().script()); OptimizationLevel optimizationLevel = gen->optimizationInfo().level(); - // Capture the SIMD template objects which are used during the - // compilation. This iterates over the template objects, using read-barriers - // to let the GC know that the generated code relies on these template - // objects. - captureSimdTemplate(cx); - // We finished the new IonScript. Invalidate the current active IonScript, // so we can replace it with this new (probably higher optimized) version. if (script->hasIonScript()) { @@ -10821,7 +10692,6 @@ CodeGenerator::visitLoadUnboxedScalar(LLoadUnboxedScalar* lir) const MLoadUnboxedScalar* mir = lir->mir(); Scalar::Type readType = mir->readType(); - unsigned numElems = mir->numElems(); int width = Scalar::byteSize(mir->storageType()); bool canonicalizeDouble = mir->canonicalizeDoubles(); @@ -10829,11 +10699,11 @@ CodeGenerator::visitLoadUnboxedScalar(LLoadUnboxedScalar* lir) Label fail; if (lir->index()->isConstant()) { Address source(elements, ToInt32(lir->index()) * width + mir->offsetAdjustment()); - masm.loadFromTypedArray(readType, source, out, temp, &fail, canonicalizeDouble, numElems); + masm.loadFromTypedArray(readType, source, out, temp, &fail, canonicalizeDouble); } else { BaseIndex source(elements, ToRegister(lir->index()), ScaleFromElemWidth(width), mir->offsetAdjustment()); - masm.loadFromTypedArray(readType, source, out, temp, &fail, canonicalizeDouble, numElems); + masm.loadFromTypedArray(readType, source, out, temp, &fail, canonicalizeDouble); } if (fail.used()) @@ -10884,13 +10754,12 @@ CodeGenerator::visitLoadTypedArrayElementHole(LLoadTypedArrayElementHole* lir) template <typename T> static inline void StoreToTypedArray(MacroAssembler& masm, Scalar::Type writeType, const LAllocation* value, - const T& dest, unsigned numElems = 0) + const T& dest) { - if (Scalar::isSimdType(writeType) || - writeType == Scalar::Float32 || + if (writeType == Scalar::Float32 || writeType == Scalar::Float64) { - masm.storeToTypedFloatArray(writeType, ToFloatRegister(value), dest, numElems); + masm.storeToTypedFloatArray(writeType, ToFloatRegister(value), dest); } else { if (value->isConstant()) masm.storeToTypedIntArray(writeType, Imm32(ToInt32(value)), dest); @@ -10908,17 +10777,16 @@ CodeGenerator::visitStoreUnboxedScalar(LStoreUnboxedScalar* lir) const MStoreUnboxedScalar* mir = lir->mir(); Scalar::Type writeType = mir->writeType(); - unsigned numElems = mir->numElems(); int width = Scalar::byteSize(mir->storageType()); if (lir->index()->isConstant()) { Address dest(elements, ToInt32(lir->index()) * width + mir->offsetAdjustment()); - StoreToTypedArray(masm, writeType, value, dest, numElems); + StoreToTypedArray(masm, writeType, value, dest); } else { BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width), mir->offsetAdjustment()); - StoreToTypedArray(masm, writeType, value, dest, numElems); + StoreToTypedArray(masm, writeType, value, dest); } } diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index 64fe9378b8..44804794a2 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -202,8 +202,6 @@ class CodeGenerator final : public CodeGeneratorSpecific void visitNewObject(LNewObject* lir); void visitOutOfLineNewObject(OutOfLineNewObject* ool); void visitNewTypedObject(LNewTypedObject* lir); - void visitSimdBox(LSimdBox* lir); - void visitSimdUnbox(LSimdUnbox* lir); void visitNewNamedLambdaObject(LNewNamedLambdaObject* lir); void visitNewCallObject(LNewCallObject* lir); void visitNewSingletonCallObject(LNewSingletonCallObject* lir); @@ -581,22 +579,6 @@ class CodeGenerator final : public CodeGeneratorSpecific #if defined(JS_ION_PERF) PerfSpewer perfSpewer_; #endif - - // This integer is a bit mask of all SimdTypeDescr::Type indexes. When a - // MSimdBox instruction is encoded, it might have either been created by - // IonBuilder, or by the Eager Simd Unbox phase. - // - // As the template objects are weak references, the JitCompartment is using - // Read Barriers, but such barrier cannot be used during the compilation. To - // work around this issue, the barriers are captured during - // CodeGenerator::link. - // - // Instead of saving the pointers, we just save the index of the Read - // Barriered objects in a bit mask. - uint32_t simdRefreshTemplatesDuringLink_; - - void registerSimdTemplate(SimdType simdType); - void captureSimdTemplate(JSContext* cx); }; } // namespace jit diff --git a/js/src/jit/EagerSimdUnbox.cpp b/js/src/jit/EagerSimdUnbox.cpp deleted file mode 100644 index 0e6e2f2fdb..0000000000 --- a/js/src/jit/EagerSimdUnbox.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "jit/EagerSimdUnbox.h" - -#include "jit/MIR.h" -#include "jit/MIRGenerator.h" -#include "jit/MIRGraph.h" - -namespace js { -namespace jit { - -// Do not optimize any Phi instruction which has conflicting Unbox operations, -// as this might imply some intended polymorphism. -static bool -CanUnboxSimdPhi(const JitCompartment* jitCompartment, MPhi* phi, SimdType unboxType) -{ - MOZ_ASSERT(phi->type() == MIRType::Object); - - // If we are unboxing, we are more than likely to have boxed this SIMD type - // once in baseline, otherwise, we cannot create a MSimdBox as we have no - // template object to use. - if (!jitCompartment->maybeGetSimdTemplateObjectFor(unboxType)) - return false; - - MResumePoint* entry = phi->block()->entryResumePoint(); - MIRType mirType = SimdTypeToMIRType(unboxType); - for (MUseIterator i(phi->usesBegin()), e(phi->usesEnd()); i != e; i++) { - // If we cannot recover the Simd object at the entry of the basic block, - // then we would have to box the content anyways. - if ((*i)->consumer() == entry && !entry->isRecoverableOperand(*i)) - return false; - - if (!(*i)->consumer()->isDefinition()) - continue; - - MDefinition* def = (*i)->consumer()->toDefinition(); - if (def->isSimdUnbox() && def->toSimdUnbox()->type() != mirType) - return false; - } - - return true; -} - -static void -UnboxSimdPhi(const JitCompartment* jitCompartment, MIRGraph& graph, MPhi* phi, SimdType unboxType) -{ - TempAllocator& alloc = graph.alloc(); - - // Unbox and replace all operands. - for (size_t i = 0, e = phi->numOperands(); i < e; i++) { - MDefinition* op = phi->getOperand(i); - MSimdUnbox* unbox = MSimdUnbox::New(alloc, op, unboxType); - op->block()->insertAtEnd(unbox); - phi->replaceOperand(i, unbox); - } - - // Change the MIRType of the Phi. - MIRType mirType = SimdTypeToMIRType(unboxType); - phi->setResultType(mirType); - - MBasicBlock* phiBlock = phi->block(); - MInstruction* atRecover = phiBlock->safeInsertTop(nullptr, MBasicBlock::IgnoreRecover); - MInstruction* at = phiBlock->safeInsertTop(atRecover); - - // Note, we capture the uses-list now, as new instructions are not visited. - MUseIterator i(phi->usesBegin()), e(phi->usesEnd()); - - // Add a MSimdBox, and replace all the Phi uses with it. - JSObject* templateObject = jitCompartment->maybeGetSimdTemplateObjectFor(unboxType); - InlineTypedObject* inlineTypedObject = &templateObject->as<InlineTypedObject>(); - MSimdBox* recoverBox = MSimdBox::New(alloc, nullptr, phi, inlineTypedObject, unboxType, gc::DefaultHeap); - recoverBox->setRecoveredOnBailout(); - phiBlock->insertBefore(atRecover, recoverBox); - - MSimdBox* box = nullptr; - while (i != e) { - MUse* use = *i++; - MNode* ins = use->consumer(); - - if ((ins->isDefinition() && ins->toDefinition()->isRecoveredOnBailout()) || - (ins->isResumePoint() && ins->toResumePoint()->isRecoverableOperand(use))) - { - use->replaceProducer(recoverBox); - continue; - } - - if (!box) { - box = MSimdBox::New(alloc, nullptr, phi, inlineTypedObject, unboxType, gc::DefaultHeap); - phiBlock->insertBefore(at, box); - } - - use->replaceProducer(box); - } -} - -bool -EagerSimdUnbox(MIRGenerator* mir, MIRGraph& graph) -{ - const JitCompartment* jitCompartment = GetJitContext()->compartment->jitCompartment(); - for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) { - if (mir->shouldCancel("Eager Simd Unbox")) - return false; - - for (MInstructionReverseIterator ins = block->rbegin(); ins != block->rend(); ins++) { - if (!ins->isSimdUnbox()) - continue; - - MSimdUnbox* unbox = ins->toSimdUnbox(); - if (!unbox->input()->isPhi()) - continue; - - MPhi* phi = unbox->input()->toPhi(); - if (!CanUnboxSimdPhi(jitCompartment, phi, unbox->simdType())) - continue; - - UnboxSimdPhi(jitCompartment, graph, phi, unbox->simdType()); - } - } - - return true; -} - -} /* namespace jit */ -} /* namespace js */ diff --git a/js/src/jit/EagerSimdUnbox.h b/js/src/jit/EagerSimdUnbox.h deleted file mode 100644 index 685a3d962b..0000000000 --- a/js/src/jit/EagerSimdUnbox.h +++ /dev/null @@ -1,24 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// This file declares eager SIMD unboxing. -#ifndef jit_EagerSimdUnbox_h -#define jit_EagerSimdUnbox_h - -#include "mozilla/Attributes.h" - -namespace js { -namespace jit { - -class MIRGenerator; -class MIRGraph; - -MOZ_MUST_USE bool -EagerSimdUnbox(MIRGenerator* mir, MIRGraph& graph); - -} // namespace jit -} // namespace js - -#endif /* jit_EagerSimdUnbox_h */ diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h index 561eb4b2db..65d1693cc3 100644 --- a/js/src/jit/InlinableNatives.h +++ b/js/src/jit/InlinableNatives.h @@ -88,17 +88,6 @@ \ _(ObjectCreate) \ \ - _(SimdInt32x4) \ - _(SimdUint32x4) \ - _(SimdInt16x8) \ - _(SimdUint16x8) \ - _(SimdInt8x16) \ - _(SimdUint8x16) \ - _(SimdFloat32x4) \ - _(SimdBool32x4) \ - _(SimdBool16x8) \ - _(SimdBool8x16) \ - \ _(TestBailout) \ _(TestAssertFloat32) \ _(TestAssertRecoveredOnBailout) \ diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 1a8fa40dd3..1a949fae62 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -22,7 +22,6 @@ #include "jit/BaselineInspector.h" #include "jit/BaselineJIT.h" #include "jit/CodeGenerator.h" -#include "jit/EagerSimdUnbox.h" #include "jit/EdgeCaseAnalysis.h" #include "jit/EffectiveAddressAnalysis.h" #include "jit/FlowAliasAnalysis.h" @@ -678,11 +677,6 @@ JitCompartment::sweep(FreeOp* fop, JSCompartment* compartment) if (regExpTesterStub_ && !IsMarkedUnbarriered(rt, ®ExpTesterStub_)) regExpTesterStub_ = nullptr; - - for (ReadBarrieredObject& obj : simdTemplateObjects_) { - if (obj && IsAboutToBeFinalized(&obj)) - obj.set(nullptr); - } } void @@ -1600,17 +1594,6 @@ OptimizeMIR(MIRGenerator* mir) return false; } - if (!JitOptions.disableRecoverIns && mir->optimizationInfo().eagerSimdUnboxEnabled()) { - AutoTraceLog log(logger, TraceLogger_EagerSimdUnbox); - if (!EagerSimdUnbox(mir, graph)) - return false; - gs.spewPass("Eager Simd Unbox"); - AssertGraphCoherency(graph); - - if (mir->shouldCancel("Eager Simd Unbox")) - return false; - } - if (mir->optimizationInfo().amaEnabled()) { AutoTraceLog log(logger, TraceLogger_AlignmentMaskAnalysis); AlignmentMaskAnalysis ama(graph); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index a440bfa598..ae3776c888 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -9163,11 +9163,6 @@ IonBuilder::getElemTryTypedObject(bool* emitted, MDefinition* obj, MDefinition* return true; switch (elemPrediction.kind()) { - case type::Simd: - // FIXME (bug 894105): load into a MIRType::float32x4 etc - trackOptimizationOutcome(TrackedOutcome::GenericFailure); - return true; - case type::Struct: case type::Array: return getElemTryComplexElemOfTypedObject(emitted, @@ -10277,11 +10272,6 @@ IonBuilder::setElemTryTypedObject(bool* emitted, MDefinition* obj, return true; switch (elemPrediction.kind()) { - case type::Simd: - // FIXME (bug 894105): store a MIRType::float32x4 etc - trackOptimizationOutcome(TrackedOutcome::GenericFailure); - return true; - case type::Reference: return setElemTryReferenceElemOfTypedObject(emitted, obj, index, objPrediction, value, elemPrediction); @@ -11897,10 +11887,6 @@ IonBuilder::getPropTryTypedObject(bool* emitted, return true; switch (fieldPrediction.kind()) { - case type::Simd: - // FIXME (bug 894104): load into a MIRType::float32x4 etc - return true; - case type::Struct: case type::Array: return getPropTryComplexPropOfTypedObject(emitted, @@ -12966,10 +12952,6 @@ IonBuilder::setPropTryTypedObject(bool* emitted, MDefinition* obj, return true; switch (fieldPrediction.kind()) { - case type::Simd: - // FIXME (bug 894104): store into a MIRType::float32x4 etc - return true; - case type::Reference: return setPropTryReferencePropOfTypedObject(emitted, obj, fieldOffset, value, fieldPrediction, name); diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 6f3fc027f6..96cfd821ca 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -914,52 +914,6 @@ class IonBuilder InliningStatus inlineSetTypedObjectOffset(CallInfo& callInfo); InliningStatus inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* target); - // SIMD intrinsics and natives. - InliningStatus inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* target); - - // SIMD helpers. - bool canInlineSimd(CallInfo& callInfo, JSNative native, unsigned numArgs, - InlineTypedObject** templateObj); - MDefinition* unboxSimd(MDefinition* ins, SimdType type); - IonBuilder::InliningStatus boxSimd(CallInfo& callInfo, MDefinition* ins, - InlineTypedObject* templateObj); - MDefinition* convertToBooleanSimdLane(MDefinition* scalar); - - InliningStatus inlineSimd(CallInfo& callInfo, JSFunction* target, SimdType type); - - InliningStatus inlineSimdBinaryArith(CallInfo& callInfo, JSNative native, - MSimdBinaryArith::Operation op, SimdType type); - InliningStatus inlineSimdBinaryBitwise(CallInfo& callInfo, JSNative native, - MSimdBinaryBitwise::Operation op, SimdType type); - InliningStatus inlineSimdBinarySaturating(CallInfo& callInfo, JSNative native, - MSimdBinarySaturating::Operation op, SimdType type); - InliningStatus inlineSimdShift(CallInfo& callInfo, JSNative native, MSimdShift::Operation op, - SimdType type); - InliningStatus inlineSimdComp(CallInfo& callInfo, JSNative native, - MSimdBinaryComp::Operation op, SimdType type); - InliningStatus inlineSimdUnary(CallInfo& callInfo, JSNative native, - MSimdUnaryArith::Operation op, SimdType type); - InliningStatus inlineSimdExtractLane(CallInfo& callInfo, JSNative native, SimdType type); - InliningStatus inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, SimdType type); - InliningStatus inlineSimdSplat(CallInfo& callInfo, JSNative native, SimdType type); - InliningStatus inlineSimdShuffle(CallInfo& callInfo, JSNative native, SimdType type, - unsigned numVectors); - InliningStatus inlineSimdCheck(CallInfo& callInfo, JSNative native, SimdType type); - InliningStatus inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast, - SimdType from, SimdType to); - InliningStatus inlineSimdSelect(CallInfo& callInfo, JSNative native, SimdType type); - - MOZ_MUST_USE bool prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, - MInstruction** elements, MDefinition** index, - Scalar::Type* arrayType); - InliningStatus inlineSimdLoad(CallInfo& callInfo, JSNative native, SimdType type, - unsigned numElems); - InliningStatus inlineSimdStore(CallInfo& callInfo, JSNative native, SimdType type, - unsigned numElems); - - InliningStatus inlineSimdAnyAllTrue(CallInfo& callInfo, bool IsAllTrue, JSNative native, - SimdType type); - // Utility intrinsics. InliningStatus inlineIsCallable(CallInfo& callInfo); InliningStatus inlineIsConstructor(CallInfo& callInfo); diff --git a/js/src/jit/IonOptimizationLevels.cpp b/js/src/jit/IonOptimizationLevels.cpp index fa4cca4160..f5cfb4ebaf 100644 --- a/js/src/jit/IonOptimizationLevels.cpp +++ b/js/src/jit/IonOptimizationLevels.cpp @@ -24,7 +24,6 @@ OptimizationInfo::initNormalOptimizationInfo() autoTruncate_ = true; eaa_ = true; - eagerSimdUnbox_ = true; edgeCaseAnalysis_ = true; eliminateRedundantChecks_ = true; inlineInterpreted_ = true; @@ -66,7 +65,6 @@ OptimizationInfo::initWasmOptimizationInfo() ama_ = true; autoTruncate_ = false; - eagerSimdUnbox_ = false; // wasm has no boxing / unboxing. edgeCaseAnalysis_ = false; eliminateRedundantChecks_ = false; scalarReplacement_ = false; // wasm has no objects. diff --git a/js/src/jit/IonOptimizationLevels.h b/js/src/jit/IonOptimizationLevels.h index 811a2d43eb..37ed713dc8 100644 --- a/js/src/jit/IonOptimizationLevels.h +++ b/js/src/jit/IonOptimizationLevels.h @@ -65,9 +65,6 @@ class OptimizationInfo // Toggles whether native scripts get inlined. bool inlineNative_; - // Toggles whether eager unboxing of SIMD is used. - bool eagerSimdUnbox_; - // Toggles whether global value numbering is used. bool gvn_; @@ -169,10 +166,6 @@ class OptimizationInfo uint32_t compilerWarmUpThreshold(JSScript* script, jsbytecode* pc = nullptr) const; - bool eagerSimdUnboxEnabled() const { - return eagerSimdUnbox_ && !JitOptions.disableEagerSimdUnbox; - } - bool gvnEnabled() const { return gvn_ && !JitOptions.disableGvn; } diff --git a/js/src/jit/IonTypes.h b/js/src/jit/IonTypes.h index 50b09cc30e..50d612ac8e 100644 --- a/js/src/jit/IonTypes.h +++ b/js/src/jit/IonTypes.h @@ -105,9 +105,6 @@ enum BailoutKind Bailout_NonSymbolInput, Bailout_NonBigIntInput, - // SIMD Unbox expects a given type, bails out if it doesn't match. - Bailout_UnexpectedSimdInput, - // Atomic operations require shared memory, bail out if the typed array // maps unshared memory. Bailout_NonSharedTypedArrayInput, @@ -215,8 +212,6 @@ BailoutKindString(BailoutKind kind) return "Bailout_NonSymbolInput"; case Bailout_NonBigIntInput: return "Bailout_NonBigIntInput"; - case Bailout_UnexpectedSimdInput: - return "Bailout_UnexpectedSimdInput"; case Bailout_NonSharedTypedArrayInput: return "Bailout_NonSharedTypedArrayInput"; case Bailout_Debugger: @@ -261,6 +256,19 @@ static const uint32_t VECTOR_SCALE_BITS = 3; static const uint32_t VECTOR_SCALE_SHIFT = ELEMENT_TYPE_BITS + ELEMENT_TYPE_SHIFT; static const uint32_t VECTOR_SCALE_MASK = (1 << VECTOR_SCALE_BITS) - 1; +// The integer SIMD types have a lot of operations that do the exact same thing +// for signed and unsigned integer types. Sometimes it is simpler to treat +// signed and unsigned integer SIMD types as the same type, using a SimdSign to +// distinguish the few cases where there is a difference. +enum class SimdSign { + // Signedness is not applicable to this type. (i.e., Float or Bool). + NotApplicable, + // Treat as an unsigned integer with a range 0 .. 2^N-1. + Unsigned, + // Treat as a signed integer in two's complement encoding. + Signed, +}; + class SimdConstant { public: enum Type { @@ -451,39 +459,6 @@ IsSimdType(MIRType type) return ((unsigned(type) >> VECTOR_SCALE_SHIFT) & VECTOR_SCALE_MASK) != 0; } -// Returns the number of vector elements (hereby called "length") for a given -// SIMD kind. It is the Y part of the name "Foo x Y". -static inline unsigned -SimdTypeToLength(MIRType type) -{ - MOZ_ASSERT(IsSimdType(type)); - return 1 << ((unsigned(type) >> VECTOR_SCALE_SHIFT) & VECTOR_SCALE_MASK); -} - -// Get the type of the individual lanes in a SIMD type. -// For example, Int32x4 -> Int32, Float32x4 -> Float32 etc. -static inline MIRType -SimdTypeToLaneType(MIRType type) -{ - MOZ_ASSERT(IsSimdType(type)); - static_assert(unsigned(MIRType::Last) <= ELEMENT_TYPE_MASK, - "ELEMENT_TYPE_MASK should be larger than the last MIRType"); - return MIRType((unsigned(type) >> ELEMENT_TYPE_SHIFT) & ELEMENT_TYPE_MASK); -} - -// Get the type expected when inserting a lane into a SIMD type. -// This is the argument type expected by the MSimdValue constructors as well as -// MSimdSplat and MSimdInsertElement. -static inline MIRType -SimdTypeToLaneArgumentType(MIRType type) -{ - MIRType laneType = SimdTypeToLaneType(type); - - // Boolean lanes should be pre-converted to an Int32 with the values 0 or -1. - // All other lane types are inserted directly. - return laneType == MIRType::Boolean ? MIRType::Int32 : laneType; -} - static inline MIRType MIRTypeFromValueType(JSValueType type) { @@ -671,24 +646,6 @@ IsNullOrUndefined(MIRType type) } static inline bool -IsFloatingPointSimdType(MIRType type) -{ - return type == MIRType::Float32x4; -} - -static inline bool -IsIntegerSimdType(MIRType type) -{ - return IsSimdType(type) && SimdTypeToLaneType(type) == MIRType::Int32; -} - -static inline bool -IsBooleanSimdType(MIRType type) -{ - return IsSimdType(type) && SimdTypeToLaneType(type) == MIRType::Boolean; -} - -static inline bool IsMagicType(MIRType type) { return type == MIRType::MagicHole || @@ -716,21 +673,13 @@ ScalarTypeToMIRType(Scalar::Type type) return MIRType::Float32; case Scalar::Float64: return MIRType::Double; - case Scalar::Float32x4: - return MIRType::Float32x4; - case Scalar::Int8x16: - return MIRType::Int8x16; - case Scalar::Int16x8: - return MIRType::Int16x8; - case Scalar::Int32x4: - return MIRType::Int32x4; case Scalar::BigInt64: case Scalar::BigUint64: MOZ_CRASH("NYI"); case Scalar::MaxTypedArrayViewType: break; } - MOZ_CRASH("unexpected SIMD kind"); + MOZ_CRASH("unexpected kind"); } static inline const char* diff --git a/js/src/jit/JitCompartment.h b/js/src/jit/JitCompartment.h index f6282330e0..a6cbd86719 100644 --- a/js/src/jit/JitCompartment.h +++ b/js/src/jit/JitCompartment.h @@ -461,38 +461,12 @@ class JitCompartment JitCode* regExpSearcherStub_; JitCode* regExpTesterStub_; - mozilla::EnumeratedArray<SimdType, SimdType::Count, ReadBarrieredObject> simdTemplateObjects_; - JitCode* generateStringConcatStub(JSContext* cx); JitCode* generateRegExpMatcherStub(JSContext* cx); JitCode* generateRegExpSearcherStub(JSContext* cx); JitCode* generateRegExpTesterStub(JSContext* cx); public: - JSObject* getSimdTemplateObjectFor(JSContext* cx, Handle<SimdTypeDescr*> descr) { - ReadBarrieredObject& tpl = simdTemplateObjects_[descr->type()]; - if (!tpl) - tpl.set(TypedObject::createZeroed(cx, descr, 0, gc::TenuredHeap)); - return tpl.get(); - } - - JSObject* maybeGetSimdTemplateObjectFor(SimdType type) const { - const ReadBarrieredObject& tpl = simdTemplateObjects_[type]; - - // This function is used by Eager Simd Unbox phase, so we cannot use the - // read barrier. For more information, see the comment above - // CodeGenerator::simdRefreshTemplatesDuringLink_ . - return tpl.unbarrieredGet(); - } - - // This function is used to call the read barrier, to mark the SIMD template - // type as used. This function can only be called from the main thread. - void registerSimdTemplateObjectFor(SimdType type) { - ReadBarrieredObject& tpl = simdTemplateObjects_[type]; - MOZ_ASSERT(tpl.unbarrieredGet()); - tpl.get(); - } - JitCode* getStubCode(uint32_t key) { ICStubCodeMap::AddPtr p = stubCodes_->lookupForAdd(key); if (p) diff --git a/js/src/jit/JitFrameIterator.h b/js/src/jit/JitFrameIterator.h index b5b217b4e1..abe2dbb231 100644 --- a/js/src/jit/JitFrameIterator.h +++ b/js/src/jit/JitFrameIterator.h @@ -388,7 +388,6 @@ struct MaybeReadFallback class RResumePoint; -class RSimdBox; // Reads frame information in snapshot-encoding order (that is, outermost frame // to innermost frame). @@ -450,7 +449,6 @@ class SnapshotIterator void warnUnreadableAllocation(); private: - friend class RSimdBox; const FloatRegisters::RegisterContent* floatAllocationPointer(const RValueAllocation& a) const; public: diff --git a/js/src/jit/JitOptions.cpp b/js/src/jit/JitOptions.cpp index daae3d53b5..78f24bb803 100644 --- a/js/src/jit/JitOptions.cpp +++ b/js/src/jit/JitOptions.cpp @@ -83,9 +83,6 @@ DefaultJitOptions::DefaultJitOptions() // Toggles whether Effective Address Analysis is globally disabled. SET_DEFAULT(disableEaa, false); - // Toggle whether eager simd unboxing is globally disabled. - SET_DEFAULT(disableEagerSimdUnbox, false); - // Toggles whether Edge Case Analysis is gobally disabled. SET_DEFAULT(disableEdgeCaseAnalysis, false); diff --git a/js/src/jit/JitOptions.h b/js/src/jit/JitOptions.h index 6abb894cb9..0fbfc99829 100644 --- a/js/src/jit/JitOptions.h +++ b/js/src/jit/JitOptions.h @@ -49,7 +49,6 @@ struct DefaultJitOptions bool disableInlineBacktracking; bool disableAma; bool disableEaa; - bool disableEagerSimdUnbox; bool disableEdgeCaseAnalysis; bool disableFlowAA; bool disableGvn; diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h index e9143a6f41..bee3b3ebea 100644 --- a/js/src/jit/LIR.h +++ b/js/src/jit/LIR.h @@ -622,15 +622,6 @@ class LDefinition case MIRType::Int64: return LDefinition::GENERAL; #endif - case MIRType::Int8x16: - case MIRType::Int16x8: - case MIRType::Int32x4: - case MIRType::Bool8x16: - case MIRType::Bool16x8: - case MIRType::Bool32x4: - return LDefinition::SIMD128INT; - case MIRType::Float32x4: - return LDefinition::SIMD128FLOAT; default: MOZ_CRASH("unexpected type"); } diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index d315c618e7..11e7348547 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -3410,8 +3410,7 @@ LIRGenerator::visitLoadUnboxedScalar(MLoadUnboxedScalar* ins) const LUse elements = useRegister(ins->elements()); const LAllocation index = useRegisterOrConstant(ins->index()); - MOZ_ASSERT(IsNumberType(ins->type()) || IsSimdType(ins->type()) || - ins->type() == MIRType::Boolean); + MOZ_ASSERT(IsNumberType(ins->type()) || ins->type() == MIRType::Boolean); // We need a temp register for Uint32Array with known double result. LDefinition tempDef = LDefinition::BogusTemp(); @@ -3502,12 +3501,7 @@ LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment())); MOZ_ASSERT(ins->index()->type() == MIRType::Int32); - if (ins->isSimdWrite()) { - MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32x4, ins->value()->type() == MIRType::Float32x4); - MOZ_ASSERT_IF(ins->writeType() == Scalar::Int8x16, ins->value()->type() == MIRType::Int8x16); - MOZ_ASSERT_IF(ins->writeType() == Scalar::Int16x8, ins->value()->type() == MIRType::Int16x8); - MOZ_ASSERT_IF(ins->writeType() == Scalar::Int32x4, ins->value()->type() == MIRType::Int32x4); - } else if (ins->isFloatWrite()) { + if (ins->isFloatWrite()) { MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32, ins->value()->type() == MIRType::Float32); MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64, ins->value()->type() == MIRType::Double); } else { @@ -4284,7 +4278,7 @@ LIRGenerator::visitWasmParameter(MWasmParameter* ins) #endif ); } else { - MOZ_ASSERT(IsNumberType(ins->type()) || IsSimdType(ins->type())); + MOZ_ASSERT(IsNumberType(ins->type())); defineFixed(new(alloc()) LWasmParameter, ins, LArgument(abi.offsetFromArgBase())); } } @@ -4310,8 +4304,6 @@ LIRGenerator::visitWasmReturn(MWasmReturn* ins) lir->setOperand(0, useFixed(rval, ReturnFloat32Reg)); else if (rval->type() == MIRType::Double) lir->setOperand(0, useFixed(rval, ReturnDoubleReg)); - else if (IsSimdType(rval->type())) - lir->setOperand(0, useFixed(rval, ReturnSimd128Reg)); else if (rval->type() == MIRType::Int32) lir->setOperand(0, useFixed(rval, ReturnReg)); else @@ -4341,7 +4333,7 @@ LIRGenerator::visitWasmStackArg(MWasmStackArg* ins) { if (ins->arg()->type() == MIRType::Int64) { add(new(alloc()) LWasmStackArgI64(useInt64RegisterOrConstantAtStart(ins->arg())), ins); - } else if (IsFloatingPointType(ins->arg()->type()) || IsSimdType(ins->arg()->type())) { + } else if (IsFloatingPointType(ins->arg()->type())) { MOZ_ASSERT(!ins->arg()->isEmittedAtUses()); add(new(alloc()) LWasmStackArg(useRegisterAtStart(ins->arg())), ins); } else { @@ -4456,217 +4448,6 @@ LIRGenerator::visitRecompileCheck(MRecompileCheck* ins) } void -LIRGenerator::visitSimdBox(MSimdBox* ins) -{ - MOZ_ASSERT(IsSimdType(ins->input()->type())); - LUse in = useRegister(ins->input()); - LSimdBox* lir = new(alloc()) LSimdBox(in, temp()); - define(lir, ins); - assignSafepoint(lir, ins); -} - -void -LIRGenerator::visitSimdUnbox(MSimdUnbox* ins) -{ - MOZ_ASSERT(ins->input()->type() == MIRType::Object); - MOZ_ASSERT(IsSimdType(ins->type())); - LUse in = useRegister(ins->input()); - LSimdUnbox* lir = new(alloc()) LSimdUnbox(in, temp()); - assignSnapshot(lir, Bailout_UnexpectedSimdInput); - define(lir, ins); -} - -void -LIRGenerator::visitSimdConstant(MSimdConstant* ins) -{ - MOZ_ASSERT(IsSimdType(ins->type())); - - switch (ins->type()) { - case MIRType::Int8x16: - case MIRType::Int16x8: - case MIRType::Int32x4: - case MIRType::Bool8x16: - case MIRType::Bool16x8: - case MIRType::Bool32x4: - define(new(alloc()) LSimd128Int(), ins); - break; - case MIRType::Float32x4: - define(new(alloc()) LSimd128Float(), ins); - break; - default: - MOZ_CRASH("Unknown SIMD kind when generating constant"); - } -} - -void -LIRGenerator::visitSimdConvert(MSimdConvert* ins) -{ - MOZ_ASSERT(IsSimdType(ins->type())); - MDefinition* input = ins->input(); - LUse use = useRegister(input); - if (ins->type() == MIRType::Int32x4) { - MOZ_ASSERT(input->type() == MIRType::Float32x4); - switch (ins->signedness()) { - case SimdSign::Signed: { - LFloat32x4ToInt32x4* lir = new(alloc()) LFloat32x4ToInt32x4(use, temp()); - if (!gen->compilingWasm()) - assignSnapshot(lir, Bailout_BoundsCheck); - define(lir, ins); - break; - } - case SimdSign::Unsigned: { - LFloat32x4ToUint32x4* lir = - new (alloc()) LFloat32x4ToUint32x4(use, temp(), temp(LDefinition::SIMD128INT)); - if (!gen->compilingWasm()) - assignSnapshot(lir, Bailout_BoundsCheck); - define(lir, ins); - break; - } - default: - MOZ_CRASH("Unexpected SimdConvert sign"); - } - } else if (ins->type() == MIRType::Float32x4) { - MOZ_ASSERT(input->type() == MIRType::Int32x4); - MOZ_ASSERT(ins->signedness() == SimdSign::Signed, "Unexpected SimdConvert sign"); - define(new(alloc()) LInt32x4ToFloat32x4(use), ins); - } else { - MOZ_CRASH("Unknown SIMD kind when generating constant"); - } -} - -void -LIRGenerator::visitSimdReinterpretCast(MSimdReinterpretCast* ins) -{ - MOZ_ASSERT(IsSimdType(ins->type()) && IsSimdType(ins->input()->type())); - MDefinition* input = ins->input(); - LUse use = useRegisterAtStart(input); - // :TODO: (Bug 1132894) We have to allocate a different register as redefine - // and/or defineReuseInput are not yet capable of reusing the same register - // with a different register type. - define(new(alloc()) LSimdReinterpretCast(use), ins); -} - -void -LIRGenerator::visitSimdAllTrue(MSimdAllTrue* ins) -{ - MDefinition* input = ins->input(); - MOZ_ASSERT(IsBooleanSimdType(input->type())); - - LUse use = useRegisterAtStart(input); - define(new(alloc()) LSimdAllTrue(use), ins); -} - -void -LIRGenerator::visitSimdAnyTrue(MSimdAnyTrue* ins) -{ - MDefinition* input = ins->input(); - MOZ_ASSERT(IsBooleanSimdType(input->type())); - - LUse use = useRegisterAtStart(input); - define(new(alloc()) LSimdAnyTrue(use), ins); -} - -void -LIRGenerator::visitSimdUnaryArith(MSimdUnaryArith* ins) -{ - MOZ_ASSERT(IsSimdType(ins->input()->type())); - MOZ_ASSERT(IsSimdType(ins->type())); - - // Cannot be at start, as the ouput is used as a temporary to store values. - LUse in = use(ins->input()); - - switch (ins->type()) { - case MIRType::Int8x16: - case MIRType::Bool8x16: - define(new (alloc()) LSimdUnaryArithIx16(in), ins); - break; - case MIRType::Int16x8: - case MIRType::Bool16x8: - define(new (alloc()) LSimdUnaryArithIx8(in), ins); - break; - case MIRType::Int32x4: - case MIRType::Bool32x4: - define(new (alloc()) LSimdUnaryArithIx4(in), ins); - break; - case MIRType::Float32x4: - define(new (alloc()) LSimdUnaryArithFx4(in), ins); - break; - default: - MOZ_CRASH("Unknown SIMD kind for unary operation"); - } -} - -void -LIRGenerator::visitSimdBinaryComp(MSimdBinaryComp* ins) -{ - MOZ_ASSERT(IsSimdType(ins->lhs()->type())); - MOZ_ASSERT(IsSimdType(ins->rhs()->type())); - MOZ_ASSERT(IsBooleanSimdType(ins->type())); - - if (ShouldReorderCommutative(ins->lhs(), ins->rhs(), ins)) - ins->reverse(); - - switch (ins->specialization()) { - case MIRType::Int8x16: { - MOZ_ASSERT(ins->signedness() == SimdSign::Signed); - LSimdBinaryCompIx16* add = new (alloc()) LSimdBinaryCompIx16(); - lowerForFPU(add, ins, ins->lhs(), ins->rhs()); - return; - } - case MIRType::Int16x8: { - MOZ_ASSERT(ins->signedness() == SimdSign::Signed); - LSimdBinaryCompIx8* add = new (alloc()) LSimdBinaryCompIx8(); - lowerForFPU(add, ins, ins->lhs(), ins->rhs()); - return; - } - case MIRType::Int32x4: { - MOZ_ASSERT(ins->signedness() == SimdSign::Signed); - LSimdBinaryCompIx4* add = new (alloc()) LSimdBinaryCompIx4(); - lowerForCompIx4(add, ins, ins->lhs(), ins->rhs()); - return; - } - case MIRType::Float32x4: { - MOZ_ASSERT(ins->signedness() == SimdSign::NotApplicable); - LSimdBinaryCompFx4* add = new (alloc()) LSimdBinaryCompFx4(); - lowerForCompFx4(add, ins, ins->lhs(), ins->rhs()); - return; - } - default: - MOZ_CRASH("Unknown compare type when comparing values"); - } -} - -void -LIRGenerator::visitSimdBinaryBitwise(MSimdBinaryBitwise* ins) -{ - MOZ_ASSERT(IsSimdType(ins->lhs()->type())); - MOZ_ASSERT(IsSimdType(ins->rhs()->type())); - MOZ_ASSERT(IsSimdType(ins->type())); - - MDefinition* lhs = ins->lhs(); - MDefinition* rhs = ins->rhs(); - ReorderCommutative(&lhs, &rhs, ins); - LSimdBinaryBitwise* lir = new(alloc()) LSimdBinaryBitwise; - lowerForFPU(lir, ins, lhs, rhs); -} - -void -LIRGenerator::visitSimdShift(MSimdShift* ins) -{ - MOZ_ASSERT(IsIntegerSimdType(ins->type())); - MOZ_ASSERT(ins->lhs()->type() == ins->type()); - MOZ_ASSERT(ins->rhs()->type() == MIRType::Int32); - - LUse vector = useRegisterAtStart(ins->lhs()); - LAllocation value = useRegisterOrConstant(ins->rhs()); - // We need a temp register to mask the shift amount, but not if the shift - // amount is a constant. - LDefinition tempReg = value.isConstant() ? LDefinition::BogusTemp() : temp(); - LSimdShift* lir = new(alloc()) LSimdShift(vector, value, tempReg); - defineReuseInput(lir, ins, 0); -} - -void LIRGenerator::visitLexicalCheck(MLexicalCheck* ins) { MDefinition* input = ins->input(); diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index d0e00fb82f..9217ed9dcd 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -304,17 +304,6 @@ class LIRGenerator : public LIRGeneratorSpecific void visitGetDOMProperty(MGetDOMProperty* ins); void visitGetDOMMember(MGetDOMMember* ins); void visitRecompileCheck(MRecompileCheck* ins); - void visitSimdBox(MSimdBox* ins); - void visitSimdUnbox(MSimdUnbox* ins); - void visitSimdUnaryArith(MSimdUnaryArith* ins); - void visitSimdBinaryComp(MSimdBinaryComp* ins); - void visitSimdBinaryBitwise(MSimdBinaryBitwise* ins); - void visitSimdShift(MSimdShift* ins); - void visitSimdConstant(MSimdConstant* ins); - void visitSimdConvert(MSimdConvert* ins); - void visitSimdReinterpretCast(MSimdReinterpretCast* ins); - void visitSimdAllTrue(MSimdAllTrue* ins); - void visitSimdAnyTrue(MSimdAnyTrue* ins); void visitPhi(MPhi* ins); void visitBeta(MBeta* ins); void visitObjectState(MObjectState* ins); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 064c7ee7d2..0f78ef3f2f 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -10,7 +10,6 @@ #include "jsstr.h" #include "builtin/AtomicsObject.h" -#include "builtin/SIMD.h" #include "builtin/TestingFunctions.h" #include "builtin/TypedObject.h" #include "builtin/intl/Collator.h" @@ -233,28 +232,6 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) case InlinableNative::ObjectCreate: return inlineObjectCreate(callInfo); - // SIMD natives. - case InlinableNative::SimdInt32x4: - return inlineSimd(callInfo, target, SimdType::Int32x4); - case InlinableNative::SimdUint32x4: - return inlineSimd(callInfo, target, SimdType::Uint32x4); - case InlinableNative::SimdInt16x8: - return inlineSimd(callInfo, target, SimdType::Int16x8); - case InlinableNative::SimdUint16x8: - return inlineSimd(callInfo, target, SimdType::Uint16x8); - case InlinableNative::SimdInt8x16: - return inlineSimd(callInfo, target, SimdType::Int8x16); - case InlinableNative::SimdUint8x16: - return inlineSimd(callInfo, target, SimdType::Uint8x16); - case InlinableNative::SimdFloat32x4: - return inlineSimd(callInfo, target, SimdType::Float32x4); - case InlinableNative::SimdBool32x4: - return inlineSimd(callInfo, target, SimdType::Bool32x4); - case InlinableNative::SimdBool16x8: - return inlineSimd(callInfo, target, SimdType::Bool16x8); - case InlinableNative::SimdBool8x16: - return inlineSimd(callInfo, target, SimdType::Bool8x16); - // Testing functions. case InlinableNative::TestBailout: return inlineBailout(callInfo); @@ -430,9 +407,6 @@ IonBuilder::inlineNonFunctionCall(CallInfo& callInfo, JSObject* target) if (callInfo.constructing() && target->constructHook() == TypedObject::construct) return inlineConstructTypedObject(callInfo, &target->as<TypeDescr>()); - if (!callInfo.constructing() && target->callHook() == SimdTypeDescr::call) - return inlineConstructSimdObject(callInfo, &target->as<SimdTypeDescr>()); - return InliningStatus_NotInlined; } @@ -3384,767 +3358,6 @@ IonBuilder::inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* descr) return InliningStatus_Inlined; } -// Main entry point for SIMD inlining. -// When the controlling simdType is an integer type, sign indicates whether the lanes should -// be treated as signed or unsigned integers. -IonBuilder::InliningStatus -IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, SimdType type) -{ - if (!JitSupportsSimd()) { - trackOptimizationOutcome(TrackedOutcome::NoSimdJitSupport); - return InliningStatus_NotInlined; - } - - JSNative native = target->native(); - const JSJitInfo* jitInfo = target->jitInfo(); - MOZ_ASSERT(jitInfo && jitInfo->type() == JSJitInfo::InlinableNative); - SimdOperation simdOp = SimdOperation(jitInfo->nativeOp); - - switch(simdOp) { - case SimdOperation::Constructor: - // SIMD constructor calls are handled via inlineNonFunctionCall(), so - // they won't show up here where target is required to be a JSFunction. - // See also inlineConstructSimdObject(). - MOZ_CRASH("SIMD constructor call not expected."); - case SimdOperation::Fn_check: - return inlineSimdCheck(callInfo, native, type); - case SimdOperation::Fn_splat: - return inlineSimdSplat(callInfo, native, type); - case SimdOperation::Fn_extractLane: - return inlineSimdExtractLane(callInfo, native, type); - case SimdOperation::Fn_replaceLane: - return inlineSimdReplaceLane(callInfo, native, type); - case SimdOperation::Fn_select: - return inlineSimdSelect(callInfo, native, type); - case SimdOperation::Fn_swizzle: - return inlineSimdShuffle(callInfo, native, type, 1); - case SimdOperation::Fn_shuffle: - return inlineSimdShuffle(callInfo, native, type, 2); - - // Unary arithmetic. - case SimdOperation::Fn_abs: - return inlineSimdUnary(callInfo, native, MSimdUnaryArith::abs, type); - case SimdOperation::Fn_neg: - return inlineSimdUnary(callInfo, native, MSimdUnaryArith::neg, type); - case SimdOperation::Fn_not: - return inlineSimdUnary(callInfo, native, MSimdUnaryArith::not_, type); - case SimdOperation::Fn_reciprocalApproximation: - return inlineSimdUnary(callInfo, native, MSimdUnaryArith::reciprocalApproximation, - type); - case SimdOperation::Fn_reciprocalSqrtApproximation: - return inlineSimdUnary(callInfo, native, MSimdUnaryArith::reciprocalSqrtApproximation, - type); - case SimdOperation::Fn_sqrt: - return inlineSimdUnary(callInfo, native, MSimdUnaryArith::sqrt, type); - - // Binary arithmetic. - case SimdOperation::Fn_add: - return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_add, type); - case SimdOperation::Fn_sub: - return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_sub, type); - case SimdOperation::Fn_mul: - return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_mul, type); - case SimdOperation::Fn_div: - return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_div, type); - case SimdOperation::Fn_max: - return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_max, type); - case SimdOperation::Fn_min: - return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_min, type); - case SimdOperation::Fn_maxNum: - return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_maxNum, type); - case SimdOperation::Fn_minNum: - return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_minNum, type); - - // Binary saturating. - case SimdOperation::Fn_addSaturate: - return inlineSimdBinarySaturating(callInfo, native, MSimdBinarySaturating::add, type); - case SimdOperation::Fn_subSaturate: - return inlineSimdBinarySaturating(callInfo, native, MSimdBinarySaturating::sub, type); - - // Binary bitwise. - case SimdOperation::Fn_and: - return inlineSimdBinaryBitwise(callInfo, native, MSimdBinaryBitwise::and_, type); - case SimdOperation::Fn_or: - return inlineSimdBinaryBitwise(callInfo, native, MSimdBinaryBitwise::or_, type); - case SimdOperation::Fn_xor: - return inlineSimdBinaryBitwise(callInfo, native, MSimdBinaryBitwise::xor_, type); - - // Shifts. - case SimdOperation::Fn_shiftLeftByScalar: - return inlineSimdShift(callInfo, native, MSimdShift::lsh, type); - case SimdOperation::Fn_shiftRightByScalar: - return inlineSimdShift(callInfo, native, MSimdShift::rshForSign(GetSimdSign(type)), type); - - // Boolean unary. - case SimdOperation::Fn_allTrue: - return inlineSimdAnyAllTrue(callInfo, /* IsAllTrue= */true, native, type); - case SimdOperation::Fn_anyTrue: - return inlineSimdAnyAllTrue(callInfo, /* IsAllTrue= */false, native, type); - - // Comparisons. - case SimdOperation::Fn_lessThan: - return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThan, type); - case SimdOperation::Fn_lessThanOrEqual: - return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThanOrEqual, type); - case SimdOperation::Fn_equal: - return inlineSimdComp(callInfo, native, MSimdBinaryComp::equal, type); - case SimdOperation::Fn_notEqual: - return inlineSimdComp(callInfo, native, MSimdBinaryComp::notEqual, type); - case SimdOperation::Fn_greaterThan: - return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThan, type); - case SimdOperation::Fn_greaterThanOrEqual: - return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThanOrEqual, type); - - // Int <-> Float conversions. - case SimdOperation::Fn_fromInt32x4: - return inlineSimdConvert(callInfo, native, false, SimdType::Int32x4, type); - case SimdOperation::Fn_fromUint32x4: - return inlineSimdConvert(callInfo, native, false, SimdType::Uint32x4, type); - case SimdOperation::Fn_fromFloat32x4: - return inlineSimdConvert(callInfo, native, false, SimdType::Float32x4, type); - - // Load/store. - case SimdOperation::Fn_load: - return inlineSimdLoad(callInfo, native, type, GetSimdLanes(type)); - case SimdOperation::Fn_load1: - return inlineSimdLoad(callInfo, native, type, 1); - case SimdOperation::Fn_load2: - return inlineSimdLoad(callInfo, native, type, 2); - case SimdOperation::Fn_load3: - return inlineSimdLoad(callInfo, native, type, 3); - case SimdOperation::Fn_store: - return inlineSimdStore(callInfo, native, type, GetSimdLanes(type)); - case SimdOperation::Fn_store1: - return inlineSimdStore(callInfo, native, type, 1); - case SimdOperation::Fn_store2: - return inlineSimdStore(callInfo, native, type, 2); - case SimdOperation::Fn_store3: - return inlineSimdStore(callInfo, native, type, 3); - - // Bitcasts. One for each type with a memory representation. - case SimdOperation::Fn_fromInt32x4Bits: - return inlineSimdConvert(callInfo, native, true, SimdType::Int32x4, type); - case SimdOperation::Fn_fromUint32x4Bits: - return inlineSimdConvert(callInfo, native, true, SimdType::Uint32x4, type); - case SimdOperation::Fn_fromInt16x8Bits: - return inlineSimdConvert(callInfo, native, true, SimdType::Int16x8, type); - case SimdOperation::Fn_fromUint16x8Bits: - return inlineSimdConvert(callInfo, native, true, SimdType::Uint16x8, type); - case SimdOperation::Fn_fromInt8x16Bits: - return inlineSimdConvert(callInfo, native, true, SimdType::Int8x16, type); - case SimdOperation::Fn_fromUint8x16Bits: - return inlineSimdConvert(callInfo, native, true, SimdType::Uint8x16, type); - case SimdOperation::Fn_fromFloat32x4Bits: - return inlineSimdConvert(callInfo, native, true, SimdType::Float32x4, type); - case SimdOperation::Fn_fromFloat64x2Bits: - return InliningStatus_NotInlined; - } - - MOZ_CRASH("Unexpected SIMD opcode"); -} - -// The representation of boolean SIMD vectors is the same as the corresponding -// integer SIMD vectors with -1 lanes meaning true and 0 lanes meaning false. -// -// Functions that set the value of a boolean vector lane work by applying -// ToBoolean on the input argument, so they accept any argument type, just like -// the MNot and MTest instructions. -// -// Convert any scalar value into an appropriate SIMD lane value: An Int32 value -// that is either 0 for false or -1 for true. -MDefinition* -IonBuilder::convertToBooleanSimdLane(MDefinition* scalar) -{ - MSub* result; - - if (scalar->type() == MIRType::Boolean) { - // The input scalar is already a boolean with the int32 values 0 / 1. - // Compute result = 0 - scalar. - result = MSub::New(alloc(), constant(Int32Value(0)), scalar); - } else { - // For any other type, let MNot handle the conversion to boolean. - // Compute result = !scalar - 1. - MNot* inv = MNot::New(alloc(), scalar); - current->add(inv); - result = MSub::New(alloc(), inv, constant(Int32Value(1))); - } - - result->setInt32Specialization(); - current->add(result); - return result; -} - -IonBuilder::InliningStatus -IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr) -{ - if (!JitSupportsSimd()) { - trackOptimizationOutcome(TrackedOutcome::NoSimdJitSupport); - return InliningStatus_NotInlined; - } - - // Generic constructor of SIMD valuesX4. - MIRType simdType; - if (!MaybeSimdTypeToMIRType(descr->type(), &simdType)) { - trackOptimizationOutcome(TrackedOutcome::SimdTypeNotOptimized); - return InliningStatus_NotInlined; - } - - // Take the templateObject out of Baseline ICs, such that we can box - // SIMD value type in the same kind of objects. - MOZ_ASSERT(size_t(descr->size(descr->type())) < InlineTypedObject::MaximumSize); - MOZ_ASSERT(descr->getClass() == &SimdTypeDescr::class_, - "getTemplateObjectForSimdCtor needs an update"); - - JSObject* templateObject = inspector->getTemplateObjectForSimdCtor(pc, descr->type()); - if (!templateObject) - return InliningStatus_NotInlined; - - // The previous assertion ensures this will never fail if we were able to - // allocate a templateObject in Baseline. - InlineTypedObject* inlineTypedObject = &templateObject->as<InlineTypedObject>(); - MOZ_ASSERT(&inlineTypedObject->typeDescr() == descr); - - // When there are missing arguments, provide a default value - // containing the coercion of 'undefined' to the right type. - MConstant* defVal = nullptr; - MIRType laneType = SimdTypeToLaneType(simdType); - unsigned lanes = SimdTypeToLength(simdType); - if (lanes != 4 || callInfo.argc() < lanes) { - if (laneType == MIRType::Int32 || laneType == MIRType::Boolean) { - // The default lane for a boolean vector is |false|, but - // |MSimdSplat|, |MSimdValueX4|, and |MSimdInsertElement| all - // require an Int32 argument with the value 0 or 01 to initialize a - // boolean lane. See also convertToBooleanSimdLane() which is - // idempotent with a 0 argument after constant folding. - defVal = constant(Int32Value(0)); - } else if (laneType == MIRType::Double) { - defVal = constant(DoubleNaNValue()); - } else { - MOZ_ASSERT(laneType == MIRType::Float32); - defVal = MConstant::NewFloat32(alloc(), JS::GenericNaN()); - current->add(defVal); - } - } - - MInstruction *values = nullptr; - - // Use the MSimdValueX4 constructor for X4 vectors. - if (lanes == 4) { - MDefinition* lane[4]; - for (unsigned i = 0; i < 4; i++) - lane[i] = callInfo.getArgWithDefault(i, defVal); - - // Convert boolean lanes into Int32 0 / -1. - if (laneType == MIRType::Boolean) { - for (unsigned i = 0; i < 4; i++) - lane[i] = convertToBooleanSimdLane(lane[i]); - } - - values = MSimdValueX4::New(alloc(), simdType, lane[0], lane[1], lane[2], lane[3]); - current->add(values); - } else { - // For general constructor calls, start from splat(defVal), insert one - // lane at a time. - values = MSimdSplat::New(alloc(), defVal, simdType); - current->add(values); - - // Stop early if constructor doesn't have enough arguments. These lanes - // then get the default value. - if (callInfo.argc() < lanes) - lanes = callInfo.argc(); - - for (unsigned i = 0; i < lanes; i++) { - MDefinition* lane = callInfo.getArg(i); - if (laneType == MIRType::Boolean) - lane = convertToBooleanSimdLane(lane); - values = MSimdInsertElement::New(alloc(), values, lane, i); - current->add(values); - } - } - - MSimdBox* obj = MSimdBox::New(alloc(), constraints(), values, inlineTypedObject, descr->type(), - inlineTypedObject->group()->initialHeap(constraints())); - current->add(obj); - current->push(obj); - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -bool -IonBuilder::canInlineSimd(CallInfo& callInfo, JSNative native, unsigned numArgs, - InlineTypedObject** templateObj) -{ - if (callInfo.argc() != numArgs) - return false; - - JSObject* templateObject = inspector->getTemplateObjectForNative(pc, native); - if (!templateObject) - return false; - - *templateObj = &templateObject->as<InlineTypedObject>(); - return true; -} - -IonBuilder::InliningStatus -IonBuilder::inlineSimdCheck(CallInfo& callInfo, JSNative native, SimdType type) -{ - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 1, &templateObj)) - return InliningStatus_NotInlined; - - // Unboxing checks the SIMD object type and throws a TypeError if it doesn't - // match type. - MDefinition *arg = unboxSimd(callInfo.getArg(0), type); - - // Create an unbox/box pair, expecting the box to be optimized away if - // anyone use the return value from this check() call. This is what you want - // for code like this: - // - // function f(x) { - // x = Int32x4.check(x) - // for(...) { - // y = Int32x4.add(x, ...) - // } - // - // The unboxing of x happens as early as possible, and only once. - return boxSimd(callInfo, arg, templateObj); -} - -// Given a value or object, insert a dynamic check that this is a SIMD object of -// the required SimdType, and unbox it into the corresponding SIMD MIRType. -// -// This represents the standard type checking that all the SIMD operations -// perform on their arguments. -MDefinition* -IonBuilder::unboxSimd(MDefinition* ins, SimdType type) -{ - // Trivial optimization: If ins is a MSimdBox of the same SIMD type, there - // is no way the unboxing could fail, and we can skip it altogether. - // This is the same thing MSimdUnbox::foldsTo() does, but we can save the - // memory allocation here. - if (ins->isSimdBox()) { - MSimdBox* box = ins->toSimdBox(); - if (box->simdType() == type) { - MDefinition* value = box->input(); - MOZ_ASSERT(value->type() == SimdTypeToMIRType(type)); - return value; - } - } - - MSimdUnbox* unbox = MSimdUnbox::New(alloc(), ins, type); - current->add(unbox); - return unbox; -} - -IonBuilder::InliningStatus -IonBuilder::boxSimd(CallInfo& callInfo, MDefinition* ins, InlineTypedObject* templateObj) -{ - SimdType simdType = templateObj->typeDescr().as<SimdTypeDescr>().type(); - MSimdBox* obj = MSimdBox::New(alloc(), constraints(), ins, templateObj, simdType, - templateObj->group()->initialHeap(constraints())); - - // In some cases, ins has already been added to current. - if (!ins->block() && ins->isInstruction()) - current->add(ins->toInstruction()); - current->add(obj); - current->push(obj); - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningStatus -IonBuilder::inlineSimdBinaryArith(CallInfo& callInfo, JSNative native, - MSimdBinaryArith::Operation op, SimdType type) -{ - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 2, &templateObj)) - return InliningStatus_NotInlined; - - MDefinition* lhs = unboxSimd(callInfo.getArg(0), type); - MDefinition* rhs = unboxSimd(callInfo.getArg(1), type); - - auto* ins = MSimdBinaryArith::AddLegalized(alloc(), current, lhs, rhs, op); - return boxSimd(callInfo, ins, templateObj); -} - -IonBuilder::InliningStatus -IonBuilder::inlineSimdBinaryBitwise(CallInfo& callInfo, JSNative native, - MSimdBinaryBitwise::Operation op, SimdType type) -{ - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 2, &templateObj)) - return InliningStatus_NotInlined; - - MDefinition* lhs = unboxSimd(callInfo.getArg(0), type); - MDefinition* rhs = unboxSimd(callInfo.getArg(1), type); - - auto* ins = MSimdBinaryBitwise::New(alloc(), lhs, rhs, op); - return boxSimd(callInfo, ins, templateObj); -} - -// Inline a binary SIMD operation where both arguments are SIMD types. -IonBuilder::InliningStatus -IonBuilder::inlineSimdBinarySaturating(CallInfo& callInfo, JSNative native, - MSimdBinarySaturating::Operation op, SimdType type) -{ - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 2, &templateObj)) - return InliningStatus_NotInlined; - - MDefinition* lhs = unboxSimd(callInfo.getArg(0), type); - MDefinition* rhs = unboxSimd(callInfo.getArg(1), type); - - MSimdBinarySaturating* ins = - MSimdBinarySaturating::New(alloc(), lhs, rhs, op, GetSimdSign(type)); - return boxSimd(callInfo, ins, templateObj); -} - -// Inline a SIMD shiftByScalar operation. -IonBuilder::InliningStatus -IonBuilder::inlineSimdShift(CallInfo& callInfo, JSNative native, MSimdShift::Operation op, - SimdType type) -{ - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 2, &templateObj)) - return InliningStatus_NotInlined; - - MDefinition* vec = unboxSimd(callInfo.getArg(0), type); - - MInstruction* ins = MSimdShift::AddLegalized(alloc(), current, vec, callInfo.getArg(1), op); - return boxSimd(callInfo, ins, templateObj); -} - -IonBuilder::InliningStatus -IonBuilder::inlineSimdComp(CallInfo& callInfo, JSNative native, MSimdBinaryComp::Operation op, - SimdType type) -{ - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 2, &templateObj)) - return InliningStatus_NotInlined; - - MDefinition* lhs = unboxSimd(callInfo.getArg(0), type); - MDefinition* rhs = unboxSimd(callInfo.getArg(1), type); - MInstruction* ins = - MSimdBinaryComp::AddLegalized(alloc(), current, lhs, rhs, op, GetSimdSign(type)); - return boxSimd(callInfo, ins, templateObj); -} - -IonBuilder::InliningStatus -IonBuilder::inlineSimdUnary(CallInfo& callInfo, JSNative native, MSimdUnaryArith::Operation op, - SimdType type) -{ - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 1, &templateObj)) - return InliningStatus_NotInlined; - - MDefinition* arg = unboxSimd(callInfo.getArg(0), type); - - MSimdUnaryArith* ins = MSimdUnaryArith::New(alloc(), arg, op); - return boxSimd(callInfo, ins, templateObj); -} - -IonBuilder::InliningStatus -IonBuilder::inlineSimdSplat(CallInfo& callInfo, JSNative native, SimdType type) -{ - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 1, &templateObj)) - return InliningStatus_NotInlined; - - MIRType mirType = SimdTypeToMIRType(type); - MDefinition* arg = callInfo.getArg(0); - - // Convert to 0 / -1 before splatting a boolean lane. - if (SimdTypeToLaneType(mirType) == MIRType::Boolean) - arg = convertToBooleanSimdLane(arg); - - MSimdSplat* ins = MSimdSplat::New(alloc(), arg, mirType); - return boxSimd(callInfo, ins, templateObj); -} - -IonBuilder::InliningStatus -IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native, SimdType type) -{ - // extractLane() returns a scalar, so don't use canInlineSimd() which looks - // for a template object. - if (callInfo.argc() != 2 || callInfo.constructing()) { - trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm); - return InliningStatus_NotInlined; - } - - // Lane index. - MDefinition* arg = callInfo.getArg(1); - if (!arg->isConstant() || arg->type() != MIRType::Int32) - return InliningStatus_NotInlined; - unsigned lane = arg->toConstant()->toInt32(); - if (lane >= GetSimdLanes(type)) - return InliningStatus_NotInlined; - - // Original vector. - MDefinition* orig = unboxSimd(callInfo.getArg(0), type); - MIRType vecType = orig->type(); - MIRType laneType = SimdTypeToLaneType(vecType); - SimdSign sign = GetSimdSign(type); - - // An Uint32 lane can't be represented in MIRType::Int32. Get it as a double. - if (type == SimdType::Uint32x4) - laneType = MIRType::Double; - - MSimdExtractElement* ins = - MSimdExtractElement::New(alloc(), orig, laneType, lane, sign); - current->add(ins); - current->push(ins); - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningStatus -IonBuilder::inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, SimdType type) -{ - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 3, &templateObj)) - return InliningStatus_NotInlined; - - // Lane index. - MDefinition* arg = callInfo.getArg(1); - if (!arg->isConstant() || arg->type() != MIRType::Int32) - return InliningStatus_NotInlined; - - unsigned lane = arg->toConstant()->toInt32(); - if (lane >= GetSimdLanes(type)) - return InliningStatus_NotInlined; - - // Original vector. - MDefinition* orig = unboxSimd(callInfo.getArg(0), type); - MIRType vecType = orig->type(); - - // Convert to 0 / -1 before inserting a boolean lane. - MDefinition* value = callInfo.getArg(2); - if (SimdTypeToLaneType(vecType) == MIRType::Boolean) - value = convertToBooleanSimdLane(value); - - MSimdInsertElement* ins = MSimdInsertElement::New(alloc(), orig, value, lane); - return boxSimd(callInfo, ins, templateObj); -} - -// Inline a SIMD conversion or bitcast. When isCast==false, one of the types -// must be floating point and the other integer. In this case, sign indicates if -// the integer lanes should be treated as signed or unsigned integers. -IonBuilder::InliningStatus -IonBuilder::inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast, SimdType fromType, - SimdType toType) -{ - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 1, &templateObj)) - return InliningStatus_NotInlined; - - MDefinition* arg = unboxSimd(callInfo.getArg(0), fromType); - MIRType mirType = SimdTypeToMIRType(toType); - - MInstruction* ins; - if (isCast) { - // Signed/Unsigned doesn't matter for bitcasts. - ins = MSimdReinterpretCast::New(alloc(), arg, mirType); - } else { - // Exactly one of fromType, toType must be an integer type. - SimdSign sign = GetSimdSign(fromType); - if (sign == SimdSign::NotApplicable) - sign = GetSimdSign(toType); - - // Possibly expand into multiple instructions. - ins = MSimdConvert::AddLegalized(alloc(), current, arg, mirType, sign); - } - - return boxSimd(callInfo, ins, templateObj); -} - -IonBuilder::InliningStatus -IonBuilder::inlineSimdSelect(CallInfo& callInfo, JSNative native, SimdType type) -{ - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 3, &templateObj)) - return InliningStatus_NotInlined; - - MDefinition* mask = unboxSimd(callInfo.getArg(0), GetBooleanSimdType(type)); - MDefinition* tval = unboxSimd(callInfo.getArg(1), type); - MDefinition* fval = unboxSimd(callInfo.getArg(2), type); - - MSimdSelect* ins = MSimdSelect::New(alloc(), mask, tval, fval); - return boxSimd(callInfo, ins, templateObj); -} - -IonBuilder::InliningStatus -IonBuilder::inlineSimdShuffle(CallInfo& callInfo, JSNative native, SimdType type, - unsigned numVectors) -{ - unsigned numLanes = GetSimdLanes(type); - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, numVectors + numLanes, &templateObj)) - return InliningStatus_NotInlined; - - MIRType mirType = SimdTypeToMIRType(type); - - MSimdGeneralShuffle* ins = MSimdGeneralShuffle::New(alloc(), numVectors, numLanes, mirType); - - if (!ins->init(alloc())) - return InliningStatus_Error; - - for (unsigned i = 0; i < numVectors; i++) - ins->setVector(i, unboxSimd(callInfo.getArg(i), type)); - for (size_t i = 0; i < numLanes; i++) - ins->setLane(i, callInfo.getArg(numVectors + i)); - - return boxSimd(callInfo, ins, templateObj); -} - -IonBuilder::InliningStatus -IonBuilder::inlineSimdAnyAllTrue(CallInfo& callInfo, bool IsAllTrue, JSNative native, - SimdType type) -{ - // anyTrue() / allTrue() return a scalar, so don't use canInlineSimd() which looks - // for a template object. - if (callInfo.argc() != 1 || callInfo.constructing()) { - trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm); - return InliningStatus_NotInlined; - } - - MDefinition* arg = unboxSimd(callInfo.getArg(0), type); - - MUnaryInstruction* ins; - if (IsAllTrue) - ins = MSimdAllTrue::New(alloc(), arg, MIRType::Boolean); - else - ins = MSimdAnyTrue::New(alloc(), arg, MIRType::Boolean); - - current->add(ins); - current->push(ins); - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -// Get the typed array element type corresponding to the lanes in a SIMD vector type. -// This only applies to SIMD types that can be loaded and stored to a typed array. -static Scalar::Type -SimdTypeToArrayElementType(SimdType type) -{ - switch (type) { - case SimdType::Float32x4: return Scalar::Float32x4; - case SimdType::Int8x16: - case SimdType::Uint8x16: return Scalar::Int8x16; - case SimdType::Int16x8: - case SimdType::Uint16x8: return Scalar::Int16x8; - case SimdType::Int32x4: - case SimdType::Uint32x4: return Scalar::Int32x4; - default: MOZ_CRASH("unexpected simd type"); - } -} - -bool -IonBuilder::prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, MInstruction** elements, - MDefinition** index, Scalar::Type* arrayType) -{ - MDefinition* array = callInfo.getArg(0); - *index = callInfo.getArg(1); - - if (!ElementAccessIsTypedArray(constraints(), array, *index, arrayType)) - return false; - - MInstruction* indexAsInt32 = MToInt32::New(alloc(), *index); - current->add(indexAsInt32); - *index = indexAsInt32; - - MDefinition* indexForBoundsCheck = *index; - - // Artificially make sure the index is in bounds by adding the difference - // number of slots needed (e.g. reading from Float32Array we need to make - // sure to be in bounds for 4 slots, so add 3, etc.). - MOZ_ASSERT(Scalar::byteSize(simdType) % Scalar::byteSize(*arrayType) == 0); - int32_t suppSlotsNeeded = Scalar::byteSize(simdType) / Scalar::byteSize(*arrayType) - 1; - if (suppSlotsNeeded) { - MConstant* suppSlots = constant(Int32Value(suppSlotsNeeded)); - MAdd* addedIndex = MAdd::New(alloc(), *index, suppSlots); - // We're fine even with the add overflows, as long as the generated code - // for the bounds check uses an unsigned comparison. - addedIndex->setInt32Specialization(); - current->add(addedIndex); - indexForBoundsCheck = addedIndex; - } - - MInstruction* length; - addTypedArrayLengthAndData(array, SkipBoundsCheck, index, &length, elements); - - // It can be that the index is out of bounds, while the added index for the - // bounds check is in bounds, so we actually need two bounds checks here. - MInstruction* positiveCheck = MBoundsCheck::New(alloc(), *index, length); - current->add(positiveCheck); - - MInstruction* fullCheck = MBoundsCheck::New(alloc(), indexForBoundsCheck, length); - current->add(fullCheck); - return true; -} - -IonBuilder::InliningStatus -IonBuilder::inlineSimdLoad(CallInfo& callInfo, JSNative native, SimdType type, unsigned numElems) -{ - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 2, &templateObj)) - return InliningStatus_NotInlined; - - Scalar::Type elemType = SimdTypeToArrayElementType(type); - - MDefinition* index = nullptr; - MInstruction* elements = nullptr; - Scalar::Type arrayType; - if (!prepareForSimdLoadStore(callInfo, elemType, &elements, &index, &arrayType)) - return InliningStatus_NotInlined; - - MLoadUnboxedScalar* load = MLoadUnboxedScalar::New(alloc(), elements, index, arrayType); - load->setResultType(SimdTypeToMIRType(type)); - load->setSimdRead(elemType, numElems); - - return boxSimd(callInfo, load, templateObj); -} - -IonBuilder::InliningStatus -IonBuilder::inlineSimdStore(CallInfo& callInfo, JSNative native, SimdType type, unsigned numElems) -{ - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 3, &templateObj)) - return InliningStatus_NotInlined; - - Scalar::Type elemType = SimdTypeToArrayElementType(type); - - MDefinition* index = nullptr; - MInstruction* elements = nullptr; - Scalar::Type arrayType; - if (!prepareForSimdLoadStore(callInfo, elemType, &elements, &index, &arrayType)) - return InliningStatus_NotInlined; - - MDefinition* valueToWrite = unboxSimd(callInfo.getArg(2), type); - MStoreUnboxedScalar* store = MStoreUnboxedScalar::New(alloc(), elements, index, - valueToWrite, arrayType, - MStoreUnboxedScalar::TruncateInput); - store->setSimdWrite(elemType, numElems); - - current->add(store); - // Produce the original boxed value as our return value. - // This is unlikely to be used, so don't bother reboxing valueToWrite. - current->push(callInfo.getArg(2)); - - callInfo.setImplicitlyUsedUnchecked(); - - if (!resumeAfter(store)) - return InliningStatus_Error; - - return InliningStatus_Inlined; -} - -// Note that SIMD.cpp provides its own JSJitInfo objects for SIMD.foo.* functions. -// The Simd* objects defined here represent SIMD.foo() constructor calls. -// They are encoded with .nativeOp = 0. That is the sub-opcode within the SIMD type. -static_assert(uint16_t(SimdOperation::Constructor) == 0, "Constructor opcode must be 0"); - #define ADD_NATIVE(native) const JSJitInfo JitInfo_##native { \ { nullptr }, { uint16_t(InlinableNative::native) }, { 0 }, JSJitInfo::InlinableNative }; INLINABLE_NATIVE_LIST(ADD_NATIVE) diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 2264bed4f2..34d9e07bf9 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -1235,530 +1235,6 @@ MConstant::valueToBoolean(bool* res) const } } -MDefinition* -MSimdValueX4::foldsTo(TempAllocator& alloc) -{ -#ifdef DEBUG - MIRType laneType = SimdTypeToLaneArgumentType(type()); -#endif - bool allConstants = true; - bool allSame = true; - - for (size_t i = 0; i < 4; ++i) { - MDefinition* op = getOperand(i); - MOZ_ASSERT(op->type() == laneType); - if (!op->isConstant()) - allConstants = false; - if (i > 0 && op != getOperand(i - 1)) - allSame = false; - } - - if (!allConstants && !allSame) - return this; - - if (allConstants) { - SimdConstant cst; - switch (type()) { - case MIRType::Bool32x4: { - int32_t a[4]; - for (size_t i = 0; i < 4; ++i) - a[i] = getOperand(i)->toConstant()->valueToBooleanInfallible() ? -1 : 0; - cst = SimdConstant::CreateX4(a); - break; - } - case MIRType::Int32x4: { - int32_t a[4]; - for (size_t i = 0; i < 4; ++i) - a[i] = getOperand(i)->toConstant()->toInt32(); - cst = SimdConstant::CreateX4(a); - break; - } - case MIRType::Float32x4: { - float a[4]; - for (size_t i = 0; i < 4; ++i) - a[i] = getOperand(i)->toConstant()->numberToDouble(); - cst = SimdConstant::CreateX4(a); - break; - } - default: MOZ_CRASH("unexpected type in MSimdValueX4::foldsTo"); - } - - return MSimdConstant::New(alloc, cst, type()); - } - - MOZ_ASSERT(allSame); - return MSimdSplat::New(alloc, getOperand(0), type()); -} - -MDefinition* -MSimdSplat::foldsTo(TempAllocator& alloc) -{ -#ifdef DEBUG - MIRType laneType = SimdTypeToLaneArgumentType(type()); -#endif - MDefinition* op = getOperand(0); - if (!op->isConstant()) - return this; - MOZ_ASSERT(op->type() == laneType); - - SimdConstant cst; - switch (type()) { - case MIRType::Bool8x16: { - int8_t v = op->toConstant()->valueToBooleanInfallible() ? -1 : 0; - cst = SimdConstant::SplatX16(v); - break; - } - case MIRType::Bool16x8: { - int16_t v = op->toConstant()->valueToBooleanInfallible() ? -1 : 0; - cst = SimdConstant::SplatX8(v); - break; - } - case MIRType::Bool32x4: { - int32_t v = op->toConstant()->valueToBooleanInfallible() ? -1 : 0; - cst = SimdConstant::SplatX4(v); - break; - } - case MIRType::Int8x16: { - int32_t v = op->toConstant()->toInt32(); - cst = SimdConstant::SplatX16(v); - break; - } - case MIRType::Int16x8: { - int32_t v = op->toConstant()->toInt32(); - cst = SimdConstant::SplatX8(v); - break; - } - case MIRType::Int32x4: { - int32_t v = op->toConstant()->toInt32(); - cst = SimdConstant::SplatX4(v); - break; - } - case MIRType::Float32x4: { - float v = op->toConstant()->numberToDouble(); - cst = SimdConstant::SplatX4(v); - break; - } - default: MOZ_CRASH("unexpected type in MSimdSplat::foldsTo"); - } - - return MSimdConstant::New(alloc, cst, type()); -} - -MDefinition* -MSimdUnbox::foldsTo(TempAllocator& alloc) -{ - MDefinition* in = input(); - - if (in->isSimdBox()) { - MSimdBox* box = in->toSimdBox(); - // If the operand is a MSimdBox, then we just reuse the operand of the - // MSimdBox as long as the type corresponds to what we are supposed to - // unbox. - in = box->input(); - if (box->simdType() != simdType()) - return this; - MOZ_ASSERT(in->type() == type()); - return in; - } - - return this; -} - -MDefinition* -MSimdSwizzle::foldsTo(TempAllocator& alloc) -{ - if (lanesMatch(0, 1, 2, 3)) - return input(); - return this; -} - -MDefinition* -MSimdGeneralShuffle::foldsTo(TempAllocator& alloc) -{ - FixedList<uint8_t> lanes; - if (!lanes.init(alloc, numLanes())) - return this; - - for (size_t i = 0; i < numLanes(); i++) { - if (!lane(i)->isConstant() || lane(i)->type() != MIRType::Int32) - return this; - int32_t temp = lane(i)->toConstant()->toInt32(); - if (temp < 0 || unsigned(temp) >= numLanes() * numVectors()) - return this; - lanes[i] = uint8_t(temp); - } - - if (numVectors() == 1) - return MSimdSwizzle::New(alloc, vector(0), lanes.data()); - - MOZ_ASSERT(numVectors() == 2); - return MSimdShuffle::New(alloc, vector(0), vector(1), lanes.data()); -} - -MInstruction* -MSimdConvert::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* obj, - MIRType toType, SimdSign sign, wasm::TrapOffset trapOffset) -{ - MIRType fromType = obj->type(); - - if (SupportsUint32x4FloatConversions || sign != SimdSign::Unsigned) { - MInstruction* ins = New(alloc, obj, toType, sign, trapOffset); - addTo->add(ins); - return ins; - } - - // This architecture can't do Uint32x4 <-> Float32x4 conversions (Hi SSE!) - MOZ_ASSERT(sign == SimdSign::Unsigned); - if (fromType == MIRType::Int32x4 && toType == MIRType::Float32x4) { - // Converting Uint32x4 -> Float32x4. This algorithm is from LLVM. - // - // Split the input number into high and low parts: - // - // uint32_t hi = x >> 16; - // uint32_t lo = x & 0xffff; - // - // Insert these parts as the low mantissa bits in a float32 number with - // the corresponding exponent: - // - // float fhi = (bits-as-float)(hi | 0x53000000); // 0x1.0p39f + hi*2^16 - // float flo = (bits-as-float)(lo | 0x4b000000); // 0x1.0p23f + lo - // - // Subtract the bias from the hi part: - // - // fhi -= (0x1.0p39 + 0x1.0p23) // hi*2^16 - 0x1.0p23 - // - // And finally combine: - // - // result = flo + fhi // lo + hi*2^16. - - // Compute hi = obj >> 16 (lane-wise unsigned shift). - MInstruction* c16 = MConstant::New(alloc, Int32Value(16)); - addTo->add(c16); - MInstruction* hi = MSimdShift::AddLegalized(alloc, addTo, obj, c16, MSimdShift::ursh); - - // Compute lo = obj & 0xffff (lane-wise). - MInstruction* m16 = - MSimdConstant::New(alloc, SimdConstant::SplatX4(0xffff), MIRType::Int32x4); - addTo->add(m16); - MInstruction* lo = MSimdBinaryBitwise::New(alloc, obj, m16, MSimdBinaryBitwise::and_); - addTo->add(lo); - - // Mix in the exponents. - MInstruction* exphi = - MSimdConstant::New(alloc, SimdConstant::SplatX4(0x53000000), MIRType::Int32x4); - addTo->add(exphi); - MInstruction* mhi = MSimdBinaryBitwise::New(alloc, hi, exphi, MSimdBinaryBitwise::or_); - addTo->add(mhi); - MInstruction* explo = - MSimdConstant::New(alloc, SimdConstant::SplatX4(0x4b000000), MIRType::Int32x4); - addTo->add(explo); - MInstruction* mlo = MSimdBinaryBitwise::New(alloc, lo, explo, MSimdBinaryBitwise::or_); - addTo->add(mlo); - - // Bit-cast both to Float32x4. - MInstruction* fhi = MSimdReinterpretCast::New(alloc, mhi, MIRType::Float32x4); - addTo->add(fhi); - MInstruction* flo = MSimdReinterpretCast::New(alloc, mlo, MIRType::Float32x4); - addTo->add(flo); - - // Subtract out the bias: 0x1.0p39f + 0x1.0p23f. - // MSVC doesn't support the hexadecimal float syntax. - const float BiasValue = 549755813888.f + 8388608.f; - MInstruction* bias = - MSimdConstant::New(alloc, SimdConstant::SplatX4(BiasValue), MIRType::Float32x4); - addTo->add(bias); - MInstruction* fhi_debiased = - MSimdBinaryArith::AddLegalized(alloc, addTo, fhi, bias, MSimdBinaryArith::Op_sub); - - // Compute the final result. - return MSimdBinaryArith::AddLegalized(alloc, addTo, fhi_debiased, flo, - MSimdBinaryArith::Op_add); - } - - if (fromType == MIRType::Float32x4 && toType == MIRType::Int32x4) { - // The Float32x4 -> Uint32x4 conversion can throw if the input is out of - // range. This is handled by the LFloat32x4ToUint32x4 expansion. - MInstruction* ins = New(alloc, obj, toType, sign, trapOffset); - addTo->add(ins); - return ins; - } - - MOZ_CRASH("Unhandled SIMD type conversion"); -} - -MInstruction* -MSimdBinaryComp::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left, - MDefinition* right, Operation op, SimdSign sign) -{ - MOZ_ASSERT(left->type() == right->type()); - MIRType opType = left->type(); - MOZ_ASSERT(IsSimdType(opType)); - bool IsEquality = op == equal || op == notEqual; - - // Check if this is an unsupported unsigned compare that needs to be biased. - // If so, put the bias vector in `bias`. - if (sign == SimdSign::Unsigned && !IsEquality) { - MInstruction* bias = nullptr; - - // This is an order comparison of Uint32x4 vectors which are not supported on this target. - // Simply offset |left| and |right| by INT_MIN, then do a signed comparison. - if (!SupportsUint32x4Compares && opType == MIRType::Int32x4) - bias = MSimdConstant::New(alloc, SimdConstant::SplatX4(int32_t(0x80000000)), opType); - else if (!SupportsUint16x8Compares && opType == MIRType::Int16x8) - bias = MSimdConstant::New(alloc, SimdConstant::SplatX8(int16_t(0x8000)), opType); - if (!SupportsUint8x16Compares && opType == MIRType::Int8x16) - bias = MSimdConstant::New(alloc, SimdConstant::SplatX16(int8_t(0x80)), opType); - - if (bias) { - addTo->add(bias); - - // Add the bias. - MInstruction* bleft = - MSimdBinaryArith::AddLegalized(alloc, addTo, left, bias, MSimdBinaryArith::Op_add); - MInstruction* bright = - MSimdBinaryArith::AddLegalized(alloc, addTo, right, bias, MSimdBinaryArith::Op_add); - - // Do the equivalent signed comparison. - MInstruction* result = - MSimdBinaryComp::New(alloc, bleft, bright, op, SimdSign::Signed); - addTo->add(result); - - return result; - } - } - - if (sign == SimdSign::Unsigned && - ((!SupportsUint32x4Compares && opType == MIRType::Int32x4) || - (!SupportsUint16x8Compares && opType == MIRType::Int16x8) || - (!SupportsUint8x16Compares && opType == MIRType::Int8x16))) { - // The sign doesn't matter for equality tests. Flip it to make the - // backend assertions happy. - MOZ_ASSERT(IsEquality); - sign = SimdSign::Signed; - } - - // This is a legal operation already. Just create the instruction requested. - MInstruction* result = MSimdBinaryComp::New(alloc, left, right, op, sign); - addTo->add(result); - return result; -} - -MInstruction* -MSimdBinaryArith::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left, - MDefinition* right, Operation op) -{ - MOZ_ASSERT(left->type() == right->type()); - MIRType opType = left->type(); - MOZ_ASSERT(IsSimdType(opType)); - - // SSE does not have 8x16 multiply instructions. - if (opType == MIRType::Int8x16 && op == Op_mul) { - // Express the multiply in terms of Int16x8 multiplies by handling the - // even and odd lanes separately. - - MInstruction* wideL = MSimdReinterpretCast::New(alloc, left, MIRType::Int16x8); - addTo->add(wideL); - MInstruction* wideR = MSimdReinterpretCast::New(alloc, right, MIRType::Int16x8); - addTo->add(wideR); - - // wideL = yyxx yyxx yyxx yyxx yyxx yyxx yyxx yyxx - // wideR = bbaa bbaa bbaa bbaa bbaa bbaa bbaa bbaa - - // Shift the odd lanes down to the low bits of the 16x8 vectors. - MInstruction* eight = MConstant::New(alloc, Int32Value(8)); - addTo->add(eight); - MInstruction* evenL = wideL; - MInstruction* evenR = wideR; - MInstruction* oddL = - MSimdShift::AddLegalized(alloc, addTo, wideL, eight, MSimdShift::ursh); - MInstruction* oddR = - MSimdShift::AddLegalized(alloc, addTo, wideR, eight, MSimdShift::ursh); - - // evenL = yyxx yyxx yyxx yyxx yyxx yyxx yyxx yyxx - // evenR = bbaa bbaa bbaa bbaa bbaa bbaa bbaa bbaa - // oddL = 00yy 00yy 00yy 00yy 00yy 00yy 00yy 00yy - // oddR = 00bb 00bb 00bb 00bb 00bb 00bb 00bb 00bb - - // Now do two 16x8 multiplications. We can use the low bits of each. - MInstruction* even = MSimdBinaryArith::AddLegalized(alloc, addTo, evenL, evenR, Op_mul); - MInstruction* odd = MSimdBinaryArith::AddLegalized(alloc, addTo, oddL, oddR, Op_mul); - - // even = ~~PP ~~PP ~~PP ~~PP ~~PP ~~PP ~~PP ~~PP - // odd = ~~QQ ~~QQ ~~QQ ~~QQ ~~QQ ~~QQ ~~QQ ~~QQ - - MInstruction* mask = - MSimdConstant::New(alloc, SimdConstant::SplatX8(int16_t(0x00ff)), MIRType::Int16x8); - addTo->add(mask); - even = MSimdBinaryBitwise::New(alloc, even, mask, MSimdBinaryBitwise::and_); - addTo->add(even); - odd = MSimdShift::AddLegalized(alloc, addTo, odd, eight, MSimdShift::lsh); - - // even = 00PP 00PP 00PP 00PP 00PP 00PP 00PP 00PP - // odd = QQ00 QQ00 QQ00 QQ00 QQ00 QQ00 QQ00 QQ00 - - // Combine: - MInstruction* result = MSimdBinaryBitwise::New(alloc, even, odd, MSimdBinaryBitwise::or_); - addTo->add(result); - result = MSimdReinterpretCast::New(alloc, result, opType); - addTo->add(result); - return result; - } - - // This is a legal operation already. Just create the instruction requested. - MInstruction* result = MSimdBinaryArith::New(alloc, left, right, op); - addTo->add(result); - return result; -} - -MInstruction* -MSimdShift::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left, - MDefinition* right, Operation op) -{ - MIRType opType = left->type(); - MOZ_ASSERT(IsIntegerSimdType(opType)); - - // SSE does not provide 8x16 shift instructions. - if (opType == MIRType::Int8x16) { - // Express the shift in terms of Int16x8 shifts by splitting into even - // and odd lanes, place 8-bit lanes into the high bits of Int16x8 - // vectors `even` and `odd`. Shift, mask, combine. - // - // wide = Int16x8.fromInt8x16Bits(left); - // shiftBy = right & 7 - // mask = Int16x8.splat(0xff00); - // - MInstruction* wide = MSimdReinterpretCast::New(alloc, left, MIRType::Int16x8); - addTo->add(wide); - - // wide = yyxx yyxx yyxx yyxx yyxx yyxx yyxx yyxx - - MInstruction* shiftMask = MConstant::New(alloc, Int32Value(7)); - addTo->add(shiftMask); - MBinaryBitwiseInstruction* shiftBy = MBitAnd::New(alloc, right, shiftMask); - shiftBy->setInt32Specialization(); - addTo->add(shiftBy); - - // Move the even 8x16 lanes into the high bits of the 16x8 lanes. - MInstruction* eight = MConstant::New(alloc, Int32Value(8)); - addTo->add(eight); - MInstruction* even = MSimdShift::AddLegalized(alloc, addTo, wide, eight, lsh); - - // Leave the odd lanes in place. - MInstruction* odd = wide; - - // even = xx00 xx00 xx00 xx00 xx00 xx00 xx00 xx00 - // odd = yyxx yyxx yyxx yyxx yyxx yyxx yyxx yyxx - - MInstruction* mask = - MSimdConstant::New(alloc, SimdConstant::SplatX8(int16_t(0xff00)), MIRType::Int16x8); - addTo->add(mask); - - // Left-shift: Clear the low bits in `odd` before shifting. - if (op == lsh) { - odd = MSimdBinaryBitwise::New(alloc, odd, mask, MSimdBinaryBitwise::and_); - addTo->add(odd); - // odd = yy00 yy00 yy00 yy00 yy00 yy00 yy00 yy00 - } - - // Do the real shift twice: once for the even lanes, once for the odd - // lanes. This is a recursive call, but with a different type. - even = MSimdShift::AddLegalized(alloc, addTo, even, shiftBy, op); - odd = MSimdShift::AddLegalized(alloc, addTo, odd, shiftBy, op); - - // even = XX~~ XX~~ XX~~ XX~~ XX~~ XX~~ XX~~ XX~~ - // odd = YY~~ YY~~ YY~~ YY~~ YY~~ YY~~ YY~~ YY~~ - - // Right-shift: Clear the low bits in `odd` after shifting. - if (op != lsh) { - odd = MSimdBinaryBitwise::New(alloc, odd, mask, MSimdBinaryBitwise::and_); - addTo->add(odd); - // odd = YY00 YY00 YY00 YY00 YY00 YY00 YY00 YY00 - } - - // Move the even lanes back to their original place. - even = MSimdShift::AddLegalized(alloc, addTo, even, eight, ursh); - - // Now, `odd` contains the odd lanes properly shifted, and `even` - // contains the even lanes properly shifted: - // - // even = 00XX 00XX 00XX 00XX 00XX 00XX 00XX 00XX - // odd = YY00 YY00 YY00 YY00 YY00 YY00 YY00 YY00 - // - // Combine: - MInstruction* result = MSimdBinaryBitwise::New(alloc, even, odd, MSimdBinaryBitwise::or_); - addTo->add(result); - result = MSimdReinterpretCast::New(alloc, result, opType); - addTo->add(result); - return result; - } - - // This is a legal operation already. Just create the instruction requested. - MInstruction* result = MSimdShift::New(alloc, left, right, op); - addTo->add(result); - return result; -} - -template <typename T> -static void -PrintOpcodeOperation(T* mir, GenericPrinter& out) -{ - mir->MDefinition::printOpcode(out); - out.printf(" (%s)", T::OperationName(mir->operation())); -} - -void -MSimdBinaryArith::printOpcode(GenericPrinter& out) const -{ - PrintOpcodeOperation(this, out); -} -void -MSimdBinarySaturating::printOpcode(GenericPrinter& out) const -{ - PrintOpcodeOperation(this, out); -} -void -MSimdBinaryBitwise::printOpcode(GenericPrinter& out) const -{ - PrintOpcodeOperation(this, out); -} -void -MSimdUnaryArith::printOpcode(GenericPrinter& out) const -{ - PrintOpcodeOperation(this, out); -} -void -MSimdBinaryComp::printOpcode(GenericPrinter& out) const -{ - PrintOpcodeOperation(this, out); -} -void -MSimdShift::printOpcode(GenericPrinter& out) const -{ - PrintOpcodeOperation(this, out); -} - -void -MSimdInsertElement::printOpcode(GenericPrinter& out) const -{ - MDefinition::printOpcode(out); - out.printf(" (lane %u)", lane()); -} - -void -MSimdBox::printOpcode(GenericPrinter& out) const -{ - MDefinition::printOpcode(out); - out.printf(" (%s%s)", SimdTypeToString(simdType()), - initialHeap() == gc::TenuredHeap ? ", tenured" : ""); -} - -void -MSimdUnbox::printOpcode(GenericPrinter& out) const -{ - MDefinition::printOpcode(out); - out.printf(" (%s)", SimdTypeToString(simdType())); -} - void MControlInstruction::printOpcode(GenericPrinter& out) const { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 72c5214845..532f404b51 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -15,7 +15,6 @@ #include "mozilla/Attributes.h" #include "mozilla/MacroForEach.h" -#include "builtin/SIMD.h" #include "jit/AtomicOp.h" #include "jit/BaselineIC.h" #include "jit/FixedList.h" @@ -80,63 +79,6 @@ MIRType MIRTypeFromValue(const js::Value& vp) return MIRTypeFromValueType(vp.extractNonDoubleType()); } -// If simdType is one of the SIMD types suported by Ion, set mirType to the -// corresponding MIRType, and return true. -// -// If simdType is not suported by Ion, return false. -static inline MOZ_MUST_USE -bool MaybeSimdTypeToMIRType(SimdType type, MIRType* mirType) -{ - switch (type) { - case SimdType::Uint32x4: - case SimdType::Int32x4: *mirType = MIRType::Int32x4; return true; - case SimdType::Uint16x8: - case SimdType::Int16x8: *mirType = MIRType::Int16x8; return true; - case SimdType::Uint8x16: - case SimdType::Int8x16: *mirType = MIRType::Int8x16; return true; - case SimdType::Float32x4: *mirType = MIRType::Float32x4; return true; - case SimdType::Bool32x4: *mirType = MIRType::Bool32x4; return true; - case SimdType::Bool16x8: *mirType = MIRType::Bool16x8; return true; - case SimdType::Bool8x16: *mirType = MIRType::Bool8x16; return true; - default: return false; - } -} - -// Convert a SimdType to the corresponding MIRType, or crash. -// -// Note that this is not an injective mapping: SimdType has signed and unsigned -// integer types that map to the same MIRType. -static inline -MIRType SimdTypeToMIRType(SimdType type) -{ - MIRType ret = MIRType::None; - JS_ALWAYS_TRUE(MaybeSimdTypeToMIRType(type, &ret)); - return ret; -} - -static inline -SimdType MIRTypeToSimdType(MIRType type) -{ - switch (type) { - case MIRType::Int32x4: return SimdType::Int32x4; - case MIRType::Int16x8: return SimdType::Int16x8; - case MIRType::Int8x16: return SimdType::Int8x16; - case MIRType::Float32x4: return SimdType::Float32x4; - case MIRType::Bool32x4: return SimdType::Bool32x4; - case MIRType::Bool16x8: return SimdType::Bool16x8; - case MIRType::Bool8x16: return SimdType::Bool8x16; - default: break; - } - MOZ_CRASH("unhandled MIRType"); -} - -// Get the boolean MIRType with the same shape as type. -static inline -MIRType MIRTypeToBooleanSimdType(MIRType type) -{ - return SimdTypeToMIRType(GetBooleanSimdType(MIRTypeToSimdType(type))); -} - #define MIR_FLAG_LIST(_) \ _(InWorklist) \ _(EmittedAtUses) \ @@ -1708,1036 +1650,6 @@ class MConstant : public MNullaryInstruction bool appendRoots(MRootList& roots) const override; }; -// Generic constructor of SIMD valuesX4. -class MSimdValueX4 - : public MQuaternaryInstruction, - public Mix4Policy<SimdScalarPolicy<0>, SimdScalarPolicy<1>, - SimdScalarPolicy<2>, SimdScalarPolicy<3> >::Data -{ - protected: - MSimdValueX4(MIRType type, MDefinition* x, MDefinition* y, MDefinition* z, MDefinition* w) - : MQuaternaryInstruction(x, y, z, w) - { - MOZ_ASSERT(IsSimdType(type)); - MOZ_ASSERT(SimdTypeToLength(type) == 4); - - setMovable(); - setResultType(type); - } - - public: - INSTRUCTION_HEADER(SimdValueX4) - TRIVIAL_NEW_WRAPPERS - - bool canConsumeFloat32(MUse* use) const override { - return SimdTypeToLaneType(type()) == MIRType::Float32; - } - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - - bool congruentTo(const MDefinition* ins) const override { - return congruentIfOperandsEqual(ins); - } - - MDefinition* foldsTo(TempAllocator& alloc) override; - - ALLOW_CLONE(MSimdValueX4) -}; - -// Generic constructor of SIMD values with identical lanes. -class MSimdSplat - : public MUnaryInstruction, - public SimdScalarPolicy<0>::Data -{ - protected: - MSimdSplat(MDefinition* v, MIRType type) - : MUnaryInstruction(v) - { - MOZ_ASSERT(IsSimdType(type)); - setMovable(); - setResultType(type); - } - - public: - INSTRUCTION_HEADER(SimdSplat) - TRIVIAL_NEW_WRAPPERS - - bool canConsumeFloat32(MUse* use) const override { - return SimdTypeToLaneType(type()) == MIRType::Float32; - } - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - - bool congruentTo(const MDefinition* ins) const override { - return congruentIfOperandsEqual(ins); - } - - MDefinition* foldsTo(TempAllocator& alloc) override; - - ALLOW_CLONE(MSimdSplat) -}; - -// A constant SIMD value. -class MSimdConstant - : public MNullaryInstruction -{ - SimdConstant value_; - - protected: - MSimdConstant(const SimdConstant& v, MIRType type) : value_(v) { - MOZ_ASSERT(IsSimdType(type)); - setMovable(); - setResultType(type); - } - - public: - INSTRUCTION_HEADER(SimdConstant) - TRIVIAL_NEW_WRAPPERS - - bool congruentTo(const MDefinition* ins) const override { - if (!ins->isSimdConstant()) - return false; - // Bool32x4 and Int32x4 share the same underlying SimdConstant representation. - if (type() != ins->type()) - return false; - return value() == ins->toSimdConstant()->value(); - } - - const SimdConstant& value() const { - return value_; - } - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - - ALLOW_CLONE(MSimdConstant) -}; - -// Converts all lanes of a given vector into the type of another vector -class MSimdConvert - : public MUnaryInstruction, - public SimdPolicy<0>::Data -{ - // When either fromType or toType is an integer vector, should it be treated - // as signed or unsigned. Note that we don't support int-int conversions - - // use MSimdReinterpretCast for that. - SimdSign sign_; - wasm::TrapOffset trapOffset_; - - MSimdConvert(MDefinition* obj, MIRType toType, SimdSign sign, wasm::TrapOffset trapOffset) - : MUnaryInstruction(obj), sign_(sign), trapOffset_(trapOffset) - { - MIRType fromType = obj->type(); - MOZ_ASSERT(IsSimdType(fromType)); - MOZ_ASSERT(IsSimdType(toType)); - // All conversions are int <-> float, so signedness is required. - MOZ_ASSERT(sign != SimdSign::NotApplicable); - - setResultType(toType); - specialization_ = fromType; // expects fromType as input - - setMovable(); - if (IsFloatingPointSimdType(fromType) && IsIntegerSimdType(toType)) { - // Does the extra range check => do not remove - setGuard(); - } - } - - static MSimdConvert* New(TempAllocator& alloc, MDefinition* obj, MIRType toType, SimdSign sign, - wasm::TrapOffset trapOffset) - { - return new (alloc) MSimdConvert(obj, toType, sign, trapOffset); - } - - public: - INSTRUCTION_HEADER(SimdConvert) - - // Create a MSimdConvert instruction and add it to the basic block. - // Possibly create and add an equivalent sequence of instructions instead if - // the current target doesn't support the requested conversion directly. - // Return the inserted MInstruction that computes the converted value. - static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* obj, - MIRType toType, SimdSign sign, - wasm::TrapOffset trapOffset = wasm::TrapOffset()); - - SimdSign signedness() const { - return sign_; - } - wasm::TrapOffset trapOffset() const { - return trapOffset_; - } - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - bool congruentTo(const MDefinition* ins) const override { - if (!congruentIfOperandsEqual(ins)) - return false; - const MSimdConvert* other = ins->toSimdConvert(); - return sign_ == other->sign_; - } - ALLOW_CLONE(MSimdConvert) -}; - -// Casts bits of a vector input to another SIMD type (doesn't generate code). -class MSimdReinterpretCast - : public MUnaryInstruction, - public SimdPolicy<0>::Data -{ - MSimdReinterpretCast(MDefinition* obj, MIRType toType) - : MUnaryInstruction(obj) - { - MIRType fromType = obj->type(); - MOZ_ASSERT(IsSimdType(fromType)); - MOZ_ASSERT(IsSimdType(toType)); - setMovable(); - setResultType(toType); - specialization_ = fromType; // expects fromType as input - } - - public: - INSTRUCTION_HEADER(SimdReinterpretCast) - TRIVIAL_NEW_WRAPPERS - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - bool congruentTo(const MDefinition* ins) const override { - return congruentIfOperandsEqual(ins); - } - ALLOW_CLONE(MSimdReinterpretCast) -}; - -// Extracts a lane element from a given vector type, given by its lane symbol. -// -// For integer SIMD types, a SimdSign must be provided so the lane value can be -// converted to a scalar correctly. -class MSimdExtractElement - : public MUnaryInstruction, - public SimdPolicy<0>::Data -{ - protected: - unsigned lane_; - SimdSign sign_; - - MSimdExtractElement(MDefinition* obj, MIRType laneType, unsigned lane, SimdSign sign) - : MUnaryInstruction(obj), lane_(lane), sign_(sign) - { - MIRType vecType = obj->type(); - MOZ_ASSERT(IsSimdType(vecType)); - MOZ_ASSERT(lane < SimdTypeToLength(vecType)); - MOZ_ASSERT(!IsSimdType(laneType)); - MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(vecType), - "Signedness must be specified for integer SIMD extractLanes"); - // The resulting type should match the lane type. - // Allow extracting boolean lanes directly into an Int32 (for wasm). - // Allow extracting Uint32 lanes into a double. - // - // We also allow extracting Uint32 lanes into a MIRType::Int32. This is - // equivalent to extracting the Uint32 lane to a double and then - // applying MTruncateToInt32, but it bypasses the conversion to/from - // double. - MOZ_ASSERT(SimdTypeToLaneType(vecType) == laneType || - (IsBooleanSimdType(vecType) && laneType == MIRType::Int32) || - (vecType == MIRType::Int32x4 && laneType == MIRType::Double && - sign == SimdSign::Unsigned)); - - setMovable(); - specialization_ = vecType; - setResultType(laneType); - } - - public: - INSTRUCTION_HEADER(SimdExtractElement) - TRIVIAL_NEW_WRAPPERS - - unsigned lane() const { - return lane_; - } - - SimdSign signedness() const { - return sign_; - } - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - bool congruentTo(const MDefinition* ins) const override { - if (!ins->isSimdExtractElement()) - return false; - const MSimdExtractElement* other = ins->toSimdExtractElement(); - if (other->lane_ != lane_ || other->sign_ != sign_) - return false; - return congruentIfOperandsEqual(other); - } - ALLOW_CLONE(MSimdExtractElement) -}; - -// Replaces the datum in the given lane by a scalar value of the same type. -class MSimdInsertElement - : public MBinaryInstruction, - public MixPolicy< SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >::Data -{ - private: - unsigned lane_; - - MSimdInsertElement(MDefinition* vec, MDefinition* val, unsigned lane) - : MBinaryInstruction(vec, val), lane_(lane) - { - MIRType type = vec->type(); - MOZ_ASSERT(IsSimdType(type)); - MOZ_ASSERT(lane < SimdTypeToLength(type)); - setMovable(); - setResultType(type); - } - - public: - INSTRUCTION_HEADER(SimdInsertElement) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, vector), (1, value)) - - unsigned lane() const { - return lane_; - } - - bool canConsumeFloat32(MUse* use) const override { - return use == getUseFor(1) && SimdTypeToLaneType(type()) == MIRType::Float32; - } - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - - bool congruentTo(const MDefinition* ins) const override { - return binaryCongruentTo(ins) && lane_ == ins->toSimdInsertElement()->lane(); - } - - void printOpcode(GenericPrinter& out) const override; - - ALLOW_CLONE(MSimdInsertElement) -}; - -// Returns true if all lanes are true. -class MSimdAllTrue - : public MUnaryInstruction, - public SimdPolicy<0>::Data -{ - protected: - explicit MSimdAllTrue(MDefinition* obj, MIRType result) - : MUnaryInstruction(obj) - { - MIRType simdType = obj->type(); - MOZ_ASSERT(IsBooleanSimdType(simdType)); - MOZ_ASSERT(result == MIRType::Boolean || result == MIRType::Int32); - setResultType(result); - specialization_ = simdType; - setMovable(); - } - - public: - INSTRUCTION_HEADER(SimdAllTrue) - TRIVIAL_NEW_WRAPPERS - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - bool congruentTo(const MDefinition* ins) const override { - return congruentIfOperandsEqual(ins); - } - ALLOW_CLONE(MSimdAllTrue) -}; - -// Returns true if any lane is true. -class MSimdAnyTrue - : public MUnaryInstruction, - public SimdPolicy<0>::Data -{ - protected: - explicit MSimdAnyTrue(MDefinition* obj, MIRType result) - : MUnaryInstruction(obj) - { - MIRType simdType = obj->type(); - MOZ_ASSERT(IsBooleanSimdType(simdType)); - MOZ_ASSERT(result == MIRType::Boolean || result == MIRType::Int32); - setResultType(result); - specialization_ = simdType; - setMovable(); - } - - public: - INSTRUCTION_HEADER(SimdAnyTrue) - TRIVIAL_NEW_WRAPPERS - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - bool congruentTo(const MDefinition* ins) const override { - return congruentIfOperandsEqual(ins); - } - - ALLOW_CLONE(MSimdAnyTrue) -}; - -// Base for the MSimdSwizzle and MSimdShuffle classes. -class MSimdShuffleBase -{ - protected: - // As of now, there are at most 16 lanes. For each lane, we need to know - // which input we choose and which of the lanes we choose. - mozilla::Array<uint8_t, 16> lane_; - uint32_t arity_; - - MSimdShuffleBase(const uint8_t lanes[], MIRType type) - { - arity_ = SimdTypeToLength(type); - for (unsigned i = 0; i < arity_; i++) - lane_[i] = lanes[i]; - } - - bool sameLanes(const MSimdShuffleBase* other) const { - return arity_ == other->arity_ && - memcmp(&lane_[0], &other->lane_[0], arity_) == 0; - } - - public: - unsigned numLanes() const { - return arity_; - } - - unsigned lane(unsigned i) const { - MOZ_ASSERT(i < arity_); - return lane_[i]; - } - - bool lanesMatch(uint32_t x, uint32_t y, uint32_t z, uint32_t w) const { - return arity_ == 4 && lane(0) == x && lane(1) == y && lane(2) == z && - lane(3) == w; - } -}; - -// Applies a swizzle operation to the input, putting the input lanes as -// indicated in the output register's lanes. This implements the SIMD.js -// "swizzle" function, that takes one vector and an array of lane indexes. -class MSimdSwizzle - : public MUnaryInstruction, - public MSimdShuffleBase, - public NoTypePolicy::Data -{ - protected: - MSimdSwizzle(MDefinition* obj, const uint8_t lanes[]) - : MUnaryInstruction(obj), MSimdShuffleBase(lanes, obj->type()) - { - for (unsigned i = 0; i < arity_; i++) - MOZ_ASSERT(lane(i) < arity_); - setResultType(obj->type()); - setMovable(); - } - - public: - INSTRUCTION_HEADER(SimdSwizzle) - TRIVIAL_NEW_WRAPPERS - - bool congruentTo(const MDefinition* ins) const override { - if (!ins->isSimdSwizzle()) - return false; - const MSimdSwizzle* other = ins->toSimdSwizzle(); - return sameLanes(other) && congruentIfOperandsEqual(other); - } - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - - MDefinition* foldsTo(TempAllocator& alloc) override; - - ALLOW_CLONE(MSimdSwizzle) -}; - -// A "general shuffle" is a swizzle or a shuffle with non-constant lane -// indices. This is the one that Ion inlines and it can be folded into a -// MSimdSwizzle/MSimdShuffle if lane indices are constant. Performance of -// general swizzle/shuffle does not really matter, as we expect to get -// constant indices most of the time. -class MSimdGeneralShuffle : - public MVariadicInstruction, - public SimdShufflePolicy::Data -{ - unsigned numVectors_; - unsigned numLanes_; - - protected: - MSimdGeneralShuffle(unsigned numVectors, unsigned numLanes, MIRType type) - : numVectors_(numVectors), numLanes_(numLanes) - { - MOZ_ASSERT(IsSimdType(type)); - MOZ_ASSERT(SimdTypeToLength(type) == numLanes_); - - setResultType(type); - specialization_ = type; - setGuard(); // throws if lane index is out of bounds - setMovable(); - } - - public: - INSTRUCTION_HEADER(SimdGeneralShuffle); - TRIVIAL_NEW_WRAPPERS - - MOZ_MUST_USE bool init(TempAllocator& alloc) { - return MVariadicInstruction::init(alloc, numVectors_ + numLanes_); - } - void setVector(unsigned i, MDefinition* vec) { - MOZ_ASSERT(i < numVectors_); - initOperand(i, vec); - } - void setLane(unsigned i, MDefinition* laneIndex) { - MOZ_ASSERT(i < numLanes_); - initOperand(numVectors_ + i, laneIndex); - } - - unsigned numVectors() const { - return numVectors_; - } - unsigned numLanes() const { - return numLanes_; - } - MDefinition* vector(unsigned i) const { - MOZ_ASSERT(i < numVectors_); - return getOperand(i); - } - MDefinition* lane(unsigned i) const { - MOZ_ASSERT(i < numLanes_); - return getOperand(numVectors_ + i); - } - - bool congruentTo(const MDefinition* ins) const override { - if (!ins->isSimdGeneralShuffle()) - return false; - const MSimdGeneralShuffle* other = ins->toSimdGeneralShuffle(); - return numVectors_ == other->numVectors() && - numLanes_ == other->numLanes() && - congruentIfOperandsEqual(other); - } - - MDefinition* foldsTo(TempAllocator& alloc) override; - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } -}; - -// Applies a shuffle operation to the inputs. The lane indexes select a source -// lane from the concatenation of the two input vectors. -class MSimdShuffle - : public MBinaryInstruction, - public MSimdShuffleBase, - public NoTypePolicy::Data -{ - MSimdShuffle(MDefinition* lhs, MDefinition* rhs, const uint8_t lanes[]) - : MBinaryInstruction(lhs, rhs), MSimdShuffleBase(lanes, lhs->type()) - { - MOZ_ASSERT(IsSimdType(lhs->type())); - MOZ_ASSERT(IsSimdType(rhs->type())); - MOZ_ASSERT(lhs->type() == rhs->type()); - for (unsigned i = 0; i < arity_; i++) - MOZ_ASSERT(lane(i) < 2 * arity_); - setResultType(lhs->type()); - setMovable(); - } - - public: - INSTRUCTION_HEADER(SimdShuffle) - - static MInstruction* New(TempAllocator& alloc, MDefinition* lhs, MDefinition* rhs, - const uint8_t lanes[]) - { - unsigned arity = SimdTypeToLength(lhs->type()); - - // Swap operands so that new lanes come from LHS in majority. - // In the balanced case, swap operands if needs be, in order to be able - // to do only one vshufps on x86. - unsigned lanesFromLHS = 0; - for (unsigned i = 0; i < arity; i++) { - if (lanes[i] < arity) - lanesFromLHS++; - } - - if (lanesFromLHS < arity / 2 || - (arity == 4 && lanesFromLHS == 2 && lanes[0] >= 4 && lanes[1] >= 4)) { - mozilla::Array<uint8_t, 16> newLanes; - for (unsigned i = 0; i < arity; i++) - newLanes[i] = (lanes[i] + arity) % (2 * arity); - return New(alloc, rhs, lhs, &newLanes[0]); - } - - // If all lanes come from the same vector, just use swizzle instead. - if (lanesFromLHS == arity) - return MSimdSwizzle::New(alloc, lhs, lanes); - - return new(alloc) MSimdShuffle(lhs, rhs, lanes); - } - - bool congruentTo(const MDefinition* ins) const override { - if (!ins->isSimdShuffle()) - return false; - const MSimdShuffle* other = ins->toSimdShuffle(); - return sameLanes(other) && binaryCongruentTo(other); - } - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - - ALLOW_CLONE(MSimdShuffle) -}; - -class MSimdUnaryArith - : public MUnaryInstruction, - public SimdSameAsReturnedTypePolicy<0>::Data -{ - public: - enum Operation { -#define OP_LIST_(OP) OP, - FOREACH_FLOAT_SIMD_UNOP(OP_LIST_) - neg, - not_ -#undef OP_LIST_ - }; - - static const char* OperationName(Operation op) { - switch (op) { - case abs: return "abs"; - case neg: return "neg"; - case not_: return "not"; - case reciprocalApproximation: return "reciprocalApproximation"; - case reciprocalSqrtApproximation: return "reciprocalSqrtApproximation"; - case sqrt: return "sqrt"; - } - MOZ_CRASH("unexpected operation"); - } - - private: - Operation operation_; - - MSimdUnaryArith(MDefinition* def, Operation op) - : MUnaryInstruction(def), operation_(op) - { - MIRType type = def->type(); - MOZ_ASSERT(IsSimdType(type)); - MOZ_ASSERT_IF(IsIntegerSimdType(type), op == neg || op == not_); - setResultType(type); - setMovable(); - } - - public: - INSTRUCTION_HEADER(SimdUnaryArith) - TRIVIAL_NEW_WRAPPERS - - Operation operation() const { return operation_; } - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - - bool congruentTo(const MDefinition* ins) const override { - return congruentIfOperandsEqual(ins) && ins->toSimdUnaryArith()->operation() == operation(); - } - - void printOpcode(GenericPrinter& out) const override; - - ALLOW_CLONE(MSimdUnaryArith); -}; - -// Compares each value of a SIMD vector to each corresponding lane's value of -// another SIMD vector, and returns a boolean vector containing the results of -// the comparison: all bits are set to 1 if the comparison is true, 0 otherwise. -// When comparing integer vectors, a SimdSign must be provided to request signed -// or unsigned comparison. -class MSimdBinaryComp - : public MBinaryInstruction, - public SimdAllPolicy::Data -{ - public: - enum Operation { -#define NAME_(x) x, - FOREACH_COMP_SIMD_OP(NAME_) -#undef NAME_ - }; - - static const char* OperationName(Operation op) { - switch (op) { -#define NAME_(x) case x: return #x; - FOREACH_COMP_SIMD_OP(NAME_) -#undef NAME_ - } - MOZ_CRASH("unexpected operation"); - } - - private: - Operation operation_; - SimdSign sign_; - - MSimdBinaryComp(MDefinition* left, MDefinition* right, Operation op, SimdSign sign) - : MBinaryInstruction(left, right), operation_(op), sign_(sign) - { - MOZ_ASSERT(left->type() == right->type()); - MIRType opType = left->type(); - MOZ_ASSERT(IsSimdType(opType)); - MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(opType), - "Signedness must be specified for integer SIMD compares"); - setResultType(MIRTypeToBooleanSimdType(opType)); - specialization_ = opType; - setMovable(); - if (op == equal || op == notEqual) - setCommutative(); - } - - static MSimdBinaryComp* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, - Operation op, SimdSign sign) - { - return new (alloc) MSimdBinaryComp(left, right, op, sign); - } - - public: - INSTRUCTION_HEADER(SimdBinaryComp) - - // Create a MSimdBinaryComp or an equivalent sequence of instructions - // supported by the current target. - // Add all instructions to the basic block |addTo|. - static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left, - MDefinition* right, Operation op, SimdSign sign); - - AliasSet getAliasSet() const override - { - return AliasSet::None(); - } - - Operation operation() const { return operation_; } - SimdSign signedness() const { return sign_; } - MIRType specialization() const { return specialization_; } - - // Swap the operands and reverse the comparison predicate. - void reverse() { - switch (operation()) { - case greaterThan: operation_ = lessThan; break; - case greaterThanOrEqual: operation_ = lessThanOrEqual; break; - case lessThan: operation_ = greaterThan; break; - case lessThanOrEqual: operation_ = greaterThanOrEqual; break; - case equal: - case notEqual: - break; - default: MOZ_CRASH("Unexpected compare operation"); - } - swapOperands(); - } - - bool congruentTo(const MDefinition* ins) const override { - if (!binaryCongruentTo(ins)) - return false; - const MSimdBinaryComp* other = ins->toSimdBinaryComp(); - return specialization_ == other->specialization() && - operation_ == other->operation() && - sign_ == other->signedness(); - } - - void printOpcode(GenericPrinter& out) const override; - - ALLOW_CLONE(MSimdBinaryComp) -}; - -class MSimdBinaryArith - : public MBinaryInstruction, - public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data -{ - public: - enum Operation { -#define OP_LIST_(OP) Op_##OP, - FOREACH_NUMERIC_SIMD_BINOP(OP_LIST_) - FOREACH_FLOAT_SIMD_BINOP(OP_LIST_) -#undef OP_LIST_ - }; - - static const char* OperationName(Operation op) { - switch (op) { -#define OP_CASE_LIST_(OP) case Op_##OP: return #OP; - FOREACH_NUMERIC_SIMD_BINOP(OP_CASE_LIST_) - FOREACH_FLOAT_SIMD_BINOP(OP_CASE_LIST_) -#undef OP_CASE_LIST_ - } - MOZ_CRASH("unexpected operation"); - } - - private: - Operation operation_; - - MSimdBinaryArith(MDefinition* left, MDefinition* right, Operation op) - : MBinaryInstruction(left, right), operation_(op) - { - MOZ_ASSERT(left->type() == right->type()); - MIRType type = left->type(); - MOZ_ASSERT(IsSimdType(type)); - MOZ_ASSERT_IF(IsIntegerSimdType(type), op == Op_add || op == Op_sub || op == Op_mul); - setResultType(type); - setMovable(); - if (op == Op_add || op == Op_mul || op == Op_min || op == Op_max) - setCommutative(); - } - - static MSimdBinaryArith* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, - Operation op) - { - return new (alloc) MSimdBinaryArith(left, right, op); - } - - public: - INSTRUCTION_HEADER(SimdBinaryArith) - - // Create an MSimdBinaryArith instruction and add it to the basic block. Possibly - // create and add an equivalent sequence of instructions instead if the - // current target doesn't support the requested shift operation directly. - static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left, - MDefinition* right, Operation op); - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - - Operation operation() const { return operation_; } - - bool congruentTo(const MDefinition* ins) const override { - if (!binaryCongruentTo(ins)) - return false; - return operation_ == ins->toSimdBinaryArith()->operation(); - } - - void printOpcode(GenericPrinter& out) const override; - - ALLOW_CLONE(MSimdBinaryArith) -}; - -class MSimdBinarySaturating - : public MBinaryInstruction, - public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1>>::Data -{ - public: - enum Operation - { - add, - sub, - }; - - static const char* OperationName(Operation op) - { - switch (op) { - case add: - return "add"; - case sub: - return "sub"; - } - MOZ_CRASH("unexpected operation"); - } - - private: - Operation operation_; - SimdSign sign_; - - MSimdBinarySaturating(MDefinition* left, MDefinition* right, Operation op, SimdSign sign) - : MBinaryInstruction(left, right) - , operation_(op) - , sign_(sign) - { - MOZ_ASSERT(left->type() == right->type()); - MIRType type = left->type(); - MOZ_ASSERT(type == MIRType::Int8x16 || type == MIRType::Int16x8); - setResultType(type); - setMovable(); - if (op == add) - setCommutative(); - } - - public: - INSTRUCTION_HEADER(SimdBinarySaturating) - TRIVIAL_NEW_WRAPPERS - - AliasSet getAliasSet() const override { return AliasSet::None(); } - - Operation operation() const { return operation_; } - SimdSign signedness() const { return sign_; } - - bool congruentTo(const MDefinition* ins) const override - { - if (!binaryCongruentTo(ins)) - return false; - return operation_ == ins->toSimdBinarySaturating()->operation() && - sign_ == ins->toSimdBinarySaturating()->signedness(); - } - - void printOpcode(GenericPrinter& out) const override; - - ALLOW_CLONE(MSimdBinarySaturating) -}; - -class MSimdBinaryBitwise - : public MBinaryInstruction, - public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data -{ - public: - enum Operation { - and_, - or_, - xor_ - }; - - static const char* OperationName(Operation op) { - switch (op) { - case and_: return "and"; - case or_: return "or"; - case xor_: return "xor"; - } - MOZ_CRASH("unexpected operation"); - } - - private: - Operation operation_; - - MSimdBinaryBitwise(MDefinition* left, MDefinition* right, Operation op) - : MBinaryInstruction(left, right), operation_(op) - { - MOZ_ASSERT(left->type() == right->type()); - MIRType type = left->type(); - MOZ_ASSERT(IsSimdType(type)); - setResultType(type); - setMovable(); - setCommutative(); - } - - public: - INSTRUCTION_HEADER(SimdBinaryBitwise) - TRIVIAL_NEW_WRAPPERS - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - - Operation operation() const { return operation_; } - - bool congruentTo(const MDefinition* ins) const override { - if (!binaryCongruentTo(ins)) - return false; - return operation_ == ins->toSimdBinaryBitwise()->operation(); - } - - void printOpcode(GenericPrinter& out) const override; - - ALLOW_CLONE(MSimdBinaryBitwise) -}; - -class MSimdShift - : public MBinaryInstruction, - public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >::Data -{ - public: - enum Operation { - lsh, - rsh, - ursh - }; - - private: - Operation operation_; - - MSimdShift(MDefinition* left, MDefinition* right, Operation op) - : MBinaryInstruction(left, right), operation_(op) - { - MIRType type = left->type(); - MOZ_ASSERT(IsIntegerSimdType(type)); - setResultType(type); - setMovable(); - } - - static MSimdShift* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, - Operation op) - { - return new (alloc) MSimdShift(left, right, op); - } - - public: - INSTRUCTION_HEADER(SimdShift) - - // Create an MSimdShift instruction and add it to the basic block. Possibly - // create and add an equivalent sequence of instructions instead if the - // current target doesn't support the requested shift operation directly. - // Return the inserted MInstruction that computes the shifted value. - static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left, - MDefinition* right, Operation op); - - // Get the relevant right shift operation given the signedness of a type. - static Operation rshForSign(SimdSign sign) { - return sign == SimdSign::Unsigned ? ursh : rsh; - } - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - - Operation operation() const { return operation_; } - - static const char* OperationName(Operation op) { - switch (op) { - case lsh: return "lsh"; - case rsh: return "rsh-arithmetic"; - case ursh: return "rsh-logical"; - } - MOZ_CRASH("unexpected operation"); - } - - void printOpcode(GenericPrinter& out) const override; - - bool congruentTo(const MDefinition* ins) const override { - if (!binaryCongruentTo(ins)) - return false; - return operation_ == ins->toSimdShift()->operation(); - } - - ALLOW_CLONE(MSimdShift) -}; - -class MSimdSelect - : public MTernaryInstruction, - public SimdSelectPolicy::Data -{ - MSimdSelect(MDefinition* mask, MDefinition* lhs, MDefinition* rhs) - : MTernaryInstruction(mask, lhs, rhs) - { - MOZ_ASSERT(IsBooleanSimdType(mask->type())); - MOZ_ASSERT(lhs->type() == lhs->type()); - MIRType type = lhs->type(); - MOZ_ASSERT(IsSimdType(type)); - setResultType(type); - specialization_ = type; - setMovable(); - } - - public: - INSTRUCTION_HEADER(SimdSelect) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, mask)) - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - - bool congruentTo(const MDefinition* ins) const override { - return congruentIfOperandsEqual(ins); - } - - ALLOW_CLONE(MSimdSelect) -}; - // Deep clone a constant JSObject. class MCloneLiteral : public MUnaryInstruction, @@ -3585,117 +2497,6 @@ class MTypedObjectDescr } }; -// Generic way for constructing a SIMD object in IonMonkey, this instruction -// takes as argument a SIMD instruction and returns a new SIMD object which -// corresponds to the MIRType of its operand. -class MSimdBox - : public MUnaryInstruction, - public NoTypePolicy::Data -{ - protected: - CompilerGCPointer<InlineTypedObject*> templateObject_; - SimdType simdType_; - gc::InitialHeap initialHeap_; - - MSimdBox(CompilerConstraintList* constraints, - MDefinition* op, - InlineTypedObject* templateObject, - SimdType simdType, - gc::InitialHeap initialHeap) - : MUnaryInstruction(op), - templateObject_(templateObject), - simdType_(simdType), - initialHeap_(initialHeap) - { - MOZ_ASSERT(IsSimdType(op->type())); - setMovable(); - setResultType(MIRType::Object); - if (constraints) - setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject)); - } - - public: - INSTRUCTION_HEADER(SimdBox) - TRIVIAL_NEW_WRAPPERS - - InlineTypedObject* templateObject() const { - return templateObject_; - } - - SimdType simdType() const { - return simdType_; - } - - gc::InitialHeap initialHeap() const { - return initialHeap_; - } - - bool congruentTo(const MDefinition* ins) const override { - if (!congruentIfOperandsEqual(ins)) - return false; - const MSimdBox* box = ins->toSimdBox(); - if (box->simdType() != simdType()) - return false; - MOZ_ASSERT(box->templateObject() == templateObject()); - if (box->initialHeap() != initialHeap()) - return false; - return true; - } - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - - void printOpcode(GenericPrinter& out) const override; - MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override; - bool canRecoverOnBailout() const override { - return true; - } - - bool appendRoots(MRootList& roots) const override { - return roots.append(templateObject_); - } -}; - -class MSimdUnbox - : public MUnaryInstruction, - public SingleObjectPolicy::Data -{ - protected: - SimdType simdType_; - - MSimdUnbox(MDefinition* op, SimdType simdType) - : MUnaryInstruction(op), - simdType_(simdType) - { - MIRType type = SimdTypeToMIRType(simdType); - MOZ_ASSERT(IsSimdType(type)); - setGuard(); - setMovable(); - setResultType(type); - } - - public: - INSTRUCTION_HEADER(SimdUnbox) - TRIVIAL_NEW_WRAPPERS - ALLOW_CLONE(MSimdUnbox) - - SimdType simdType() const { return simdType_; } - - MDefinition* foldsTo(TempAllocator& alloc) override; - bool congruentTo(const MDefinition* ins) const override { - if (!congruentIfOperandsEqual(ins)) - return false; - return ins->toSimdUnbox()->simdType() == simdType(); - } - - AliasSet getAliasSet() const override { - return AliasSet::None(); - } - - void printOpcode(GenericPrinter& out) const override; -}; - // Creates a new derived type object. At runtime, this is just a call // to `BinaryBlock::createDerived()`. That is, the MIR itself does not // compile to particularly optimized code. However, using a distinct @@ -10041,7 +8842,6 @@ class MLoadUnboxedScalar { Scalar::Type storageType_; Scalar::Type readType_; - unsigned numElems_; // used only for SIMD bool requiresBarrier_; int32_t offsetAdjustment_; bool canonicalizeDoubles_; @@ -10052,7 +8852,6 @@ class MLoadUnboxedScalar : MBinaryInstruction(elements, index), storageType_(storageType), readType_(storageType), - numElems_(1), requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier), offsetAdjustment_(offsetAdjustment), canonicalizeDoubles_(canonicalizeDoubles) @@ -10072,13 +8871,6 @@ class MLoadUnboxedScalar TRIVIAL_NEW_WRAPPERS NAMED_OPERANDS((0, elements), (1, index)) - void setSimdRead(Scalar::Type type, unsigned numElems) { - readType_ = type; - numElems_ = numElems; - } - unsigned numElems() const { - return numElems_; - } Scalar::Type readType() const { return readType_; } @@ -10120,8 +8912,6 @@ class MLoadUnboxedScalar return false; if (readType_ != other->readType_) return false; - if (numElems_ != other->numElems_) - return false; if (offsetAdjustment() != other->offsetAdjustment()) return false; if (canonicalizeDoubles() != other->canonicalizeDoubles()) @@ -10263,7 +9053,7 @@ class StoreUnboxedScalarBase explicit StoreUnboxedScalarBase(Scalar::Type writeType) : writeType_(writeType) { - MOZ_ASSERT(isIntegerWrite() || isFloatWrite() || isSimdWrite()); + MOZ_ASSERT(isIntegerWrite() || isFloatWrite()); } public: @@ -10289,9 +9079,6 @@ class StoreUnboxedScalarBase return writeType_ == Scalar::Float32 || writeType_ == Scalar::Float64; } - bool isSimdWrite() const { - return Scalar::isSimdType(writeType()); - } }; // Store an unboxed scalar value to a typed array or other object. @@ -10314,7 +9101,6 @@ class MStoreUnboxedScalar bool requiresBarrier_; int32_t offsetAdjustment_; - unsigned numElems_; // used only for SIMD MStoreUnboxedScalar(MDefinition* elements, MDefinition* index, MDefinition* value, Scalar::Type storageType, TruncateInputKind truncateInput, @@ -10325,8 +9111,7 @@ class MStoreUnboxedScalar storageType_(storageType), truncateInput_(truncateInput), requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier), - offsetAdjustment_(offsetAdjustment), - numElems_(1) + offsetAdjustment_(offsetAdjustment) { if (requiresBarrier_) setGuard(); // Not removable or movable @@ -10342,14 +9127,6 @@ class MStoreUnboxedScalar TRIVIAL_NEW_WRAPPERS NAMED_OPERANDS((0, elements), (1, index), (2, value)) - void setSimdWrite(Scalar::Type writeType, unsigned numElems) { - MOZ_ASSERT(Scalar::isSimdType(writeType)); - setWriteType(writeType); - numElems_ = numElems; - } - unsigned numElems() const { - return numElems_; - } Scalar::Type storageType() const { return storageType_; } @@ -10401,8 +9178,6 @@ class MStoreTypedArrayElementHole NAMED_OPERANDS((0, elements), (1, length), (2, index), (3, value)) Scalar::Type arrayType() const { - MOZ_ASSERT(!Scalar::isSimdType(writeType()), - "arrayType == writeType iff the write type isn't SIMD"); return writeType(); } AliasSet getAliasSet() const override { @@ -13832,7 +12607,6 @@ class MAsmJSMemoryAccess needsBoundsCheck_(true) { MOZ_ASSERT(accessType != Scalar::Uint8Clamped); - MOZ_ASSERT(!Scalar::isSimdType(accessType)); } uint32_t offset() const { return offset_; } @@ -13998,7 +12772,7 @@ class MWasmLoadGlobalVar : public MNullaryInstruction MWasmLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant) : globalDataOffset_(globalDataOffset), isConstant_(isConstant) { - MOZ_ASSERT(IsNumberType(type) || IsSimdType(type)); + MOZ_ASSERT(IsNumberType(type)); setResultType(type); setMovable(); } diff --git a/js/src/jit/MIRGenerator.h b/js/src/jit/MIRGenerator.h index 080205abcf..53e1155be9 100644 --- a/js/src/jit/MIRGenerator.h +++ b/js/src/jit/MIRGenerator.h @@ -147,9 +147,6 @@ class MIRGenerator bool performsCall() const { return performsCall_; } - // Traverses the graph to find if there's any SIMD instruction. Costful but - // the value is cached, so don't worry about calling it several times. - bool usesSimd(); bool modifiesFrameArguments() const { return modifiesFrameArguments_; @@ -180,8 +177,6 @@ class MIRGenerator uint32_t wasmMaxStackArgBytes_; bool performsCall_; - bool usesSimd_; - bool cachedUsesSimd_; // Keep track of whether frame arguments are modified during execution. // RegAlloc needs to know this as spilling values back to their register diff --git a/js/src/jit/MIRGraph.cpp b/js/src/jit/MIRGraph.cpp index 286e859d39..3cba074096 100644 --- a/js/src/jit/MIRGraph.cpp +++ b/js/src/jit/MIRGraph.cpp @@ -32,8 +32,6 @@ MIRGenerator::MIRGenerator(CompileCompartment* compartment, const JitCompileOpti cancelBuild_(false), wasmMaxStackArgBytes_(0), performsCall_(false), - usesSimd_(false), - cachedUsesSimd_(false), modifiesFrameArguments_(false), instrumentedProfiling_(false), instrumentedProfilingIsCached_(false), @@ -44,37 +42,6 @@ MIRGenerator::MIRGenerator(CompileCompartment* compartment, const JitCompileOpti { } bool -MIRGenerator::usesSimd() -{ - if (cachedUsesSimd_) - return usesSimd_; - - cachedUsesSimd_ = true; - for (ReversePostorderIterator block = graph_->rpoBegin(), - end = graph_->rpoEnd(); - block != end; - block++) - { - // It's fine to use MInstructionIterator here because we don't have to - // worry about Phis, since any reachable phi (or phi cycle) will have at - // least one instruction as an input. - for (MInstructionIterator inst = block->begin(); inst != block->end(); inst++) { - // Instructions that have SIMD inputs but not a SIMD type are fine - // to ignore, as their inputs are also reached at some point. By - // induction, at least one instruction with a SIMD type is reached - // at some point. - if (IsSimdType(inst->type())) { - MOZ_ASSERT(SupportsSimd); - usesSimd_ = true; - return true; - } - } - } - usesSimd_ = false; - return false; -} - -bool MIRGenerator::abortFmt(const char* message, va_list ap) { JitSpewVA(JitSpew_IonAbort, message, ap); diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index 54c65aff90..aa2dda77a2 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -11,27 +11,6 @@ namespace jit { #define MIR_OPCODE_LIST(_) \ _(Constant) \ - _(SimdBox) \ - _(SimdUnbox) \ - _(SimdValueX4) \ - _(SimdSplat) \ - _(SimdConstant) \ - _(SimdConvert) \ - _(SimdReinterpretCast) \ - _(SimdExtractElement) \ - _(SimdInsertElement) \ - _(SimdSwizzle) \ - _(SimdGeneralShuffle) \ - _(SimdShuffle) \ - _(SimdUnaryArith) \ - _(SimdBinaryComp) \ - _(SimdBinaryArith) \ - _(SimdBinarySaturating) \ - _(SimdBinaryBitwise) \ - _(SimdShift) \ - _(SimdSelect) \ - _(SimdAllTrue) \ - _(SimdAnyTrue) \ _(CloneLiteral) \ _(Parameter) \ _(Callee) \ diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index 07f7b6fdcd..6721dd4419 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -240,8 +240,7 @@ template void MacroAssembler::guardTypeSetMightBeIncomplete(const TemporaryTypeS template<typename S, typename T> static void -StoreToTypedFloatArray(MacroAssembler& masm, int arrayType, const S& value, const T& dest, - unsigned numElems) +StoreToTypedFloatArray(MacroAssembler& masm, int arrayType, const S& value, const T& dest) { switch (arrayType) { case Scalar::Float32: @@ -250,48 +249,6 @@ StoreToTypedFloatArray(MacroAssembler& masm, int arrayType, const S& value, cons case Scalar::Float64: masm.storeDouble(value, dest); break; - case Scalar::Float32x4: - switch (numElems) { - case 1: - masm.storeFloat32(value, dest); - break; - case 2: - masm.storeDouble(value, dest); - break; - case 3: - masm.storeFloat32x3(value, dest); - break; - case 4: - masm.storeUnalignedSimd128Float(value, dest); - break; - default: MOZ_CRASH("unexpected number of elements in simd write"); - } - break; - case Scalar::Int32x4: - switch (numElems) { - case 1: - masm.storeInt32x1(value, dest); - break; - case 2: - masm.storeInt32x2(value, dest); - break; - case 3: - masm.storeInt32x3(value, dest); - break; - case 4: - masm.storeUnalignedSimd128Int(value, dest); - break; - default: MOZ_CRASH("unexpected number of elements in simd write"); - } - break; - case Scalar::Int8x16: - MOZ_ASSERT(numElems == 16, "unexpected partial store"); - masm.storeUnalignedSimd128Int(value, dest); - break; - case Scalar::Int16x8: - MOZ_ASSERT(numElems == 8, "unexpected partial store"); - masm.storeUnalignedSimd128Int(value, dest); - break; default: MOZ_CRASH("Invalid typed array type"); } @@ -299,21 +256,21 @@ StoreToTypedFloatArray(MacroAssembler& masm, int arrayType, const S& value, cons void MacroAssembler::storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, - const BaseIndex& dest, unsigned numElems) + const BaseIndex& dest) { - StoreToTypedFloatArray(*this, arrayType, value, dest, numElems); + StoreToTypedFloatArray(*this, arrayType, value, dest); } void MacroAssembler::storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, - const Address& dest, unsigned numElems) + const Address& dest) { - StoreToTypedFloatArray(*this, arrayType, value, dest, numElems); + StoreToTypedFloatArray(*this, arrayType, value, dest); } template<typename T> void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const T& src, AnyRegister dest, Register temp, - Label* fail, bool canonicalizeDoubles, unsigned numElems) + Label* fail, bool canonicalizeDoubles) { switch (arrayType) { case Scalar::Int8: @@ -359,59 +316,15 @@ MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const T& src, AnyRegi if (canonicalizeDoubles) canonicalizeDouble(dest.fpu()); break; - case Scalar::Int32x4: - switch (numElems) { - case 1: - loadInt32x1(src, dest.fpu()); - break; - case 2: - loadInt32x2(src, dest.fpu()); - break; - case 3: - loadInt32x3(src, dest.fpu()); - break; - case 4: - loadUnalignedSimd128Int(src, dest.fpu()); - break; - default: MOZ_CRASH("unexpected number of elements in SIMD load"); - } - break; - case Scalar::Float32x4: - switch (numElems) { - case 1: - loadFloat32(src, dest.fpu()); - break; - case 2: - loadDouble(src, dest.fpu()); - break; - case 3: - loadFloat32x3(src, dest.fpu()); - break; - case 4: - loadUnalignedSimd128Float(src, dest.fpu()); - break; - default: MOZ_CRASH("unexpected number of elements in SIMD load"); - } - break; - case Scalar::Int8x16: - MOZ_ASSERT(numElems == 16, "unexpected partial load"); - loadUnalignedSimd128Int(src, dest.fpu()); - break; - case Scalar::Int16x8: - MOZ_ASSERT(numElems == 8, "unexpected partial load"); - loadUnalignedSimd128Int(src, dest.fpu()); - break; default: MOZ_CRASH("Invalid typed array type"); } } template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const Address& src, AnyRegister dest, - Register temp, Label* fail, bool canonicalizeDoubles, - unsigned numElems); + Register temp, Label* fail, bool canonicalizeDoubles); template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const BaseIndex& src, AnyRegister dest, - Register temp, Label* fail, bool canonicalizeDoubles, - unsigned numElems); + Register temp, Label* fail, bool canonicalizeDoubles); template<typename T> void diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 173a39014c..f681456396 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -1290,9 +1290,6 @@ class MacroAssembler : public MacroAssemblerSpecific inline void canonicalizeFloat(FloatRegister reg); inline void canonicalizeFloatIfDeterministic(FloatRegister reg); - inline void canonicalizeFloat32x4(FloatRegister reg, FloatRegister scratch) - DEFINED_ON(x86_shared); - public: // ======================================================================== // Memory access primitives. @@ -1603,7 +1600,7 @@ class MacroAssembler : public MacroAssemblerSpecific template<typename T> void loadFromTypedArray(Scalar::Type arrayType, const T& src, AnyRegister dest, Register temp, Label* fail, - bool canonicalizeDoubles = true, unsigned numElems = 0); + bool canonicalizeDoubles = true); template<typename T> void loadFromTypedArray(Scalar::Type arrayType, const T& src, const ValueOperand& dest, bool allowDouble, @@ -1630,10 +1627,8 @@ class MacroAssembler : public MacroAssemblerSpecific } } - void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const BaseIndex& dest, - unsigned numElems = 0); - void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const Address& dest, - unsigned numElems = 0); + void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const BaseIndex& dest); + void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const Address& dest); // Load a property from an UnboxedPlainObject or UnboxedArrayObject. template <typename T> diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index 52c737e677..7b35349ab2 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -1785,10 +1785,6 @@ GetTypedArrayRange(TempAllocator& alloc, Scalar::Type type) case Scalar::Int64: case Scalar::Float32: case Scalar::Float64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: case Scalar::MaxTypedArrayViewType: break; } diff --git a/js/src/jit/Recover.cpp b/js/src/jit/Recover.cpp index 0d6882f52c..28601fa7cd 100644 --- a/js/src/jit/Recover.cpp +++ b/js/src/jit/Recover.cpp @@ -14,7 +14,6 @@ #include "jsstr.h" #include "builtin/RegExp.h" -#include "builtin/SIMD.h" #include "builtin/TypedObject.h" #include "gc/Heap.h" @@ -1448,79 +1447,6 @@ RLambda::recover(JSContext* cx, SnapshotIterator& iter) const } bool -MSimdBox::writeRecoverData(CompactBufferWriter& writer) const -{ - MOZ_ASSERT(canRecoverOnBailout()); - writer.writeUnsigned(uint32_t(RInstruction::Recover_SimdBox)); - static_assert(unsigned(SimdType::Count) < 0x100, "assuming SimdType fits in 8 bits"); - writer.writeByte(uint8_t(simdType())); - return true; -} - -RSimdBox::RSimdBox(CompactBufferReader& reader) -{ - type_ = reader.readByte(); -} - -bool -RSimdBox::recover(JSContext* cx, SnapshotIterator& iter) const -{ - JSObject* resultObject = nullptr; - RValueAllocation a = iter.readAllocation(); - MOZ_ASSERT(iter.allocationReadable(a)); - MOZ_ASSERT_IF(a.mode() == RValueAllocation::ANY_FLOAT_REG, a.fpuReg().isSimd128()); - const FloatRegisters::RegisterContent* raw = iter.floatAllocationPointer(a); - switch (SimdType(type_)) { - case SimdType::Bool8x16: - resultObject = js::CreateSimd<Bool8x16>(cx, (const Bool8x16::Elem*) raw); - break; - case SimdType::Int8x16: - resultObject = js::CreateSimd<Int8x16>(cx, (const Int8x16::Elem*) raw); - break; - case SimdType::Uint8x16: - resultObject = js::CreateSimd<Uint8x16>(cx, (const Uint8x16::Elem*) raw); - break; - case SimdType::Bool16x8: - resultObject = js::CreateSimd<Bool16x8>(cx, (const Bool16x8::Elem*) raw); - break; - case SimdType::Int16x8: - resultObject = js::CreateSimd<Int16x8>(cx, (const Int16x8::Elem*) raw); - break; - case SimdType::Uint16x8: - resultObject = js::CreateSimd<Uint16x8>(cx, (const Uint16x8::Elem*) raw); - break; - case SimdType::Bool32x4: - resultObject = js::CreateSimd<Bool32x4>(cx, (const Bool32x4::Elem*) raw); - break; - case SimdType::Int32x4: - resultObject = js::CreateSimd<Int32x4>(cx, (const Int32x4::Elem*) raw); - break; - case SimdType::Uint32x4: - resultObject = js::CreateSimd<Uint32x4>(cx, (const Uint32x4::Elem*) raw); - break; - case SimdType::Float32x4: - resultObject = js::CreateSimd<Float32x4>(cx, (const Float32x4::Elem*) raw); - break; - case SimdType::Float64x2: - MOZ_CRASH("NYI, RSimdBox of Float64x2"); - break; - case SimdType::Bool64x2: - MOZ_CRASH("NYI, RSimdBox of Bool64x2"); - break; - case SimdType::Count: - MOZ_CRASH("RSimdBox of Count is unreachable"); - } - - if (!resultObject) - return false; - - RootedValue result(cx); - result.setObject(*resultObject); - iter.storeInstructionResult(result); - return true; -} - -bool MObjectState::writeRecoverData(CompactBufferWriter& writer) const { MOZ_ASSERT(canRecoverOnBailout()); diff --git a/js/src/jit/Recover.h b/js/src/jit/Recover.h index 41e64a9259..0d88e61ed6 100644 --- a/js/src/jit/Recover.h +++ b/js/src/jit/Recover.h @@ -104,7 +104,6 @@ namespace jit { _(NewDerivedTypedObject) \ _(CreateThisWithTemplate) \ _(Lambda) \ - _(SimdBox) \ _(ObjectState) \ _(ArrayState) \ _(AtomicIsLockFree) \ @@ -616,17 +615,6 @@ class RLambda final : public RInstruction MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override; }; -class RSimdBox final : public RInstruction -{ - private: - uint8_t type_; - - public: - RINSTRUCTION_HEADER_NUM_OP_(SimdBox, 1) - - MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override; -}; - class RObjectState final : public RInstruction { private: diff --git a/js/src/jit/TypePolicy.cpp b/js/src/jit/TypePolicy.cpp index 1222cdd2b2..59ac9e2c21 100644 --- a/js/src/jit/TypePolicy.cpp +++ b/js/src/jit/TypePolicy.cpp @@ -582,45 +582,6 @@ template bool NoFloatPolicyAfter<2>::adjustInputs(TempAllocator& alloc, MInstruc template <unsigned Op> bool -SimdScalarPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) -{ - MOZ_ASSERT(IsSimdType(ins->type())); - MIRType laneType = SimdTypeToLaneType(ins->type()); - - MDefinition* in = ins->getOperand(Op); - - // A vector with boolean lanes requires Int32 inputs that have already been - // converted to 0/-1. - // We can't insert a MIRType::Boolean lane directly - it requires conversion. - if (laneType == MIRType::Boolean) { - MOZ_ASSERT(in->type() == MIRType::Int32, "Boolean SIMD vector requires Int32 lanes."); - return true; - } - - if (in->type() == laneType) - return true; - - MInstruction* replace; - if (laneType == MIRType::Int32) { - replace = MTruncateToInt32::New(alloc, in); - } else { - MOZ_ASSERT(laneType == MIRType::Float32); - replace = MToFloat32::New(alloc, in); - } - - ins->block()->insertBefore(ins, replace); - ins->replaceOperand(Op, replace); - - return replace->typePolicy()->adjustInputs(alloc, replace); -} - -template bool SimdScalarPolicy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); -template bool SimdScalarPolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); -template bool SimdScalarPolicy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); -template bool SimdScalarPolicy<3>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def); - -template <unsigned Op> -bool BoxPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) { MDefinition* in = ins->getOperand(Op); @@ -802,75 +763,6 @@ template bool ObjectPolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruc template bool ObjectPolicy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); template bool ObjectPolicy<3>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); -template <unsigned Op> -bool -SimdSameAsReturnedTypePolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) -{ - MOZ_ASSERT(ins->type() == ins->getOperand(Op)->type()); - return true; -} - -template bool -SimdSameAsReturnedTypePolicy<0>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); -template bool -SimdSameAsReturnedTypePolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); - -bool -SimdAllPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) -{ - for (unsigned i = 0, e = ins->numOperands(); i < e; i++) - MOZ_ASSERT(ins->getOperand(i)->type() == ins->typePolicySpecialization()); - return true; -} - -template <unsigned Op> -bool -SimdPolicy<Op>::adjustInputs(TempAllocator& alloc, MInstruction* ins) -{ - MOZ_ASSERT(ins->typePolicySpecialization() == ins->getOperand(Op)->type()); - return true; -} - -template bool -SimdPolicy<0>::adjustInputs(TempAllocator& alloc, MInstruction* ins); - -bool -SimdShufflePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) -{ - MSimdGeneralShuffle* s = ins->toSimdGeneralShuffle(); - - for (unsigned i = 0; i < s->numVectors(); i++) - MOZ_ASSERT(ins->getOperand(i)->type() == ins->typePolicySpecialization()); - - // Next inputs are the lanes, which need to be int32 - for (unsigned i = 0; i < s->numLanes(); i++) { - MDefinition* in = ins->getOperand(s->numVectors() + i); - if (in->type() == MIRType::Int32) - continue; - - MInstruction* replace = MToInt32::New(alloc, in, MacroAssembler::IntConversion_NumbersOnly); - ins->block()->insertBefore(ins, replace); - ins->replaceOperand(s->numVectors() + i, replace); - if (!replace->typePolicy()->adjustInputs(alloc, replace)) - return false; - } - - return true; -} - -bool -SimdSelectPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) -{ - // First input is the mask, which has to be a boolean. - MOZ_ASSERT(IsBooleanSimdType(ins->getOperand(0)->type())); - - // Next inputs are the two vectors of a particular type. - for (unsigned i = 1; i < 3; i++) - MOZ_ASSERT(ins->getOperand(i)->type() == ins->typePolicySpecialization()); - - return true; -} - bool CallPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) { @@ -928,13 +820,6 @@ StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator& alloc, MInstruction* i Scalar::Type writeType, MDefinition* value, int valueOperand) { - // Storing a SIMD value requires a valueOperand that has already been - // SimdUnboxed. See IonBuilder::inlineSimdStore(() - if (Scalar::isSimdType(writeType)) { - MOZ_ASSERT(IsSimdType(value->type())); - return true; - } - MDefinition* curValue = value; // First, ensure the value is int32, boolean, double or Value. // The conversion is based on TypedArrayObjectTemplate::setElementTail. @@ -1196,9 +1081,6 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) _(FilterTypeSetPolicy) \ _(InstanceOfPolicy) \ _(PowPolicy) \ - _(SimdAllPolicy) \ - _(SimdSelectPolicy) \ - _(SimdShufflePolicy) \ _(StoreTypedArrayElementStaticPolicy) \ _(StoreTypedArrayHolePolicy) \ _(StoreUnboxedScalarPolicy) \ @@ -1236,7 +1118,6 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) _(Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>, IntPolicy<3>>) \ _(Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>, TruncateToInt32Policy<3> >) \ _(Mix3Policy<ObjectPolicy<0>, CacheIdPolicy<1>, NoFloatPolicy<2>>) \ - _(Mix4Policy<SimdScalarPolicy<0>, SimdScalarPolicy<1>, SimdScalarPolicy<2>, SimdScalarPolicy<3> >) \ _(MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >) \ _(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >) \ _(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1> >) \ @@ -1254,8 +1135,6 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) _(MixPolicy<ObjectPolicy<0>, StringPolicy<1> >) \ _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<2> >) \ _(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> >) \ - _(MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >) \ - _(MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >) \ _(MixPolicy<StringPolicy<0>, IntPolicy<1> >) \ _(MixPolicy<StringPolicy<0>, StringPolicy<1> >) \ _(MixPolicy<BoxPolicy<0>, BoxPolicy<1> >) \ @@ -1265,9 +1144,6 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) _(ObjectPolicy<0>) \ _(ObjectPolicy<1>) \ _(ObjectPolicy<3>) \ - _(SimdPolicy<0>) \ - _(SimdSameAsReturnedTypePolicy<0>) \ - _(SimdScalarPolicy<0>) \ _(StringPolicy<0>) diff --git a/js/src/jit/TypePolicy.h b/js/src/jit/TypePolicy.h index f5d8d7a59e..0b9d2b37ef 100644 --- a/js/src/jit/TypePolicy.h +++ b/js/src/jit/TypePolicy.h @@ -318,61 +318,6 @@ class ObjectPolicy final : public TypePolicy // a primitive, we use ValueToNonNullObject. typedef ObjectPolicy<0> SingleObjectPolicy; -// Convert an operand to have a type identical to the scalar type of the -// returned type of the instruction. -template <unsigned Op> -class SimdScalarPolicy final : public TypePolicy -{ - public: - EMPTY_DATA_; - static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def); - virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override { - return staticAdjustInputs(alloc, def); - } -}; - -class SimdAllPolicy final : public TypePolicy -{ - public: - SPECIALIZATION_DATA_; - virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override; -}; - -template <unsigned Op> -class SimdPolicy final : public TypePolicy -{ - public: - SPECIALIZATION_DATA_; - virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override; -}; - -class SimdSelectPolicy final : public TypePolicy -{ - public: - SPECIALIZATION_DATA_; - virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override; -}; - -class SimdShufflePolicy final : public TypePolicy -{ - public: - SPECIALIZATION_DATA_; - virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override; -}; - -// SIMD value-type policy, use the returned type of the instruction to determine -// how to unbox its operand. -template <unsigned Op> -class SimdSameAsReturnedTypePolicy final : public TypePolicy -{ - public: - EMPTY_DATA_; - static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins); - virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override { - return staticAdjustInputs(alloc, ins); - } -}; - template <unsigned Op> class BoxPolicy final : public TypePolicy { diff --git a/js/src/jit/TypedObjectPrediction.cpp b/js/src/jit/TypedObjectPrediction.cpp index fe968e5eeb..f6d6138bb5 100644 --- a/js/src/jit/TypedObjectPrediction.cpp +++ b/js/src/jit/TypedObjectPrediction.cpp @@ -118,7 +118,6 @@ TypedObjectPrediction::ofArrayKind() const switch (kind()) { case type::Scalar: case type::Reference: - case type::Simd: case type::Struct: return false; @@ -206,12 +205,6 @@ TypedObjectPrediction::referenceType() const return extractType<ReferenceTypeDescr>(); } -SimdType -TypedObjectPrediction::simdType() const -{ - return descr().as<SimdTypeDescr>().type(); -} - bool TypedObjectPrediction::hasKnownArrayLength(int32_t* length) const { diff --git a/js/src/jit/TypedObjectPrediction.h b/js/src/jit/TypedObjectPrediction.h index 3a042b7712..9bf9ae6e8a 100644 --- a/js/src/jit/TypedObjectPrediction.h +++ b/js/src/jit/TypedObjectPrediction.h @@ -163,11 +163,10 @@ class TypedObjectPrediction { ////////////////////////////////////////////////////////////////////// // Simple operations // - // Only valid when |kind()| is Scalar, Reference, or Simd (as appropriate). + // Only valid when |kind()| is Scalar or Reference (as appropriate). ScalarTypeDescr::Type scalarType() const; ReferenceTypeDescr::Type referenceType() const; - SimdType simdType() const; /////////////////////////////////////////////////////////////////////////// // Queries valid only for arrays. diff --git a/js/src/jit/arm/Lowering-arm.h b/js/src/jit/arm/Lowering-arm.h index 137ab32d2a..9b8bbf5de5 100644 --- a/js/src/jit/arm/Lowering-arm.h +++ b/js/src/jit/arm/Lowering-arm.h @@ -63,17 +63,6 @@ class LIRGeneratorARM : public LIRGeneratorShared void lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir, MDefinition* lhs, MDefinition* rhs); - void lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir, - MDefinition* lhs, MDefinition* rhs) - { - return lowerForFPU(ins, mir, lhs, rhs); - } - void lowerForCompFx4(LSimdBinaryCompFx4* ins, MSimdBinaryComp* mir, - MDefinition* lhs, MDefinition* rhs) - { - return lowerForFPU(ins, mir, lhs, rhs); - } - void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir, MDefinition* lhs, MDefinition* rhs); void lowerTruncateDToInt32(MTruncateToInt32* ins); diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index aaf92539a3..cb200f0609 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1046,34 +1046,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void loadPrivate(const Address& address, Register dest); - void loadInt32x1(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x1(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x2(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x2(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x3(const BaseIndex& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeInt32x1(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); } - void storeInt32x1(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); } - void storeInt32x2(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); } - void storeInt32x2(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); } - void storeInt32x3(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); } - void storeInt32x3(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); } - void loadAlignedSimd128Int(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeAlignedSimd128Int(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Int(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Int(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Int(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Int(FloatRegister src, BaseIndex addr) { MOZ_CRASH("NYI"); } - - void loadFloat32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadFloat32x3(const BaseIndex& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadAlignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeAlignedSimd128Float(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Float(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Float(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Float(FloatRegister src, BaseIndex addr) { MOZ_CRASH("NYI"); } - void loadDouble(const Address& addr, FloatRegister dest); void loadDouble(const BaseIndex& src, FloatRegister dest); diff --git a/js/src/jit/arm64/Lowering-arm64.h b/js/src/jit/arm64/Lowering-arm64.h index d9c3c49388..5f89accce1 100644 --- a/js/src/jit/arm64/Lowering-arm64.h +++ b/js/src/jit/arm64/Lowering-arm64.h @@ -63,18 +63,6 @@ class LIRGeneratorARM64 : public LIRGeneratorShared void lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir, MDefinition* lhs, MDefinition* rhs); - void lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir, - MDefinition* lhs, MDefinition* rhs) - { - return lowerForFPU(ins, mir, lhs, rhs); - } - - void lowerForCompFx4(LSimdBinaryCompFx4* ins, MSimdBinaryComp* mir, - MDefinition* lhs, MDefinition* rhs) - { - return lowerForFPU(ins, mir, lhs, rhs); - } - void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir, MDefinition* lhs, MDefinition* rhs); void lowerTruncateDToInt32(MTruncateToInt32* ins); diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index d91db1ecbe..05284f03fc 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -907,39 +907,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler storePtr(src.reg, address); } - // SIMD. - void loadInt32x1(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x1(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x2(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x2(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x3(const BaseIndex& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeInt32x1(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); } - void storeInt32x1(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); } - void storeInt32x2(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); } - void storeInt32x2(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); } - void storeInt32x3(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); } - void storeInt32x3(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); } - void loadAlignedSimd128Int(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadAlignedSimd128Int(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeAlignedSimd128Int(FloatRegister src, const Address& addr) { MOZ_CRASH("NYI"); } - void storeAlignedSimd128Int(FloatRegister src, const BaseIndex& addr) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Int(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Int(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Int(FloatRegister dest, const Address& addr) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Int(FloatRegister dest, const BaseIndex& addr) { MOZ_CRASH("NYI"); } - - void loadFloat32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadFloat32x3(const BaseIndex& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadAlignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadAlignedSimd128Float(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeAlignedSimd128Float(FloatRegister src, const Address& addr) { MOZ_CRASH("NYI"); } - void storeAlignedSimd128Float(FloatRegister src, const BaseIndex& addr) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Float(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Float(FloatRegister dest, const Address& addr) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Float(FloatRegister dest, const BaseIndex& addr) { MOZ_CRASH("NYI"); } - // StackPointer manipulation. template <typename T> void addToStackPtr(T t); template <typename T> void addStackPtrTo(T t); diff --git a/js/src/jit/mips-shared/Lowering-mips-shared.h b/js/src/jit/mips-shared/Lowering-mips-shared.h index 577baebc22..ebcaa186f4 100644 --- a/js/src/jit/mips-shared/Lowering-mips-shared.h +++ b/js/src/jit/mips-shared/Lowering-mips-shared.h @@ -50,17 +50,6 @@ class LIRGeneratorMIPSShared : public LIRGeneratorShared void lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir, MDefinition* lhs, MDefinition* rhs); - void lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir, - MDefinition* lhs, MDefinition* rhs) - { - return lowerForFPU(ins, mir, lhs, rhs); - } - void lowerForCompFx4(LSimdBinaryCompFx4* ins, MSimdBinaryComp* mir, - MDefinition* lhs, MDefinition* rhs) - { - return lowerForFPU(ins, mir, lhs, rhs); - } - void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir, MDefinition* lhs, MDefinition* rhs); void lowerDivI(MDiv* div); diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 5ae77384c5..c51b9277c4 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -866,34 +866,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void loadPrivate(const Address& address, Register dest); - void loadInt32x1(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x1(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x2(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x2(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x3(const BaseIndex& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeInt32x1(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); } - void storeInt32x1(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); } - void storeInt32x2(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); } - void storeInt32x2(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); } - void storeInt32x3(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); } - void storeInt32x3(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); } - void loadAlignedSimd128Int(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeAlignedSimd128Int(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Int(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Int(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Int(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Int(FloatRegister src, BaseIndex addr) { MOZ_CRASH("NYI"); } - - void loadFloat32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadFloat32x3(const BaseIndex& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadAlignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeAlignedSimd128Float(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Float(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Float(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Float(FloatRegister src, BaseIndex addr) { MOZ_CRASH("NYI"); } - void loadDouble(const Address& addr, FloatRegister dest); void loadDouble(const BaseIndex& src, FloatRegister dest); void loadUnalignedDouble(const wasm::MemoryAccessDesc& access, const BaseIndex& src, diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index 3a84b7c0c9..8594a41a1e 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -879,34 +879,6 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 void loadPrivate(const Address& address, Register dest); - void loadInt32x1(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x1(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x2(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x2(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadInt32x3(const BaseIndex& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeInt32x1(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); } - void storeInt32x1(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); } - void storeInt32x2(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); } - void storeInt32x2(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); } - void storeInt32x3(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); } - void storeInt32x3(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); } - void loadAlignedSimd128Int(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeAlignedSimd128Int(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Int(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Int(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Int(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Int(FloatRegister src, BaseIndex addr) { MOZ_CRASH("NYI"); } - - void loadFloat32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadFloat32x3(const BaseIndex& src, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadAlignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeAlignedSimd128Float(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void loadUnalignedSimd128Float(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Float(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); } - void storeUnalignedSimd128Float(FloatRegister src, BaseIndex addr) { MOZ_CRASH("NYI"); } - void loadDouble(const Address& addr, FloatRegister dest); void loadDouble(const BaseIndex& src, FloatRegister dest); void loadUnalignedDouble(const wasm::MemoryAccessDesc& access, const BaseIndex& src, diff --git a/js/src/jit/none/Lowering-none.h b/js/src/jit/none/Lowering-none.h index 6a52ac36d8..64f85e4573 100644 --- a/js/src/jit/none/Lowering-none.h +++ b/js/src/jit/none/Lowering-none.h @@ -45,14 +45,6 @@ class LIRGeneratorNone : public LIRGeneratorShared void lowerForMulInt64(LMulI64*, MMul*, MDefinition*, MDefinition* v = nullptr) { MOZ_CRASH(); } template <typename T> void lowerForShiftInt64(T, MDefinition*, MDefinition*, MDefinition* v = nullptr) { MOZ_CRASH(); } - void lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir, - MDefinition* lhs, MDefinition* rhs) { - MOZ_CRASH(); - } - void lowerForCompFx4(LSimdBinaryCompFx4* ins, MSimdBinaryComp* mir, - MDefinition* lhs, MDefinition* rhs) { - MOZ_CRASH(); - } void lowerForBitAndAndBranch(LBitAndAndBranch*, MInstruction*, MDefinition*, MDefinition*) { MOZ_CRASH(); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index f71439a6cc..bb32adcdc1 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -261,19 +261,10 @@ class MacroAssemblerNone : public Assembler template <typename T, typename S> void move64(T, S) { MOZ_CRASH(); } template <typename T> CodeOffset movWithPatch(T, Register) { MOZ_CRASH(); } - template <typename T> void loadInt32x1(T, FloatRegister dest) { MOZ_CRASH(); } - template <typename T> void loadInt32x2(T, FloatRegister dest) { MOZ_CRASH(); } - template <typename T> void loadInt32x3(T, FloatRegister dest) { MOZ_CRASH(); } - template <typename T> void loadFloat32x3(T, FloatRegister dest) { MOZ_CRASH(); } - template <typename T> void loadPtr(T, Register) { MOZ_CRASH(); } template <typename T> void load32(T, Register) { MOZ_CRASH(); } template <typename T> void loadFloat32(T, FloatRegister) { MOZ_CRASH(); } template <typename T> void loadDouble(T, FloatRegister) { MOZ_CRASH(); } - template <typename T> void loadAlignedSimd128Int(T, FloatRegister) { MOZ_CRASH(); } - template <typename T> void loadUnalignedSimd128Int(T, FloatRegister) { MOZ_CRASH(); } - template <typename T> void loadAlignedSimd128Float(T, FloatRegister) { MOZ_CRASH(); } - template <typename T> void loadUnalignedSimd128Float(T, FloatRegister) { MOZ_CRASH(); } template <typename T> void loadPrivate(T, Register) { MOZ_CRASH(); } template <typename T> void load8SignExtend(T, Register) { MOZ_CRASH(); } template <typename T> void load8ZeroExtend(T, Register) { MOZ_CRASH(); } @@ -286,16 +277,8 @@ class MacroAssemblerNone : public Assembler template <typename T, typename S> void store32_NoSecondScratch(T, S) { MOZ_CRASH(); } template <typename T, typename S> void storeFloat32(T, S) { MOZ_CRASH(); } template <typename T, typename S> void storeDouble(T, S) { MOZ_CRASH(); } - template <typename T, typename S> void storeAlignedSimd128Int(T, S) { MOZ_CRASH(); } - template <typename T, typename S> void storeUnalignedSimd128Int(T, S) { MOZ_CRASH(); } - template <typename T, typename S> void storeAlignedSimd128Float(T, S) { MOZ_CRASH(); } - template <typename T, typename S> void storeUnalignedSimd128Float(T, S) { MOZ_CRASH(); } template <typename T, typename S> void store8(T, S) { MOZ_CRASH(); } template <typename T, typename S> void store16(T, S) { MOZ_CRASH(); } - template <typename T, typename S> void storeInt32x1(T, S) { MOZ_CRASH(); } - template <typename T, typename S> void storeInt32x2(T, S) { MOZ_CRASH(); } - template <typename T, typename S> void storeInt32x3(T, S) { MOZ_CRASH(); } - template <typename T, typename S> void storeFloat32x3(T, S) { MOZ_CRASH(); } template <typename T, typename S> void store64(T, S) { MOZ_CRASH(); } template <typename T> void computeEffectiveAddress(T, Register) { MOZ_CRASH(); } diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h index f18cbb9e1d..308d9f1a12 100644 --- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -705,7 +705,6 @@ class MemoryAccessDesc uint32_t offset_; uint32_t align_; Scalar::Type type_; - unsigned numSimdElems_; jit::MemoryBarrierBits barrierBefore_; jit::MemoryBarrierBits barrierAfter_; mozilla::Maybe<wasm::TrapOffset> trapOffset_; @@ -719,32 +718,23 @@ class MemoryAccessDesc : offset_(offset), align_(align), type_(type), - numSimdElems_(numSimdElems), barrierBefore_(barrierBefore), barrierAfter_(barrierAfter), trapOffset_(trapOffset) { - MOZ_ASSERT(Scalar::isSimdType(type) == (numSimdElems > 0)); MOZ_ASSERT(mozilla::IsPowerOfTwo(align)); - MOZ_ASSERT_IF(isSimd(), hasTrap()); MOZ_ASSERT_IF(isAtomic(), hasTrap()); } uint32_t offset() const { return offset_; } uint32_t align() const { return align_; } Scalar::Type type() const { return type_; } - unsigned byteSize() const { - return Scalar::isSimdType(type()) - ? Scalar::scalarByteSize(type()) * numSimdElems() - : Scalar::byteSize(type()); - } - unsigned numSimdElems() const { MOZ_ASSERT(isSimd()); return numSimdElems_; } + unsigned byteSize() const { return Scalar::byteSize(type()); } jit::MemoryBarrierBits barrierBefore() const { return barrierBefore_; } jit::MemoryBarrierBits barrierAfter() const { return barrierAfter_; } bool hasTrap() const { return !!trapOffset_; } TrapOffset trapOffset() const { return *trapOffset_; } bool isAtomic() const { return (barrierBefore_ | barrierAfter_) != jit::MembarNobits; } - bool isSimd() const { return Scalar::isSimdType(type_); } bool isPlainAsmJS() const { return !hasTrap(); } void clearOffset() { offset_ = 0; } diff --git a/js/src/jit/shared/CodeGenerator-shared-inl.h b/js/src/jit/shared/CodeGenerator-shared-inl.h index 00ca8b3d63..7325449ed1 100644 --- a/js/src/jit/shared/CodeGenerator-shared-inl.h +++ b/js/src/jit/shared/CodeGenerator-shared-inl.h @@ -391,10 +391,6 @@ CodeGeneratorShared::verifyHeapAccessDisassembly(uint32_t begin, uint32_t end, b break; case Scalar::Float32: case Scalar::Float64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: op = OtherOperand(ToFloatRegister(alloc).encoding()); break; case Scalar::Uint8Clamped: diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 3701f24872..cdacf9ead5 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -85,17 +85,10 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator* gen, LIRGraph* graph, Mac MOZ_ASSERT(graph->argumentSlotCount() == 0); frameDepth_ += gen->wasmMaxStackArgBytes(); - if (gen->usesSimd()) { - // If the function uses any SIMD then we may need to insert padding - // so that local slots are aligned for SIMD. - frameInitialAdjustment_ = ComputeByteAlignment(sizeof(wasm::Frame), - WasmStackAlignment); - frameDepth_ += frameInitialAdjustment_; - // Keep the stack aligned. Some SIMD sequences build values on the - // stack and need the stack aligned. - frameDepth_ += ComputeByteAlignment(sizeof(wasm::Frame) + frameDepth_, - WasmStackAlignment); - } else if (gen->performsCall()) { + static_assert(!SupportsSimd, "we need padding so that local slots are SIMD-aligned and " + "the stack must be kept SIMD-aligned too."); + + if (gen->performsCall()) { // An MWasmCall does not align the stack pointer at calls sites but // instead relies on the a priori stack adjustment. This must be the // last adjustment of frameDepth_. diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index 69782f8061..437c3fa7f3 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -152,634 +152,6 @@ class LMoveGroup : public LInstructionHelper<0, 0, 0> } }; - -// Constructs a SIMD object (value type) based on the MIRType of its input. -class LSimdBox : public LInstructionHelper<1, 1, 1> -{ - public: - LIR_HEADER(SimdBox) - - explicit LSimdBox(const LAllocation& simd, const LDefinition& temp) - { - setOperand(0, simd); - setTemp(0, temp); - } - - const LDefinition* temp() { - return getTemp(0); - } - - MSimdBox* mir() const { - return mir_->toSimdBox(); - } -}; - -class LSimdUnbox : public LInstructionHelper<1, 1, 1> -{ - public: - LIR_HEADER(SimdUnbox) - - LSimdUnbox(const LAllocation& obj, const LDefinition& temp) - { - setOperand(0, obj); - setTemp(0, temp); - } - - const LDefinition* temp() { - return getTemp(0); - } - - MSimdUnbox* mir() const { - return mir_->toSimdUnbox(); - } -}; - -// Constructs a SIMD value with 16 equal components (int8x16). -class LSimdSplatX16 : public LInstructionHelper<1, 1, 0> -{ - public: - LIR_HEADER(SimdSplatX16) - explicit LSimdSplatX16(const LAllocation& v) - { - setOperand(0, v); - } - - MSimdSplat* mir() const { - return mir_->toSimdSplat(); - } -}; - -// Constructs a SIMD value with 8 equal components (int16x8). -class LSimdSplatX8 : public LInstructionHelper<1, 1, 0> -{ - public: - LIR_HEADER(SimdSplatX8) - explicit LSimdSplatX8(const LAllocation& v) - { - setOperand(0, v); - } - - MSimdSplat* mir() const { - return mir_->toSimdSplat(); - } -}; - -// Constructs a SIMD value with 4 equal components (e.g. int32x4, float32x4). -class LSimdSplatX4 : public LInstructionHelper<1, 1, 0> -{ - public: - LIR_HEADER(SimdSplatX4) - explicit LSimdSplatX4(const LAllocation& v) - { - setOperand(0, v); - } - - MSimdSplat* mir() const { - return mir_->toSimdSplat(); - } -}; - -// Reinterpret the bits of a SIMD value with a different type. -class LSimdReinterpretCast : public LInstructionHelper<1, 1, 0> -{ - public: - LIR_HEADER(SimdReinterpretCast) - explicit LSimdReinterpretCast(const LAllocation& v) - { - setOperand(0, v); - } - - MSimdReinterpretCast* mir() const { - return mir_->toSimdReinterpretCast(); - } -}; - -class LSimdExtractElementBase : public LInstructionHelper<1, 1, 0> -{ - protected: - explicit LSimdExtractElementBase(const LAllocation& base) { - setOperand(0, base); - } - - public: - const LAllocation* getBase() { - return getOperand(0); - } - MSimdExtractElement* mir() const { - return mir_->toSimdExtractElement(); - } -}; - -// Extracts an element from a given SIMD bool32x4 lane. -class LSimdExtractElementB : public LSimdExtractElementBase -{ - public: - LIR_HEADER(SimdExtractElementB); - explicit LSimdExtractElementB(const LAllocation& base) - : LSimdExtractElementBase(base) - {} -}; - -// Extracts an element from a given SIMD int32x4 lane. -class LSimdExtractElementI : public LSimdExtractElementBase -{ - public: - LIR_HEADER(SimdExtractElementI); - explicit LSimdExtractElementI(const LAllocation& base) - : LSimdExtractElementBase(base) - {} -}; - -// Extracts an element from a given SIMD float32x4 lane. -class LSimdExtractElementF : public LSimdExtractElementBase -{ - public: - LIR_HEADER(SimdExtractElementF); - explicit LSimdExtractElementF(const LAllocation& base) - : LSimdExtractElementBase(base) - {} -}; - -// Extracts an element from an Uint32x4 SIMD vector, converts to double. -class LSimdExtractElementU2D : public LInstructionHelper<1, 1, 1> -{ - public: - LIR_HEADER(SimdExtractElementU2D); - explicit LSimdExtractElementU2D(const LAllocation& base, const LDefinition& temp) { - setOperand(0, base); - setTemp(0, temp); - } - MSimdExtractElement* mir() const { - return mir_->toSimdExtractElement(); - } - const LDefinition* temp() { - return getTemp(0); - } -}; - - -class LSimdInsertElementBase : public LInstructionHelper<1, 2, 0> -{ - protected: - LSimdInsertElementBase(const LAllocation& vec, const LAllocation& val) - { - setOperand(0, vec); - setOperand(1, val); - } - - public: - const LAllocation* vector() { - return getOperand(0); - } - const LAllocation* value() { - return getOperand(1); - } - unsigned lane() const { - return mir_->toSimdInsertElement()->lane(); - } - unsigned length() const { - return SimdTypeToLength(mir_->toSimdInsertElement()->type()); - } -}; - -// Replace an element from a given SIMD integer or boolean lane with a given value. -// The value inserted into a boolean lane should be 0 or -1. -class LSimdInsertElementI : public LSimdInsertElementBase -{ - public: - LIR_HEADER(SimdInsertElementI); - LSimdInsertElementI(const LAllocation& vec, const LAllocation& val) - : LSimdInsertElementBase(vec, val) - {} -}; - -// Replace an element from a given SIMD float32x4 lane with a given value. -class LSimdInsertElementF : public LSimdInsertElementBase -{ - public: - LIR_HEADER(SimdInsertElementF); - LSimdInsertElementF(const LAllocation& vec, const LAllocation& val) - : LSimdInsertElementBase(vec, val) - {} -}; - -// Base class for both int32x4 and float32x4 shuffle instructions. -class LSimdSwizzleBase : public LInstructionHelper<1, 1, 1> -{ - public: - explicit LSimdSwizzleBase(const LAllocation& base) - { - setOperand(0, base); - } - - const LAllocation* getBase() { - return getOperand(0); - } - - unsigned numLanes() const { return mir_->toSimdSwizzle()->numLanes(); } - uint32_t lane(unsigned i) const { return mir_->toSimdSwizzle()->lane(i); } - - bool lanesMatch(uint32_t x, uint32_t y, uint32_t z, uint32_t w) const { - return mir_->toSimdSwizzle()->lanesMatch(x, y, z, w); - } -}; - -// Shuffles a int32x4 into another int32x4 vector. -class LSimdSwizzleI : public LSimdSwizzleBase -{ - public: - LIR_HEADER(SimdSwizzleI); - explicit LSimdSwizzleI(const LAllocation& base) : LSimdSwizzleBase(base) - {} -}; -// Shuffles a float32x4 into another float32x4 vector. -class LSimdSwizzleF : public LSimdSwizzleBase -{ - public: - LIR_HEADER(SimdSwizzleF); - explicit LSimdSwizzleF(const LAllocation& base) : LSimdSwizzleBase(base) - {} -}; - -class LSimdGeneralShuffleBase : public LVariadicInstruction<1, 1> -{ - public: - explicit LSimdGeneralShuffleBase(const LDefinition& temp) { - setTemp(0, temp); - } - const LAllocation* vector(unsigned i) { - MOZ_ASSERT(i < mir()->numVectors()); - return getOperand(i); - } - const LAllocation* lane(unsigned i) { - MOZ_ASSERT(i < mir()->numLanes()); - return getOperand(mir()->numVectors() + i); - } - const LDefinition* temp() { - return getTemp(0); - } - MSimdGeneralShuffle* mir() const { - return mir_->toSimdGeneralShuffle(); - } -}; - -class LSimdGeneralShuffleI : public LSimdGeneralShuffleBase -{ - public: - LIR_HEADER(SimdGeneralShuffleI); - explicit LSimdGeneralShuffleI(const LDefinition& temp) - : LSimdGeneralShuffleBase(temp) - {} -}; - -class LSimdGeneralShuffleF : public LSimdGeneralShuffleBase -{ - public: - LIR_HEADER(SimdGeneralShuffleF); - explicit LSimdGeneralShuffleF(const LDefinition& temp) - : LSimdGeneralShuffleBase(temp) - {} -}; - -// Base class for both int32x4 and float32x4 shuffle instructions. -class LSimdShuffleX4 : public LInstructionHelper<1, 2, 1> -{ - public: - LIR_HEADER(SimdShuffleX4); - LSimdShuffleX4() - {} - - const LAllocation* lhs() { - return getOperand(0); - } - const LAllocation* rhs() { - return getOperand(1); - } - const LDefinition* temp() { - return getTemp(0); - } - - uint32_t lane(unsigned i) const { return mir_->toSimdShuffle()->lane(i); } - - bool lanesMatch(uint32_t x, uint32_t y, uint32_t z, uint32_t w) const { - return mir_->toSimdShuffle()->lanesMatch(x, y, z, w); - } -}; - -// Remaining shuffles (8x16, 16x8). -class LSimdShuffle : public LInstructionHelper<1, 2, 1> -{ - public: - LIR_HEADER(SimdShuffle); - LSimdShuffle() - {} - - const LAllocation* lhs() { - return getOperand(0); - } - const LAllocation* rhs() { - return getOperand(1); - } - const LDefinition* temp() { - return getTemp(0); - } - - unsigned numLanes() const { return mir_->toSimdShuffle()->numLanes(); } - unsigned lane(unsigned i) const { return mir_->toSimdShuffle()->lane(i); } -}; - -// Binary SIMD comparison operation between two SIMD operands -class LSimdBinaryComp: public LInstructionHelper<1, 2, 0> -{ - protected: - LSimdBinaryComp() {} - -public: - const LAllocation* lhs() { - return getOperand(0); - } - const LAllocation* rhs() { - return getOperand(1); - } - MSimdBinaryComp::Operation operation() const { - return mir_->toSimdBinaryComp()->operation(); - } - const char* extraName() const { - return MSimdBinaryComp::OperationName(operation()); - } -}; - -// Binary SIMD comparison operation between two Int8x16 operands. -class LSimdBinaryCompIx16 : public LSimdBinaryComp -{ - public: - LIR_HEADER(SimdBinaryCompIx16); - LSimdBinaryCompIx16() : LSimdBinaryComp() {} -}; - -// Binary SIMD comparison operation between two Int16x8 operands. -class LSimdBinaryCompIx8 : public LSimdBinaryComp -{ - public: - LIR_HEADER(SimdBinaryCompIx8); - LSimdBinaryCompIx8() : LSimdBinaryComp() {} -}; - -// Binary SIMD comparison operation between two Int32x4 operands. -class LSimdBinaryCompIx4 : public LSimdBinaryComp -{ - public: - LIR_HEADER(SimdBinaryCompIx4); - LSimdBinaryCompIx4() : LSimdBinaryComp() {} -}; - -// Binary SIMD comparison operation between two Float32x4 operands -class LSimdBinaryCompFx4 : public LSimdBinaryComp -{ - public: - LIR_HEADER(SimdBinaryCompFx4); - LSimdBinaryCompFx4() : LSimdBinaryComp() {} -}; - -// Binary SIMD arithmetic operation between two SIMD operands -class LSimdBinaryArith : public LInstructionHelper<1, 2, 1> -{ - public: - LSimdBinaryArith() {} - - const LAllocation* lhs() { - return this->getOperand(0); - } - const LAllocation* rhs() { - return this->getOperand(1); - } - const LDefinition* temp() { - return getTemp(0); - } - - MSimdBinaryArith::Operation operation() const { - return this->mir_->toSimdBinaryArith()->operation(); - } - const char* extraName() const { - return MSimdBinaryArith::OperationName(operation()); - } -}; - -// Binary SIMD arithmetic operation between two Int8x16 operands -class LSimdBinaryArithIx16 : public LSimdBinaryArith -{ - public: - LIR_HEADER(SimdBinaryArithIx16); - LSimdBinaryArithIx16() : LSimdBinaryArith() {} -}; - -// Binary SIMD arithmetic operation between two Int16x8 operands -class LSimdBinaryArithIx8 : public LSimdBinaryArith -{ - public: - LIR_HEADER(SimdBinaryArithIx8); - LSimdBinaryArithIx8() : LSimdBinaryArith() {} -}; - -// Binary SIMD arithmetic operation between two Int32x4 operands -class LSimdBinaryArithIx4 : public LSimdBinaryArith -{ - public: - LIR_HEADER(SimdBinaryArithIx4); - LSimdBinaryArithIx4() : LSimdBinaryArith() {} -}; - -// Binary SIMD arithmetic operation between two Float32x4 operands -class LSimdBinaryArithFx4 : public LSimdBinaryArith -{ - public: - LIR_HEADER(SimdBinaryArithFx4); - LSimdBinaryArithFx4() : LSimdBinaryArith() {} -}; - -// Binary SIMD saturating arithmetic operation between two SIMD operands -class LSimdBinarySaturating : public LInstructionHelper<1, 2, 0> -{ - public: - LIR_HEADER(SimdBinarySaturating); - LSimdBinarySaturating() {} - - const LAllocation* lhs() { - return this->getOperand(0); - } - const LAllocation* rhs() { - return this->getOperand(1); - } - - MSimdBinarySaturating::Operation operation() const { - return this->mir_->toSimdBinarySaturating()->operation(); - } - SimdSign signedness() const { - return this->mir_->toSimdBinarySaturating()->signedness(); - } - MIRType type() const { - return mir_->type(); - } - const char* extraName() const { - return MSimdBinarySaturating::OperationName(operation()); - } -}; - -// Unary SIMD arithmetic operation on a SIMD operand -class LSimdUnaryArith : public LInstructionHelper<1, 1, 0> -{ - public: - explicit LSimdUnaryArith(const LAllocation& in) { - setOperand(0, in); - } - MSimdUnaryArith::Operation operation() const { - return mir_->toSimdUnaryArith()->operation(); - } -}; - -// Unary SIMD arithmetic operation on a Int8x16 operand -class LSimdUnaryArithIx16 : public LSimdUnaryArith -{ - public: - LIR_HEADER(SimdUnaryArithIx16); - explicit LSimdUnaryArithIx16(const LAllocation& in) : LSimdUnaryArith(in) {} -}; - -// Unary SIMD arithmetic operation on a Int16x8 operand -class LSimdUnaryArithIx8 : public LSimdUnaryArith -{ - public: - LIR_HEADER(SimdUnaryArithIx8); - explicit LSimdUnaryArithIx8(const LAllocation& in) : LSimdUnaryArith(in) {} -}; - -// Unary SIMD arithmetic operation on a Int32x4 operand -class LSimdUnaryArithIx4 : public LSimdUnaryArith -{ - public: - LIR_HEADER(SimdUnaryArithIx4); - explicit LSimdUnaryArithIx4(const LAllocation& in) : LSimdUnaryArith(in) {} -}; - -// Unary SIMD arithmetic operation on a Float32x4 operand -class LSimdUnaryArithFx4 : public LSimdUnaryArith -{ - public: - LIR_HEADER(SimdUnaryArithFx4); - explicit LSimdUnaryArithFx4(const LAllocation& in) : LSimdUnaryArith(in) {} -}; - -// Binary SIMD bitwise operation between two 128-bit operands. -class LSimdBinaryBitwise : public LInstructionHelper<1, 2, 0> -{ - public: - LIR_HEADER(SimdBinaryBitwise); - const LAllocation* lhs() { - return getOperand(0); - } - const LAllocation* rhs() { - return getOperand(1); - } - MSimdBinaryBitwise::Operation operation() const { - return mir_->toSimdBinaryBitwise()->operation(); - } - const char* extraName() const { - return MSimdBinaryBitwise::OperationName(operation()); - } - MIRType type() const { - return mir_->type(); - } -}; - -// Shift a SIMD vector by a scalar amount. -// The temp register is only required if the shift amount is a dynamical -// value. If it is a constant, use a BogusTemp instead. -class LSimdShift : public LInstructionHelper<1, 2, 1> -{ - public: - LIR_HEADER(SimdShift) - LSimdShift(const LAllocation& vec, const LAllocation& val, const LDefinition& temp) { - setOperand(0, vec); - setOperand(1, val); - setTemp(0, temp); - } - const LAllocation* vector() { - return getOperand(0); - } - const LAllocation* value() { - return getOperand(1); - } - const LDefinition* temp() { - return getTemp(0); - } - MSimdShift::Operation operation() const { - return mir_->toSimdShift()->operation(); - } - const char* extraName() const { - return MSimdShift::OperationName(operation()); - } - MSimdShift* mir() const { - return mir_->toSimdShift(); - } - MIRType type() const { - return mir_->type(); - } -}; - -// SIMD selection of lanes from two int32x4 or float32x4 arguments based on a -// int32x4 argument. -class LSimdSelect : public LInstructionHelper<1, 3, 1> -{ - public: - LIR_HEADER(SimdSelect); - const LAllocation* mask() { - return getOperand(0); - } - const LAllocation* lhs() { - return getOperand(1); - } - const LAllocation* rhs() { - return getOperand(2); - } - const LDefinition* temp() { - return getTemp(0); - } - MSimdSelect* mir() const { - return mir_->toSimdSelect(); - } -}; - -class LSimdAnyTrue : public LInstructionHelper<1, 1, 0> -{ - public: - LIR_HEADER(SimdAnyTrue) - explicit LSimdAnyTrue(const LAllocation& input) { - setOperand(0, input); - } - const LAllocation* vector() { - return getOperand(0); - } - MSimdAnyTrue* mir() const { - return mir_->toSimdAnyTrue(); - } -}; - -class LSimdAllTrue : public LInstructionHelper<1, 1, 0> -{ - public: - LIR_HEADER(SimdAllTrue) - explicit LSimdAllTrue(const LAllocation& input) { - setOperand(0, input); - } - const LAllocation* vector() { - return getOperand(0); - } - MSimdAllTrue* mir() const { - return mir_->toSimdAllTrue(); - } -}; - - // Constant 32-bit integer. class LInteger : public LInstructionHelper<1, 0, 0> { @@ -885,27 +257,6 @@ class LFloat32 : public LInstructionHelper<1, 0, 0> } }; -// Constant 128-bit SIMD integer vector (8x16, 16x8, 32x4). -// Also used for Bool32x4, Bool16x8, etc. -class LSimd128Int : public LInstructionHelper<1, 0, 0> -{ - public: - LIR_HEADER(Simd128Int); - - explicit LSimd128Int() {} - const SimdConstant& getValue() const { return mir_->toSimdConstant()->value(); } -}; - -// Constant 128-bit SIMD floating point vector (32x4, 64x2). -class LSimd128Float : public LInstructionHelper<1, 0, 0> -{ - public: - LIR_HEADER(Simd128Float); - - explicit LSimd128Float() {} - const SimdConstant& getValue() const { return mir_->toSimdConstant()->value(); } -}; - // A constant Value. class LValue : public LInstructionHelper<BOX_PIECES, 0, 0> { @@ -4506,54 +3857,6 @@ class LValueToObjectOrNull : public LInstructionHelper<1, BOX_PIECES, 0> } }; -class LInt32x4ToFloat32x4 : public LInstructionHelper<1, 1, 0> -{ - public: - LIR_HEADER(Int32x4ToFloat32x4); - explicit LInt32x4ToFloat32x4(const LAllocation& input) { - setOperand(0, input); - } -}; - -class LFloat32x4ToInt32x4 : public LInstructionHelper<1, 1, 1> -{ - public: - LIR_HEADER(Float32x4ToInt32x4); - explicit LFloat32x4ToInt32x4(const LAllocation& input, const LDefinition& temp) { - setOperand(0, input); - setTemp(0, temp); - } - const LDefinition* temp() { - return getTemp(0); - } - const MSimdConvert* mir() const { - return mir_->toSimdConvert(); - } -}; - -// Float32x4 to Uint32x4 needs one GPR temp and one FloatReg temp. -class LFloat32x4ToUint32x4 : public LInstructionHelper<1, 1, 2> -{ - public: - LIR_HEADER(Float32x4ToUint32x4); - explicit LFloat32x4ToUint32x4(const LAllocation& input, const LDefinition& tempR, - const LDefinition& tempF) - { - setOperand(0, input); - setTemp(0, tempR); - setTemp(1, tempF); - } - const LDefinition* tempR() { - return getTemp(0); - } - const LDefinition* tempF() { - return getTemp(1); - } - const MSimdConvert* mir() const { - return mir_->toSimdConvert(); - } -}; - // Double raised to a half power. class LPowHalfD : public LInstructionHelper<1, 1, 0> { diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h index 396765fbd0..10c6be0b36 100644 --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -17,44 +17,6 @@ _(Pointer) \ _(Double) \ _(Float32) \ - _(SimdBox) \ - _(SimdUnbox) \ - _(SimdSplatX16) \ - _(SimdSplatX8) \ - _(SimdSplatX4) \ - _(Simd128Int) \ - _(Simd128Float) \ - _(SimdAllTrue) \ - _(SimdAnyTrue) \ - _(SimdReinterpretCast) \ - _(SimdExtractElementI) \ - _(SimdExtractElementU2D) \ - _(SimdExtractElementB) \ - _(SimdExtractElementF) \ - _(SimdInsertElementI) \ - _(SimdInsertElementF) \ - _(SimdGeneralShuffleI) \ - _(SimdGeneralShuffleF) \ - _(SimdSwizzleI) \ - _(SimdSwizzleF) \ - _(SimdShuffle) \ - _(SimdShuffleX4) \ - _(SimdUnaryArithIx16) \ - _(SimdUnaryArithIx8) \ - _(SimdUnaryArithIx4) \ - _(SimdUnaryArithFx4) \ - _(SimdBinaryCompIx16) \ - _(SimdBinaryCompIx8) \ - _(SimdBinaryCompIx4) \ - _(SimdBinaryCompFx4) \ - _(SimdBinaryArithIx16) \ - _(SimdBinaryArithIx8) \ - _(SimdBinaryArithIx4) \ - _(SimdBinaryArithFx4) \ - _(SimdBinarySaturating) \ - _(SimdBinaryBitwise) \ - _(SimdShift) \ - _(SimdSelect) \ _(Value) \ _(CloneLiteral) \ _(Parameter) \ @@ -215,9 +177,6 @@ _(DoubleToString) \ _(ValueToString) \ _(ValueToObjectOrNull) \ - _(Int32x4ToFloat32x4) \ - _(Float32x4ToInt32x4) \ - _(Float32x4ToUint32x4) \ _(Start) \ _(NaNToZero) \ _(OsrEntry) \ diff --git a/js/src/jit/shared/Lowering-shared-inl.h b/js/src/jit/shared/Lowering-shared-inl.h index cdbba9ef84..75869595b5 100644 --- a/js/src/jit/shared/Lowering-shared-inl.h +++ b/js/src/jit/shared/Lowering-shared-inl.h @@ -333,9 +333,6 @@ IsCompatibleLIRCoercion(MIRType to, MIRType from) (from == MIRType::Int32 || from == MIRType::Boolean)) { return true; } - // SIMD types can be coerced with from*Bits operators. - if (IsSimdType(to) && IsSimdType(from)) - return true; return false; } diff --git a/js/src/jit/shared/Lowering-shared.h b/js/src/jit/shared/Lowering-shared.h index 64a32bd1f2..c6b0d8e3c2 100644 --- a/js/src/jit/shared/Lowering-shared.h +++ b/js/src/jit/shared/Lowering-shared.h @@ -271,22 +271,6 @@ class LIRGeneratorShared : public MDefinitionVisitor static bool allowStaticTypedArrayAccesses() { return false; } - - // Provide NYI default implementations of the SIMD visitor functions. - // Many targets don't implement SIMD at all, and we don't want to duplicate - // these stubs in the specific sub-classes. - // Some SIMD visitors are implemented in LIRGenerator in Lowering.cpp. These - // shared implementations are not included here. - void visitSimdInsertElement(MSimdInsertElement*) override { MOZ_CRASH("NYI"); } - void visitSimdExtractElement(MSimdExtractElement*) override { MOZ_CRASH("NYI"); } - void visitSimdBinaryArith(MSimdBinaryArith*) override { MOZ_CRASH("NYI"); } - void visitSimdSelect(MSimdSelect*) override { MOZ_CRASH("NYI"); } - void visitSimdSplat(MSimdSplat*) override { MOZ_CRASH("NYI"); } - void visitSimdValueX4(MSimdValueX4*) override { MOZ_CRASH("NYI"); } - void visitSimdBinarySaturating(MSimdBinarySaturating*) override { MOZ_CRASH("NYI"); } - void visitSimdSwizzle(MSimdSwizzle*) override { MOZ_CRASH("NYI"); } - void visitSimdShuffle(MSimdShuffle*) override { MOZ_CRASH("NYI"); } - void visitSimdGeneralShuffle(MSimdGeneralShuffle*) override { MOZ_CRASH("NYI"); } }; } // namespace jit diff --git a/js/src/jit/x64/Assembler-x64.h b/js/src/jit/x64/Assembler-x64.h index 509b5b5450..fa89237d9c 100644 --- a/js/src/jit/x64/Assembler-x64.h +++ b/js/src/jit/x64/Assembler-x64.h @@ -225,7 +225,9 @@ static_assert(JitStackAlignment % sizeof(Value) == 0 && JitStackValueAlignment > // this architecture or not. Rather than a method in the LIRGenerator, it is // here such that it is accessible from the entire codebase. Once full support // for SIMD is reached on all tier-1 platforms, this constant can be deleted. -static constexpr bool SupportsSimd = true; +// XXX: As of Issue #2307 this is false and will no longer compile with true. +// This should eventually be removed. +static constexpr bool SupportsSimd = false; static constexpr uint32_t SimdMemoryAlignment = 16; static_assert(CodeAlignment % SimdMemoryAlignment == 0, diff --git a/js/src/jit/x64/CodeGenerator-x64.cpp b/js/src/jit/x64/CodeGenerator-x64.cpp index 3f4052f51d..ef0502a489 100644 --- a/js/src/jit/x64/CodeGenerator-x64.cpp +++ b/js/src/jit/x64/CodeGenerator-x64.cpp @@ -416,8 +416,6 @@ CodeGeneratorX64::wasmStore(const wasm::MemoryAccessDesc& access, const LAllocat Operand dstAddr) { if (value->isConstant()) { - MOZ_ASSERT(!access.isSimd()); - masm.memoryBarrier(access.barrierBefore()); const MConstant* mir = value->toConstant(); @@ -440,10 +438,6 @@ CodeGeneratorX64::wasmStore(const wasm::MemoryAccessDesc& access, const LAllocat case Scalar::Int64: case Scalar::Float32: case Scalar::Float64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: case Scalar::Uint8Clamped: case Scalar::BigInt64: case Scalar::BigUint64: @@ -530,7 +524,6 @@ CodeGeneratorX64::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins) const LDefinition* out = ins->output(); Scalar::Type accessType = mir->access().type(); - MOZ_ASSERT(!Scalar::isSimdType(accessType)); Operand srcAddr = ptr->isBogus() ? Operand(HeapReg, mir->offset()) @@ -552,7 +545,6 @@ CodeGeneratorX64::visitAsmJSStoreHeap(LAsmJSStoreHeap* ins) const LAllocation* value = ins->value(); Scalar::Type accessType = mir->access().type(); - MOZ_ASSERT(!Scalar::isSimdType(accessType)); canonicalizeIfDeterministic(accessType, value); diff --git a/js/src/jit/x64/LOpcodes-x64.h b/js/src/jit/x64/LOpcodes-x64.h index a0f4359b35..97fc4dfaed 100644 --- a/js/src/jit/x64/LOpcodes-x64.h +++ b/js/src/jit/x64/LOpcodes-x64.h @@ -14,8 +14,6 @@ _(UDivOrModI64) \ _(WasmTruncateToInt64) \ _(Int64ToFloatingPoint) \ - _(SimdValueInt32x4) \ - _(SimdValueFloat32x4) \ _(UDivOrMod) \ _(UDivOrModConstant) diff --git a/js/src/jit/x64/Lowering-x64.cpp b/js/src/jit/x64/Lowering-x64.cpp index 4aebe05af2..070d5ebd9f 100644 --- a/js/src/jit/x64/Lowering-x64.cpp +++ b/js/src/jit/x64/Lowering-x64.cpp @@ -233,10 +233,6 @@ LIRGeneratorX64::visitWasmStore(MWasmStore* ins) break; case Scalar::Float32: case Scalar::Float64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: valueAlloc = useRegisterAtStart(value); break; case Scalar::BigInt64: @@ -279,10 +275,6 @@ LIRGeneratorX64::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins) break; case Scalar::Float32: case Scalar::Float64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: lir = new(alloc()) LAsmJSStoreHeap(useRegisterOrZeroAtStart(base), useRegisterAtStart(ins->value())); break; diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index 1fab669d2b..6374dd6c64 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -683,34 +683,6 @@ MacroAssembler::wasmLoad(const wasm::MemoryAccessDesc& access, Operand srcAddr, case Scalar::Float64: loadDouble(srcAddr, out.fpu()); break; - case Scalar::Float32x4: - switch (access.numSimdElems()) { - // In memory-to-register mode, movss zeroes out the high lanes. - case 1: loadFloat32(srcAddr, out.fpu()); break; - // See comment above, which also applies to movsd. - case 2: loadDouble(srcAddr, out.fpu()); break; - case 4: loadUnalignedSimd128Float(srcAddr, out.fpu()); break; - default: MOZ_CRASH("unexpected size for partial load"); - } - break; - case Scalar::Int32x4: - switch (access.numSimdElems()) { - // In memory-to-register mode, movd zeroes out the high lanes. - case 1: vmovd(srcAddr, out.fpu()); break; - // See comment above, which also applies to movq. - case 2: vmovq(srcAddr, out.fpu()); break; - case 4: loadUnalignedSimd128Int(srcAddr, out.fpu()); break; - default: MOZ_CRASH("unexpected size for partial load"); - } - break; - case Scalar::Int8x16: - MOZ_ASSERT(access.numSimdElems() == 16, "unexpected partial load"); - loadUnalignedSimd128Int(srcAddr, out.fpu()); - break; - case Scalar::Int16x8: - MOZ_ASSERT(access.numSimdElems() == 8, "unexpected partial load"); - loadUnalignedSimd128Int(srcAddr, out.fpu()); - break; case Scalar::Int64: MOZ_CRASH("int64 loads must use load64"); case Scalar::BigInt64: @@ -728,7 +700,6 @@ void MacroAssembler::wasmLoadI64(const wasm::MemoryAccessDesc& access, Operand srcAddr, Register64 out) { MOZ_ASSERT(!access.isAtomic()); - MOZ_ASSERT(!access.isSimd()); size_t loadOffset = size(); switch (access.type()) { @@ -756,10 +727,6 @@ MacroAssembler::wasmLoadI64(const wasm::MemoryAccessDesc& access, Operand srcAdd break; case Scalar::Float32: case Scalar::Float64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: MOZ_CRASH("non-int64 loads should use load()"); case Scalar::BigInt64: case Scalar::BigUint64: @@ -798,34 +765,6 @@ MacroAssembler::wasmStore(const wasm::MemoryAccessDesc& access, AnyRegister valu case Scalar::Float64: storeUncanonicalizedDouble(value.fpu(), dstAddr); break; - case Scalar::Float32x4: - switch (access.numSimdElems()) { - // In memory-to-register mode, movss zeroes out the high lanes. - case 1: storeUncanonicalizedFloat32(value.fpu(), dstAddr); break; - // See comment above, which also applies to movsd. - case 2: storeUncanonicalizedDouble(value.fpu(), dstAddr); break; - case 4: storeUnalignedSimd128Float(value.fpu(), dstAddr); break; - default: MOZ_CRASH("unexpected size for partial load"); - } - break; - case Scalar::Int32x4: - switch (access.numSimdElems()) { - // In memory-to-register mode, movd zeroes out the high lanes. - case 1: vmovd(value.fpu(), dstAddr); break; - // See comment above, which also applies to movq. - case 2: vmovq(value.fpu(), dstAddr); break; - case 4: storeUnalignedSimd128Int(value.fpu(), dstAddr); break; - default: MOZ_CRASH("unexpected size for partial load"); - } - break; - case Scalar::Int8x16: - MOZ_ASSERT(access.numSimdElems() == 16, "unexpected partial store"); - storeUnalignedSimd128Int(value.fpu(), dstAddr); - break; - case Scalar::Int16x8: - MOZ_ASSERT(access.numSimdElems() == 8, "unexpected partial store"); - storeUnalignedSimd128Int(value.fpu(), dstAddr); - break; case Scalar::BigInt64: case Scalar::BigUint64: case Scalar::Uint8Clamped: diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp index 7e28891a84..704674a4cd 100644 --- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp @@ -299,16 +299,11 @@ CodeGeneratorX86Shared::visitWasmStackArg(LWasmStackArg* ins) case MIRType::Float32: masm.storeFloat32(ToFloatRegister(ins->arg()), dst); return; - // StackPointer is SIMD-aligned and ABIArgGenerator guarantees - // stack offsets are SIMD-aligned. case MIRType::Int32x4: case MIRType::Bool32x4: - masm.storeAlignedSimd128Int(ToFloatRegister(ins->arg()), dst); - return; case MIRType::Float32x4: - masm.storeAlignedSimd128Float(ToFloatRegister(ins->arg()), dst); - return; - default: break; + default: + break; } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected mir type in WasmStackArg"); } @@ -399,10 +394,6 @@ CodeGeneratorX86Shared::visitOutOfLineLoadTypedArrayOutOfBounds(OutOfLineLoadTyp { switch (ool->viewType()) { case Scalar::Int64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: case Scalar::BigInt64: case Scalar::BigUint64: case Scalar::MaxTypedArrayViewType: @@ -2431,873 +2422,6 @@ CodeGeneratorX86Shared::visitNegF(LNegF* ins) } void -CodeGeneratorX86Shared::visitSimd128Int(LSimd128Int* ins) -{ - const LDefinition* out = ins->getDef(0); - masm.loadConstantSimd128Int(ins->getValue(), ToFloatRegister(out)); -} - -void -CodeGeneratorX86Shared::visitSimd128Float(LSimd128Float* ins) -{ - const LDefinition* out = ins->getDef(0); - masm.loadConstantSimd128Float(ins->getValue(), ToFloatRegister(out)); -} - -void -CodeGeneratorX86Shared::visitInt32x4ToFloat32x4(LInt32x4ToFloat32x4* ins) -{ - FloatRegister in = ToFloatRegister(ins->input()); - FloatRegister out = ToFloatRegister(ins->output()); - masm.convertInt32x4ToFloat32x4(in, out); -} - -void -CodeGeneratorX86Shared::visitFloat32x4ToInt32x4(LFloat32x4ToInt32x4* ins) -{ - FloatRegister in = ToFloatRegister(ins->input()); - FloatRegister out = ToFloatRegister(ins->output()); - Register temp = ToRegister(ins->temp()); - - auto* ool = new(alloc()) OutOfLineSimdFloatToIntCheck(temp, in, ins, ins->mir()->trapOffset()); - addOutOfLineCode(ool, ins->mir()); - - masm.checkedConvertFloat32x4ToInt32x4(in, out, temp, ool->entry(), ool->rejoin()); -} - -void -CodeGeneratorX86Shared::visitOutOfLineSimdFloatToIntCheck(OutOfLineSimdFloatToIntCheck* ool) -{ - Label onConversionError; - - masm.oolConvertFloat32x4ToInt32x4(ool->input(), ool->temp(), ool->rejoin(), &onConversionError); - if (gen->compilingWasm()) { - masm.bindLater(&onConversionError, trap(ool, wasm::Trap::ImpreciseSimdConversion)); - } else { - masm.bind(&onConversionError); - bailout(ool->ins()->snapshot()); - } -} - -// Convert Float32x4 to Uint32x4. -// If any input lane value is out of range or NaN, bail out. -void -CodeGeneratorX86Shared::visitFloat32x4ToUint32x4(LFloat32x4ToUint32x4* ins) -{ - FloatRegister in = ToFloatRegister(ins->input()); - FloatRegister out = ToFloatRegister(ins->output()); - Register temp = ToRegister(ins->tempR()); - FloatRegister tempF = ToFloatRegister(ins->tempF()); - - Label failed; - masm.checkedConvertFloat32x4ToUint32x4(in, out, temp, tempF, &failed); - - Label ok; - masm.jump(&ok); - masm.bind(&failed); - if (gen->compilingWasm()) - masm.j(Assembler::NotEqual, trap(ins->mir(), wasm::Trap::ImpreciseSimdConversion)); - else - bailout(ins->snapshot()); - masm.bind(&ok); -} - -void -CodeGeneratorX86Shared::visitSimdValueInt32x4(LSimdValueInt32x4* ins) -{ - MOZ_ASSERT(ins->mir()->type() == MIRType::Int32x4 || ins->mir()->type() == MIRType::Bool32x4); - masm.createInt32x4(ToRegister(ins->getOperand(0)), - ToRegister(ins->getOperand(1)), - ToRegister(ins->getOperand(2)), - ToRegister(ins->getOperand(3)), - ToFloatRegister(ins->output()) - ); -} - -void -CodeGeneratorX86Shared::visitSimdValueFloat32x4(LSimdValueFloat32x4* ins) -{ - MOZ_ASSERT(ins->mir()->type() == MIRType::Float32x4); - - FloatRegister r0 = ToFloatRegister(ins->getOperand(0)); - FloatRegister r1 = ToFloatRegister(ins->getOperand(1)); - FloatRegister r2 = ToFloatRegister(ins->getOperand(2)); - FloatRegister r3 = ToFloatRegister(ins->getOperand(3)); - FloatRegister tmp = ToFloatRegister(ins->getTemp(0)); - FloatRegister output = ToFloatRegister(ins->output()); - - masm.createFloat32x4(r0, r1, r2, r3, tmp, output); -} - -void -CodeGeneratorX86Shared::visitSimdSplatX16(LSimdSplatX16* ins) -{ - MOZ_ASSERT(SimdTypeToLength(ins->mir()->type()) == 16); - Register input = ToRegister(ins->getOperand(0)); - FloatRegister output = ToFloatRegister(ins->output()); - masm.splatX16(input, output); -} - -void -CodeGeneratorX86Shared::visitSimdSplatX8(LSimdSplatX8* ins) -{ - MOZ_ASSERT(SimdTypeToLength(ins->mir()->type()) == 8); - Register input = ToRegister(ins->getOperand(0)); - FloatRegister output = ToFloatRegister(ins->output()); - masm.splatX8(input, output); -} - -void -CodeGeneratorX86Shared::visitSimdSplatX4(LSimdSplatX4* ins) -{ - FloatRegister output = ToFloatRegister(ins->output()); - - MSimdSplat* mir = ins->mir(); - MOZ_ASSERT(IsSimdType(mir->type())); - JS_STATIC_ASSERT(sizeof(float) == sizeof(int32_t)); - - if (mir->type() == MIRType::Float32x4) - masm.splatX4(ToFloatRegister(ins->getOperand(0)), output); - else - masm.splatX4(ToRegister(ins->getOperand(0)), output); -} - -void -CodeGeneratorX86Shared::visitSimdReinterpretCast(LSimdReinterpretCast* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - FloatRegister output = ToFloatRegister(ins->output()); - bool isIntLaneType = IsIntegerSimdType(ins->mir()->type()); - masm.reinterpretSimd(isIntLaneType, input, output); -} - -void -CodeGeneratorX86Shared::visitSimdExtractElementB(LSimdExtractElementB* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - Register output = ToRegister(ins->output()); - MSimdExtractElement* mir = ins->mir(); - unsigned numLanes = SimdTypeToLength(mir->specialization()); - masm.extractLaneSimdBool(input, output, numLanes, mir->lane()); -} - -void -CodeGeneratorX86Shared::visitSimdExtractElementI(LSimdExtractElementI* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - Register output = ToRegister(ins->output()); - MSimdExtractElement* mir = ins->mir(); - unsigned numLanes = SimdTypeToLength(mir->specialization()); - switch (numLanes) { - case 4: - masm.extractLaneInt32x4(input, output, mir->lane()); - break; - case 8: - masm.extractLaneInt16x8(input, output, mir->lane(), mir->signedness()); - break; - case 16: - masm.extractLaneInt8x16(input, output, mir->lane(), mir->signedness()); - break; - default: - MOZ_CRASH("Unhandled SIMD length"); - } -} - -void -CodeGeneratorX86Shared::visitSimdExtractElementU2D(LSimdExtractElementU2D* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - FloatRegister output = ToFloatRegister(ins->output()); - Register temp = ToRegister(ins->temp()); - MSimdExtractElement* mir = ins->mir(); - MOZ_ASSERT(mir->specialization() == MIRType::Int32x4); - masm.extractLaneInt32x4(input, temp, mir->lane()); - masm.convertUInt32ToDouble(temp, output); -} - -void -CodeGeneratorX86Shared::visitSimdExtractElementF(LSimdExtractElementF* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - FloatRegister output = ToFloatRegister(ins->output()); - - unsigned lane = ins->mir()->lane(); - bool canonicalize = !gen->compilingWasm(); - masm.extractLaneFloat32x4(input, output, lane, canonicalize); -} - -void -CodeGeneratorX86Shared::visitSimdInsertElementI(LSimdInsertElementI* ins) -{ - FloatRegister input = ToFloatRegister(ins->vector()); - Register value = ToRegister(ins->value()); - FloatRegister output = ToFloatRegister(ins->output()); - MOZ_ASSERT(input == output); // defineReuseInput(0) - unsigned lane = ins->lane(); - unsigned length = ins->length(); - - masm.insertLaneSimdInt(input, value, output, lane, length); -} - -void -CodeGeneratorX86Shared::visitSimdInsertElementF(LSimdInsertElementF* ins) -{ - FloatRegister input = ToFloatRegister(ins->vector()); - FloatRegister value = ToFloatRegister(ins->value()); - FloatRegister output = ToFloatRegister(ins->output()); - MOZ_ASSERT(input == output); // defineReuseInput(0) - masm.insertLaneFloat32x4(input, value, output, ins->lane()); -} - -void -CodeGeneratorX86Shared::visitSimdAllTrue(LSimdAllTrue* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - Register output = ToRegister(ins->output()); - - masm.allTrueSimdBool(input, output); -} - -void -CodeGeneratorX86Shared::visitSimdAnyTrue(LSimdAnyTrue* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - Register output = ToRegister(ins->output()); - - masm.anyTrueSimdBool(input, output); -} - -// XXX note for reviewer: this is SIMD.js only, no need to keep it for wasm. -template <class T, class Reg> void -CodeGeneratorX86Shared::visitSimdGeneralShuffle(LSimdGeneralShuffleBase* ins, Reg tempRegister) -{ - MSimdGeneralShuffle* mir = ins->mir(); - unsigned numVectors = mir->numVectors(); - - Register laneTemp = ToRegister(ins->temp()); - - // This won't generate fast code, but it's fine because we expect users - // to have used constant indices (and thus MSimdGeneralShuffle to be fold - // into MSimdSwizzle/MSimdShuffle, which are fast). - - // We need stack space for the numVectors inputs and for the output vector. - unsigned stackSpace = Simd128DataSize * (numVectors + 1); - masm.reserveStack(stackSpace); - - for (unsigned i = 0; i < numVectors; i++) { - masm.storeAlignedVector<T>(ToFloatRegister(ins->vector(i)), - Address(StackPointer, Simd128DataSize * (1 + i))); - } - - Label bail; - const Scale laneScale = ScaleFromElemWidth(sizeof(T)); - - for (size_t i = 0; i < mir->numLanes(); i++) { - Operand lane = ToOperand(ins->lane(i)); - - masm.cmp32(lane, Imm32(numVectors * mir->numLanes() - 1)); - masm.j(Assembler::Above, &bail); - - if (lane.kind() == Operand::REG) { - masm.loadScalar<T>(Operand(StackPointer, ToRegister(ins->lane(i)), laneScale, Simd128DataSize), - tempRegister); - } else { - masm.load32(lane, laneTemp); - masm.loadScalar<T>(Operand(StackPointer, laneTemp, laneScale, Simd128DataSize), tempRegister); - } - - masm.storeScalar<T>(tempRegister, Address(StackPointer, i * sizeof(T))); - } - - FloatRegister output = ToFloatRegister(ins->output()); - masm.loadAlignedVector<T>(Address(StackPointer, 0), output); - - Label join; - masm.jump(&join); - - { - masm.bind(&bail); - masm.freeStack(stackSpace); - bailout(ins->snapshot()); - } - - masm.bind(&join); - masm.setFramePushed(masm.framePushed() + stackSpace); - masm.freeStack(stackSpace); -} - -// XXX SIMD.js only -void -CodeGeneratorX86Shared::visitSimdGeneralShuffleI(LSimdGeneralShuffleI* ins) -{ - switch (ins->mir()->type()) { - case MIRType::Int8x16: - return visitSimdGeneralShuffle<int8_t, Register>(ins, ToRegister(ins->temp())); - case MIRType::Int16x8: - return visitSimdGeneralShuffle<int16_t, Register>(ins, ToRegister(ins->temp())); - case MIRType::Int32x4: - return visitSimdGeneralShuffle<int32_t, Register>(ins, ToRegister(ins->temp())); - default: - MOZ_CRASH("unsupported type for general shuffle"); - } -} -void -CodeGeneratorX86Shared::visitSimdGeneralShuffleF(LSimdGeneralShuffleF* ins) -{ - ScratchFloat32Scope scratch(masm); - visitSimdGeneralShuffle<float, FloatRegister>(ins, scratch); -} - -void -CodeGeneratorX86Shared::visitSimdSwizzleI(LSimdSwizzleI* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - FloatRegister output = ToFloatRegister(ins->output()); - const unsigned numLanes = ins->numLanes(); - - switch (numLanes) { - case 4: { - unsigned lanes[4]; - for (unsigned i = 0; i < 4; i++) - lanes[i] = ins->lane(i); - masm.swizzleInt32x4(input, output, lanes); - return; - } - } - - // In the general case, use pshufb if it is available. Convert to a - // byte-wise swizzle. - const unsigned bytesPerLane = 16 / numLanes; - int8_t lanes[16]; - for (unsigned i = 0; i < numLanes; i++) { - for (unsigned b = 0; b < bytesPerLane; b++) { - lanes[i * bytesPerLane + b] = ins->lane(i) * bytesPerLane + b; - } - } - - Maybe<Register> maybeTemp; - if (!ins->getTemp(0)->isBogusTemp()) - maybeTemp.emplace(ToRegister(ins->getTemp(0))); - - masm.swizzleInt8x16(input, output, maybeTemp, lanes); -} - -void -CodeGeneratorX86Shared::visitSimdSwizzleF(LSimdSwizzleF* ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - FloatRegister output = ToFloatRegister(ins->output()); - MOZ_ASSERT(ins->numLanes() == 4); - - unsigned lanes[4]; - for (unsigned i = 0; i < 4; i++) - lanes[i] = ins->lane(i); - masm.swizzleFloat32x4(input, output, lanes); -} - -void -CodeGeneratorX86Shared::visitSimdShuffle(LSimdShuffle* ins) -{ - FloatRegister lhs = ToFloatRegister(ins->lhs()); - FloatRegister rhs = ToFloatRegister(ins->rhs()); - FloatRegister output = ToFloatRegister(ins->output()); - const unsigned numLanes = ins->numLanes(); - const unsigned bytesPerLane = 16 / numLanes; - - // Convert the shuffle to a byte-wise shuffle. - uint8_t lanes[16]; - for (unsigned i = 0; i < numLanes; i++) { - for (unsigned b = 0; b < bytesPerLane; b++) { - lanes[i * bytesPerLane + b] = ins->lane(i) * bytesPerLane + b; - } - } - - Maybe<FloatRegister> maybeFloatTemp; - Maybe<Register> maybeTemp; - if (AssemblerX86Shared::HasSSSE3()) - maybeFloatTemp.emplace(ToFloatRegister(ins->temp())); - else - maybeTemp.emplace(ToRegister(ins->temp())); - - masm.shuffleInt8x16(lhs, rhs, output, maybeFloatTemp, maybeTemp, lanes); -} - -void -CodeGeneratorX86Shared::visitSimdShuffleX4(LSimdShuffleX4* ins) -{ - FloatRegister lhs = ToFloatRegister(ins->lhs()); - Operand rhs = ToOperand(ins->rhs()); - FloatRegister out = ToFloatRegister(ins->output()); - - unsigned lanes[4]; - for (unsigned i = 0; i < 4; i++) - lanes[i] = ins->lane(i); - Maybe<FloatRegister> maybeTemp; - if (!ins->temp()->isBogusTemp()) - maybeTemp.emplace(ToFloatRegister(ins->temp())); - masm.shuffleX4(lhs, rhs, out, maybeTemp, lanes); -} - -static inline Assembler::Condition -ToCondition(MSimdBinaryComp::Operation op) -{ - switch (op) { - case MSimdBinaryComp::greaterThan: return Assembler::GreaterThan; - case MSimdBinaryComp::equal: return Assembler::Equal; - case MSimdBinaryComp::lessThan: return Assembler::LessThan; - case MSimdBinaryComp::notEqual: return Assembler::NotEqual; - case MSimdBinaryComp::greaterThanOrEqual: return Assembler::GreaterThanOrEqual; - case MSimdBinaryComp::lessThanOrEqual: return Assembler::LessThanOrEqual; - } - - MOZ_CRASH("unexpected cond"); -} - -void -CodeGeneratorX86Shared::visitSimdBinaryCompIx16(LSimdBinaryCompIx16* ins) -{ - FloatRegister lhs = ToFloatRegister(ins->lhs()); - Operand rhs = ToOperand(ins->rhs()); - FloatRegister output = ToFloatRegister(ins->output()); - MOZ_ASSERT_IF(!Assembler::HasAVX(), output == lhs); - - masm.compareInt8x16(lhs, rhs, ToCondition(ins->operation()), output); -} - -void -CodeGeneratorX86Shared::visitSimdBinaryCompIx8(LSimdBinaryCompIx8* ins) -{ - FloatRegister lhs = ToFloatRegister(ins->lhs()); - Operand rhs = ToOperand(ins->rhs()); - FloatRegister output = ToFloatRegister(ins->output()); - MOZ_ASSERT_IF(!Assembler::HasAVX(), output == lhs); - - masm.compareInt16x8(lhs, rhs, ToCondition(ins->operation()), output); -} - -void -CodeGeneratorX86Shared::visitSimdBinaryCompIx4(LSimdBinaryCompIx4* ins) -{ - FloatRegister lhs = ToFloatRegister(ins->lhs()); - Operand rhs = ToOperand(ins->rhs()); - MOZ_ASSERT(ToFloatRegister(ins->output()) == lhs); - - masm.compareInt32x4(lhs, rhs, ToCondition(ins->operation()), lhs); -} - -void -CodeGeneratorX86Shared::visitSimdBinaryCompFx4(LSimdBinaryCompFx4* ins) -{ - FloatRegister lhs = ToFloatRegister(ins->lhs()); - Operand rhs = ToOperand(ins->rhs()); - FloatRegister output = ToFloatRegister(ins->output()); - - masm.compareFloat32x4(lhs, rhs, ToCondition(ins->operation()), output); -} - -void -CodeGeneratorX86Shared::visitSimdBinaryArithIx16(LSimdBinaryArithIx16* ins) -{ - FloatRegister lhs = ToFloatRegister(ins->lhs()); - Operand rhs = ToOperand(ins->rhs()); - FloatRegister output = ToFloatRegister(ins->output()); - - MSimdBinaryArith::Operation op = ins->operation(); - switch (op) { - case MSimdBinaryArith::Op_add: - masm.addInt8x16(lhs, rhs, output); - return; - case MSimdBinaryArith::Op_sub: - masm.subInt8x16(lhs, rhs, output); - return; - case MSimdBinaryArith::Op_mul: - // 8x16 mul is a valid operation, but not supported in SSE or AVX. - // The operation is synthesized from 16x8 multiplies by - // MSimdBinaryArith::AddLegalized(). - break; - case MSimdBinaryArith::Op_div: - case MSimdBinaryArith::Op_max: - case MSimdBinaryArith::Op_min: - case MSimdBinaryArith::Op_minNum: - case MSimdBinaryArith::Op_maxNum: - break; - } - MOZ_CRASH("unexpected SIMD op"); -} - -void -CodeGeneratorX86Shared::visitSimdBinaryArithIx8(LSimdBinaryArithIx8* ins) -{ - FloatRegister lhs = ToFloatRegister(ins->lhs()); - Operand rhs = ToOperand(ins->rhs()); - FloatRegister output = ToFloatRegister(ins->output()); - - MSimdBinaryArith::Operation op = ins->operation(); - switch (op) { - case MSimdBinaryArith::Op_add: - masm.addInt16x8(lhs, rhs, output); - return; - case MSimdBinaryArith::Op_sub: - masm.subInt16x8(lhs, rhs, output); - return; - case MSimdBinaryArith::Op_mul: - masm.mulInt16x8(lhs, rhs, output); - return; - case MSimdBinaryArith::Op_div: - case MSimdBinaryArith::Op_max: - case MSimdBinaryArith::Op_min: - case MSimdBinaryArith::Op_minNum: - case MSimdBinaryArith::Op_maxNum: - break; - } - MOZ_CRASH("unexpected SIMD op"); -} - -void -CodeGeneratorX86Shared::visitSimdBinaryArithIx4(LSimdBinaryArithIx4* ins) -{ - FloatRegister lhs = ToFloatRegister(ins->lhs()); - Operand rhs = ToOperand(ins->rhs()); - FloatRegister output = ToFloatRegister(ins->output()); - - MSimdBinaryArith::Operation op = ins->operation(); - switch (op) { - case MSimdBinaryArith::Op_add: - masm.addInt32x4(lhs, rhs, output); - return; - case MSimdBinaryArith::Op_sub: - masm.subInt32x4(lhs, rhs, output); - return; - case MSimdBinaryArith::Op_mul: { - Maybe<FloatRegister> maybeTemp; - if (!AssemblerX86Shared::HasSSE41()) - maybeTemp.emplace(ToFloatRegister(ins->getTemp(0))); - masm.mulInt32x4(lhs, rhs, maybeTemp, output); - return; - } - case MSimdBinaryArith::Op_div: - // x86 doesn't have SIMD i32 div. - break; - case MSimdBinaryArith::Op_max: - // we can do max with a single instruction only if we have SSE4.1 - // using the PMAXSD instruction. - break; - case MSimdBinaryArith::Op_min: - // we can do max with a single instruction only if we have SSE4.1 - // using the PMINSD instruction. - break; - case MSimdBinaryArith::Op_minNum: - case MSimdBinaryArith::Op_maxNum: - break; - } - MOZ_CRASH("unexpected SIMD op"); -} - -void -CodeGeneratorX86Shared::visitSimdBinaryArithFx4(LSimdBinaryArithFx4* ins) -{ - FloatRegister lhs = ToFloatRegister(ins->lhs()); - Operand rhs = ToOperand(ins->rhs()); - FloatRegister output = ToFloatRegister(ins->output()); - - MSimdBinaryArith::Operation op = ins->operation(); - switch (op) { - case MSimdBinaryArith::Op_add: - masm.addFloat32x4(lhs, rhs, output); - return; - case MSimdBinaryArith::Op_sub: - masm.subFloat32x4(lhs, rhs, output); - return; - case MSimdBinaryArith::Op_mul: - masm.mulFloat32x4(lhs, rhs, output); - return; - case MSimdBinaryArith::Op_div: - masm.divFloat32x4(lhs, rhs, output); - return; - case MSimdBinaryArith::Op_max: { - masm.maxFloat32x4(lhs, rhs, ToFloatRegister(ins->temp()), output); - return; - } - case MSimdBinaryArith::Op_min: { - masm.minFloat32x4(lhs, rhs, output); - return; - } - case MSimdBinaryArith::Op_minNum: { - masm.minNumFloat32x4(lhs, rhs, ToFloatRegister(ins->temp()), output); - return; - } - case MSimdBinaryArith::Op_maxNum: { - masm.maxNumFloat32x4(lhs, rhs, ToFloatRegister(ins->temp()), output); - return; - } - } - MOZ_CRASH("unexpected SIMD op"); -} - -void -CodeGeneratorX86Shared::visitSimdBinarySaturating(LSimdBinarySaturating* ins) -{ - FloatRegister lhs = ToFloatRegister(ins->lhs()); - Operand rhs = ToOperand(ins->rhs()); - FloatRegister output = ToFloatRegister(ins->output()); - - SimdSign sign = ins->signedness(); - MOZ_ASSERT(sign != SimdSign::NotApplicable); - - switch (ins->type()) { - case MIRType::Int8x16: - switch (ins->operation()) { - case MSimdBinarySaturating::add: - masm.addSatInt8x16(lhs, rhs, sign, output); - return; - case MSimdBinarySaturating::sub: - masm.subSatInt8x16(lhs, rhs, sign, output); - return; - } - break; - - case MIRType::Int16x8: - switch (ins->operation()) { - case MSimdBinarySaturating::add: - masm.addSatInt16x8(lhs, rhs, sign, output); - return; - case MSimdBinarySaturating::sub: - masm.subSatInt16x8(lhs, rhs, sign, output); - return; - } - break; - - default: - break; - } - MOZ_CRASH("unsupported type for SIMD saturating arithmetic"); -} - -void -CodeGeneratorX86Shared::visitSimdUnaryArithIx16(LSimdUnaryArithIx16* ins) -{ - Operand in = ToOperand(ins->input()); - FloatRegister out = ToFloatRegister(ins->output()); - - switch (ins->operation()) { - case MSimdUnaryArith::neg: - masm.negInt8x16(in, out); - return; - case MSimdUnaryArith::not_: - masm.notInt8x16(in, out);; - return; - case MSimdUnaryArith::abs: - case MSimdUnaryArith::reciprocalApproximation: - case MSimdUnaryArith::reciprocalSqrtApproximation: - case MSimdUnaryArith::sqrt: - break; - } - MOZ_CRASH("unexpected SIMD op"); -} - -void -CodeGeneratorX86Shared::visitSimdUnaryArithIx8(LSimdUnaryArithIx8* ins) -{ - Operand in = ToOperand(ins->input()); - FloatRegister out = ToFloatRegister(ins->output()); - - switch (ins->operation()) { - case MSimdUnaryArith::neg: - masm.negInt16x8(in, out); - return; - case MSimdUnaryArith::not_: - masm.notInt16x8(in, out); - return; - case MSimdUnaryArith::abs: - case MSimdUnaryArith::reciprocalApproximation: - case MSimdUnaryArith::reciprocalSqrtApproximation: - case MSimdUnaryArith::sqrt: - break; - } - MOZ_CRASH("unexpected SIMD op"); -} - -void -CodeGeneratorX86Shared::visitSimdUnaryArithIx4(LSimdUnaryArithIx4* ins) -{ - Operand in = ToOperand(ins->input()); - FloatRegister out = ToFloatRegister(ins->output()); - - switch (ins->operation()) { - case MSimdUnaryArith::neg: - masm.negInt32x4(in, out); - return; - case MSimdUnaryArith::not_: - masm.notInt32x4(in, out); - return; - case MSimdUnaryArith::abs: - case MSimdUnaryArith::reciprocalApproximation: - case MSimdUnaryArith::reciprocalSqrtApproximation: - case MSimdUnaryArith::sqrt: - break; - } - MOZ_CRASH("unexpected SIMD op"); -} - -void -CodeGeneratorX86Shared::visitSimdUnaryArithFx4(LSimdUnaryArithFx4* ins) -{ - Operand in = ToOperand(ins->input()); - FloatRegister out = ToFloatRegister(ins->output()); - - switch (ins->operation()) { - case MSimdUnaryArith::abs: - masm.absFloat32x4(in, out); - return; - case MSimdUnaryArith::neg: - masm.negFloat32x4(in, out); - return; - case MSimdUnaryArith::not_: - masm.notFloat32x4(in, out); - return; - case MSimdUnaryArith::reciprocalApproximation: - masm.packedRcpApproximationFloat32x4(in, out); - return; - case MSimdUnaryArith::reciprocalSqrtApproximation: - masm.packedRcpSqrtApproximationFloat32x4(in, out); - return; - case MSimdUnaryArith::sqrt: - masm.packedSqrtFloat32x4(in, out); - return; - } - MOZ_CRASH("unexpected SIMD op"); -} - -void -CodeGeneratorX86Shared::visitSimdBinaryBitwise(LSimdBinaryBitwise* ins) -{ - FloatRegister lhs = ToFloatRegister(ins->lhs()); - Operand rhs = ToOperand(ins->rhs()); - FloatRegister output = ToFloatRegister(ins->output()); - - MSimdBinaryBitwise::Operation op = ins->operation(); - switch (op) { - case MSimdBinaryBitwise::and_: - if (ins->type() == MIRType::Float32x4) - masm.bitwiseAndFloat32x4(lhs, rhs, output); - else - masm.bitwiseAndSimdInt(lhs, rhs, output); - return; - case MSimdBinaryBitwise::or_: - if (ins->type() == MIRType::Float32x4) - masm.bitwiseOrFloat32x4(lhs, rhs, output); - else - masm.bitwiseOrSimdInt(lhs, rhs, output); - return; - case MSimdBinaryBitwise::xor_: - if (ins->type() == MIRType::Float32x4) - masm.bitwiseXorFloat32x4(lhs, rhs, output); - else - masm.bitwiseXorSimdInt(lhs, rhs, output); - return; - } - MOZ_CRASH("unexpected SIMD bitwise op"); -} - -void -CodeGeneratorX86Shared::visitSimdShift(LSimdShift* ins) -{ - FloatRegister out = ToFloatRegister(ins->output()); - MOZ_ASSERT(ToFloatRegister(ins->vector()) == out); // defineReuseInput(0); - - // Note that SSE doesn't have instructions for shifting 8x16 vectors. - // These shifts are synthesized by the MSimdShift::AddLegalized() function. - const LAllocation* val = ins->value(); - if (val->isConstant()) { - MOZ_ASSERT(ins->temp()->isBogusTemp()); - Imm32 count(uint32_t(ToInt32(val))); - switch (ins->type()) { - case MIRType::Int16x8: - switch (ins->operation()) { - case MSimdShift::lsh: - masm.packedLeftShiftByScalarInt16x8(count, out); - return; - case MSimdShift::rsh: - masm.packedRightShiftByScalarInt16x8(count, out); - return; - case MSimdShift::ursh: - masm.packedUnsignedRightShiftByScalarInt16x8(count, out); - return; - } - break; - case MIRType::Int32x4: - switch (ins->operation()) { - case MSimdShift::lsh: - masm.packedLeftShiftByScalarInt32x4(count, out); - return; - case MSimdShift::rsh: - masm.packedRightShiftByScalarInt32x4(count, out); - return; - case MSimdShift::ursh: - masm.packedUnsignedRightShiftByScalarInt32x4(count, out); - return; - } - break; - default: - MOZ_CRASH("unsupported type for SIMD shifts"); - } - MOZ_CRASH("unexpected SIMD bitwise op"); - } - - Register temp = ToRegister(ins->temp()); - Register count = ToRegister(val); - - switch (ins->type()) { - case MIRType::Int16x8: - switch (ins->operation()) { - case MSimdShift::lsh: - masm.packedLeftShiftByScalarInt16x8(out, count, temp, out); - return; - case MSimdShift::rsh: - masm.packedRightShiftByScalarInt16x8(out, count, temp, out); - return; - case MSimdShift::ursh: - masm.packedUnsignedRightShiftByScalarInt16x8(out, count, temp, out); - return; - } - break; - case MIRType::Int32x4: - switch (ins->operation()) { - case MSimdShift::lsh: - masm.packedLeftShiftByScalarInt32x4(out, count, temp, out); - return; - case MSimdShift::rsh: - masm.packedRightShiftByScalarInt32x4(out, count, temp, out); - return; - case MSimdShift::ursh: - masm.packedUnsignedRightShiftByScalarInt32x4(out, count, temp, out); - return; - } - break; - default: - MOZ_CRASH("unsupported type for SIMD shifts"); - } - MOZ_CRASH("unexpected SIMD bitwise op"); -} - -void -CodeGeneratorX86Shared::visitSimdSelect(LSimdSelect* ins) -{ - FloatRegister mask = ToFloatRegister(ins->mask()); - FloatRegister onTrue = ToFloatRegister(ins->lhs()); - FloatRegister onFalse = ToFloatRegister(ins->rhs()); - FloatRegister output = ToFloatRegister(ins->output()); - FloatRegister temp = ToFloatRegister(ins->temp()); - - MSimdSelect* mir = ins->mir(); - unsigned lanes = SimdTypeToLength(mir->type()); - if (lanes == 4) - masm.selectX4(mask, onTrue, onFalse, temp, output); - else - masm.selectSimd128(mask, onTrue, onFalse, temp, output); -} - -void CodeGeneratorX86Shared::visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir) { Register elements = ToRegister(lir->elements()); @@ -3717,15 +2841,6 @@ CodeGeneratorX86Shared::canonicalizeIfDeterministic(Scalar::Type type, const LAl masm.canonicalizeDoubleIfDeterministic(in); break; } - case Scalar::Float32x4: { - FloatRegister in = ToFloatRegister(value); - MOZ_ASSERT(in.isSimd128()); - FloatRegister scratch = in != xmm0.asSimd128() ? xmm0 : xmm1; - masm.push(scratch); - masm.canonicalizeFloat32x4(in, scratch); - masm.pop(scratch); - break; - } default: { // Other types don't need canonicalization. break; diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.h b/js/src/jit/x86-shared/CodeGenerator-x86-shared.h index 4b0664fb63..d990f662c4 100644 --- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.h +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.h @@ -49,31 +49,6 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared } }; - // Additional bounds check for vector Float to Int conversion, when the - // undefined pattern is seen. Might imply a bailout. - class OutOfLineSimdFloatToIntCheck : public OutOfLineCodeBase<CodeGeneratorX86Shared> - { - Register temp_; - FloatRegister input_; - LInstruction* ins_; - wasm::TrapOffset trapOffset_; - - public: - OutOfLineSimdFloatToIntCheck(Register temp, FloatRegister input, LInstruction *ins, - wasm::TrapOffset trapOffset) - : temp_(temp), input_(input), ins_(ins), trapOffset_(trapOffset) - {} - - Register temp() const { return temp_; } - FloatRegister input() const { return input_; } - LInstruction* ins() const { return ins_; } - wasm::TrapOffset trapOffset() const { return trapOffset_; } - - void accept(CodeGeneratorX86Shared* codegen) { - codegen->visitOutOfLineSimdFloatToIntCheck(this); - } - }; - public: NonAssertingLabel deoptLabel_; @@ -258,51 +233,6 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared void visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool); - // SIMD operators - void visitSimdValueInt32x4(LSimdValueInt32x4* lir); - void visitSimdValueFloat32x4(LSimdValueFloat32x4* lir); - void visitSimdSplatX16(LSimdSplatX16* lir); - void visitSimdSplatX8(LSimdSplatX8* lir); - void visitSimdSplatX4(LSimdSplatX4* lir); - void visitSimd128Int(LSimd128Int* ins); - void visitSimd128Float(LSimd128Float* ins); - void visitInt32x4ToFloat32x4(LInt32x4ToFloat32x4* ins); - void visitFloat32x4ToInt32x4(LFloat32x4ToInt32x4* ins); - void visitFloat32x4ToUint32x4(LFloat32x4ToUint32x4* ins); - void visitSimdReinterpretCast(LSimdReinterpretCast* lir); - void visitSimdExtractElementB(LSimdExtractElementB* lir); - void visitSimdExtractElementI(LSimdExtractElementI* lir); - void visitSimdExtractElementU2D(LSimdExtractElementU2D* lir); - void visitSimdExtractElementF(LSimdExtractElementF* lir); - void visitSimdInsertElementI(LSimdInsertElementI* lir); - void visitSimdInsertElementF(LSimdInsertElementF* lir); - void visitSimdSwizzleI(LSimdSwizzleI* lir); - void visitSimdSwizzleF(LSimdSwizzleF* lir); - void visitSimdShuffleX4(LSimdShuffleX4* lir); - void visitSimdShuffle(LSimdShuffle* lir); - void visitSimdUnaryArithIx16(LSimdUnaryArithIx16* lir); - void visitSimdUnaryArithIx8(LSimdUnaryArithIx8* lir); - void visitSimdUnaryArithIx4(LSimdUnaryArithIx4* lir); - void visitSimdUnaryArithFx4(LSimdUnaryArithFx4* lir); - void visitSimdBinaryCompIx16(LSimdBinaryCompIx16* lir); - void visitSimdBinaryCompIx8(LSimdBinaryCompIx8* lir); - void visitSimdBinaryCompIx4(LSimdBinaryCompIx4* lir); - void visitSimdBinaryCompFx4(LSimdBinaryCompFx4* lir); - void visitSimdBinaryArithIx16(LSimdBinaryArithIx16* lir); - void visitSimdBinaryArithIx8(LSimdBinaryArithIx8* lir); - void visitSimdBinaryArithIx4(LSimdBinaryArithIx4* lir); - void visitSimdBinaryArithFx4(LSimdBinaryArithFx4* lir); - void visitSimdBinarySaturating(LSimdBinarySaturating* lir); - void visitSimdBinaryBitwise(LSimdBinaryBitwise* lir); - void visitSimdShift(LSimdShift* lir); - void visitSimdSelect(LSimdSelect* ins); - void visitSimdAllTrue(LSimdAllTrue* ins); - void visitSimdAnyTrue(LSimdAnyTrue* ins); - - template <class T, class Reg> void visitSimdGeneralShuffle(LSimdGeneralShuffleBase* lir, Reg temp); - void visitSimdGeneralShuffleI(LSimdGeneralShuffleI* lir); - void visitSimdGeneralShuffleF(LSimdGeneralShuffleF* lir); - // Out of line visitors. void visitOutOfLineBailout(OutOfLineBailout* ool); void visitOutOfLineUndoALUOperation(OutOfLineUndoALUOperation* ool); @@ -310,7 +240,6 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared void visitModOverflowCheck(ModOverflowCheck* ool); void visitReturnZero(ReturnZero* ool); void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool); - void visitOutOfLineSimdFloatToIntCheck(OutOfLineSimdFloatToIntCheck* ool); void generateInvalidateEpilogue(); // Generating a result. diff --git a/js/src/jit/x86-shared/LIR-x86-shared.h b/js/src/jit/x86-shared/LIR-x86-shared.h index 7bd7414118..415e9f774a 100644 --- a/js/src/jit/x86-shared/LIR-x86-shared.h +++ b/js/src/jit/x86-shared/LIR-x86-shared.h @@ -354,47 +354,6 @@ class LMulI : public LBinaryMath<0, 1> } }; -// Constructs an int32x4 SIMD value. -class LSimdValueInt32x4 : public LInstructionHelper<1, 4, 0> -{ - public: - LIR_HEADER(SimdValueInt32x4) - LSimdValueInt32x4(const LAllocation& x, const LAllocation& y, - const LAllocation& z, const LAllocation& w) - { - setOperand(0, x); - setOperand(1, y); - setOperand(2, z); - setOperand(3, w); - } - - MSimdValueX4* mir() const { - return mir_->toSimdValueX4(); - } -}; - -// Constructs a float32x4 SIMD value, optimized for x86 family -class LSimdValueFloat32x4 : public LInstructionHelper<1, 4, 1> -{ - public: - LIR_HEADER(SimdValueFloat32x4) - LSimdValueFloat32x4(const LAllocation& x, const LAllocation& y, - const LAllocation& z, const LAllocation& w, - const LDefinition& copyY) - { - setOperand(0, x); - setOperand(1, y); - setOperand(2, z); - setOperand(3, w); - - setTemp(0, copyY); - } - - MSimdValueX4* mir() const { - return mir_->toSimdValueX4(); - } -}; - class LInt64ToFloatingPoint : public LInstructionHelper<1, INT64_PIECES, 1> { public: diff --git a/js/src/jit/x86-shared/Lowering-x86-shared.cpp b/js/src/jit/x86-shared/Lowering-x86-shared.cpp index 0a9a9cc55d..161f3634e9 100644 --- a/js/src/jit/x86-shared/Lowering-x86-shared.cpp +++ b/js/src/jit/x86-shared/Lowering-x86-shared.cpp @@ -157,31 +157,6 @@ template void LIRGeneratorX86Shared::lowerForFPU(LInstructionHelper<1, 2, 1>* in MDefinition* lhs, MDefinition* rhs); void -LIRGeneratorX86Shared::lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir, MDefinition* lhs, MDefinition* rhs) -{ - lowerForALU(ins, mir, lhs, rhs); -} - -void -LIRGeneratorX86Shared::lowerForCompFx4(LSimdBinaryCompFx4* ins, MSimdBinaryComp* mir, MDefinition* lhs, MDefinition* rhs) -{ - // Swap the operands around to fit the instructions that x86 actually has. - // We do this here, before register allocation, so that we don't need - // temporaries and copying afterwards. - switch (mir->operation()) { - case MSimdBinaryComp::greaterThan: - case MSimdBinaryComp::greaterThanOrEqual: - mir->reverse(); - Swap(lhs, rhs); - break; - default: - break; - } - - lowerForFPU(ins, mir, lhs, rhs); -} - -void LIRGeneratorX86Shared::lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir, MDefinition* lhs, MDefinition* rhs) { @@ -643,356 +618,6 @@ LIRGeneratorX86Shared::lowerAtomicTypedArrayElementBinop(MAtomicTypedArrayElemen } void -LIRGeneratorX86Shared::visitSimdInsertElement(MSimdInsertElement* ins) -{ - MOZ_ASSERT(IsSimdType(ins->type())); - - LUse vec = useRegisterAtStart(ins->vector()); - LUse val = useRegister(ins->value()); - switch (ins->type()) { - case MIRType::Int8x16: - case MIRType::Bool8x16: - // When SSE 4.1 is not available, we need to go via the stack. - // This requires the value to be inserted to be in %eax-%edx. - // Pick %ebx since other instructions use %eax or %ecx hard-wired. -#if defined(JS_CODEGEN_X86) - if (!AssemblerX86Shared::HasSSE41()) - val = useFixed(ins->value(), ebx); -#endif - defineReuseInput(new(alloc()) LSimdInsertElementI(vec, val), ins, 0); - break; - case MIRType::Int16x8: - case MIRType::Int32x4: - case MIRType::Bool16x8: - case MIRType::Bool32x4: - defineReuseInput(new(alloc()) LSimdInsertElementI(vec, val), ins, 0); - break; - case MIRType::Float32x4: - defineReuseInput(new(alloc()) LSimdInsertElementF(vec, val), ins, 0); - break; - default: - MOZ_CRASH("Unknown SIMD kind when generating constant"); - } -} - -void -LIRGeneratorX86Shared::visitSimdExtractElement(MSimdExtractElement* ins) -{ - MOZ_ASSERT(IsSimdType(ins->input()->type())); - MOZ_ASSERT(!IsSimdType(ins->type())); - - switch (ins->input()->type()) { - case MIRType::Int8x16: - case MIRType::Int16x8: - case MIRType::Int32x4: { - MOZ_ASSERT(ins->signedness() != SimdSign::NotApplicable); - LUse use = useRegisterAtStart(ins->input()); - if (ins->type() == MIRType::Double) { - // Extract an Uint32 lane into a double. - MOZ_ASSERT(ins->signedness() == SimdSign::Unsigned); - define(new (alloc()) LSimdExtractElementU2D(use, temp()), ins); - } else { - auto* lir = new (alloc()) LSimdExtractElementI(use); -#if defined(JS_CODEGEN_X86) - // On x86 (32-bit), we may need to use movsbl or movzbl instructions - // to sign or zero extend the extracted lane to 32 bits. The 8-bit - // version of these instructions require a source register that is - // %al, %bl, %cl, or %dl. - // Fix it to %ebx since we can't express that constraint better. - if (ins->input()->type() == MIRType::Int8x16) { - defineFixed(lir, ins, LAllocation(AnyRegister(ebx))); - return; - } -#endif - define(lir, ins); - } - break; - } - case MIRType::Float32x4: { - MOZ_ASSERT(ins->signedness() == SimdSign::NotApplicable); - LUse use = useRegisterAtStart(ins->input()); - define(new(alloc()) LSimdExtractElementF(use), ins); - break; - } - case MIRType::Bool8x16: - case MIRType::Bool16x8: - case MIRType::Bool32x4: { - MOZ_ASSERT(ins->signedness() == SimdSign::NotApplicable); - LUse use = useRegisterAtStart(ins->input()); - define(new(alloc()) LSimdExtractElementB(use), ins); - break; - } - default: - MOZ_CRASH("Unknown SIMD kind when extracting element"); - } -} - -void -LIRGeneratorX86Shared::visitSimdBinaryArith(MSimdBinaryArith* ins) -{ - MOZ_ASSERT(IsSimdType(ins->lhs()->type())); - MOZ_ASSERT(IsSimdType(ins->rhs()->type())); - MOZ_ASSERT(IsSimdType(ins->type())); - - MDefinition* lhs = ins->lhs(); - MDefinition* rhs = ins->rhs(); - - if (ins->isCommutative()) - ReorderCommutative(&lhs, &rhs, ins); - - switch (ins->type()) { - case MIRType::Int8x16: { - LSimdBinaryArithIx16* lir = new (alloc()) LSimdBinaryArithIx16(); - lir->setTemp(0, LDefinition::BogusTemp()); - lowerForFPU(lir, ins, lhs, rhs); - return; - } - - case MIRType::Int16x8: { - LSimdBinaryArithIx8* lir = new (alloc()) LSimdBinaryArithIx8(); - lir->setTemp(0, LDefinition::BogusTemp()); - lowerForFPU(lir, ins, lhs, rhs); - return; - } - - case MIRType::Int32x4: { - LSimdBinaryArithIx4* lir = new (alloc()) LSimdBinaryArithIx4(); - bool needsTemp = - ins->operation() == MSimdBinaryArith::Op_mul && !MacroAssembler::HasSSE41(); - lir->setTemp(0, needsTemp ? temp(LDefinition::SIMD128INT) : LDefinition::BogusTemp()); - lowerForFPU(lir, ins, lhs, rhs); - return; - } - - case MIRType::Float32x4: { - LSimdBinaryArithFx4* lir = new (alloc()) LSimdBinaryArithFx4(); - - bool needsTemp = ins->operation() == MSimdBinaryArith::Op_max || - ins->operation() == MSimdBinaryArith::Op_minNum || - ins->operation() == MSimdBinaryArith::Op_maxNum; - lir->setTemp(0, - needsTemp ? temp(LDefinition::SIMD128FLOAT) : LDefinition::BogusTemp()); - lowerForFPU(lir, ins, lhs, rhs); - return; - } - - default: - MOZ_CRASH("unknown simd type on binary arith operation"); - } -} - -void -LIRGeneratorX86Shared::visitSimdBinarySaturating(MSimdBinarySaturating* ins) -{ - MOZ_ASSERT(IsSimdType(ins->lhs()->type())); - MOZ_ASSERT(IsSimdType(ins->rhs()->type())); - MOZ_ASSERT(IsSimdType(ins->type())); - - MDefinition* lhs = ins->lhs(); - MDefinition* rhs = ins->rhs(); - - if (ins->isCommutative()) - ReorderCommutative(&lhs, &rhs, ins); - - LSimdBinarySaturating* lir = new (alloc()) LSimdBinarySaturating(); - lowerForFPU(lir, ins, lhs, rhs); -} - -void -LIRGeneratorX86Shared::visitSimdSelect(MSimdSelect* ins) -{ - MOZ_ASSERT(IsSimdType(ins->type())); - - LSimdSelect* lins = new(alloc()) LSimdSelect; - MDefinition* r0 = ins->getOperand(0); - MDefinition* r1 = ins->getOperand(1); - MDefinition* r2 = ins->getOperand(2); - - lins->setOperand(0, useRegister(r0)); - lins->setOperand(1, useRegister(r1)); - lins->setOperand(2, useRegister(r2)); - lins->setTemp(0, temp(LDefinition::SIMD128FLOAT)); - - define(lins, ins); -} - -void -LIRGeneratorX86Shared::visitSimdSplat(MSimdSplat* ins) -{ - LAllocation x = useRegisterAtStart(ins->getOperand(0)); - - switch (ins->type()) { - case MIRType::Int8x16: - define(new (alloc()) LSimdSplatX16(x), ins); - break; - case MIRType::Int16x8: - define(new (alloc()) LSimdSplatX8(x), ins); - break; - case MIRType::Int32x4: - case MIRType::Float32x4: - case MIRType::Bool8x16: - case MIRType::Bool16x8: - case MIRType::Bool32x4: - // Use the SplatX4 instruction for all boolean splats. Since the input - // value is a 32-bit int that is either 0 or -1, the X4 splat gives - // the right result for all boolean geometries. - // For floats, (Non-AVX) codegen actually wants the input and the output - // to be in the same register, but we can't currently use - // defineReuseInput because they have different types (scalar vs - // vector), so a spill slot for one may not be suitable for the other. - define(new (alloc()) LSimdSplatX4(x), ins); - break; - default: - MOZ_CRASH("Unknown SIMD kind"); - } -} - -void -LIRGeneratorX86Shared::visitSimdValueX4(MSimdValueX4* ins) -{ - switch (ins->type()) { - case MIRType::Float32x4: { - // Ideally, x would be used at start and reused for the output, however - // register allocation currently doesn't permit us to tie together two - // virtual registers with different types. - LAllocation x = useRegister(ins->getOperand(0)); - LAllocation y = useRegister(ins->getOperand(1)); - LAllocation z = useRegister(ins->getOperand(2)); - LAllocation w = useRegister(ins->getOperand(3)); - LDefinition t = temp(LDefinition::SIMD128FLOAT); - define(new (alloc()) LSimdValueFloat32x4(x, y, z, w, t), ins); - break; - } - case MIRType::Bool32x4: - case MIRType::Int32x4: { - // No defineReuseInput => useAtStart for everyone. - LAllocation x = useRegisterAtStart(ins->getOperand(0)); - LAllocation y = useRegisterAtStart(ins->getOperand(1)); - LAllocation z = useRegisterAtStart(ins->getOperand(2)); - LAllocation w = useRegisterAtStart(ins->getOperand(3)); - define(new(alloc()) LSimdValueInt32x4(x, y, z, w), ins); - break; - } - default: - MOZ_CRASH("Unknown SIMD kind"); - } -} - -void -LIRGeneratorX86Shared::visitSimdSwizzle(MSimdSwizzle* ins) -{ - MOZ_ASSERT(IsSimdType(ins->input()->type())); - MOZ_ASSERT(IsSimdType(ins->type())); - - if (IsIntegerSimdType(ins->input()->type())) { - LUse use = useRegisterAtStart(ins->input()); - LSimdSwizzleI* lir = new (alloc()) LSimdSwizzleI(use); - define(lir, ins); - // We need a GPR temp register for pre-SSSE3 codegen (no vpshufb). - if (Assembler::HasSSSE3()) { - lir->setTemp(0, LDefinition::BogusTemp()); - } else { - // The temp must be a GPR usable with 8-bit loads and stores. -#if defined(JS_CODEGEN_X86) - lir->setTemp(0, tempFixed(ebx)); -#else - lir->setTemp(0, temp()); -#endif - } - } else if (ins->input()->type() == MIRType::Float32x4) { - LUse use = useRegisterAtStart(ins->input()); - LSimdSwizzleF* lir = new (alloc()) LSimdSwizzleF(use); - define(lir, ins); - lir->setTemp(0, LDefinition::BogusTemp()); - } else { - MOZ_CRASH("Unknown SIMD kind when getting lane"); - } -} - -void -LIRGeneratorX86Shared::visitSimdShuffle(MSimdShuffle* ins) -{ - MOZ_ASSERT(IsSimdType(ins->lhs()->type())); - MOZ_ASSERT(IsSimdType(ins->rhs()->type())); - MOZ_ASSERT(IsSimdType(ins->type())); - if (ins->type() == MIRType::Int32x4 || ins->type() == MIRType::Float32x4) { - bool zFromLHS = ins->lane(2) < 4; - bool wFromLHS = ins->lane(3) < 4; - uint32_t lanesFromLHS = (ins->lane(0) < 4) + (ins->lane(1) < 4) + zFromLHS + wFromLHS; - - LSimdShuffleX4* lir = new (alloc()) LSimdShuffleX4(); - lowerForFPU(lir, ins, ins->lhs(), ins->rhs()); - - // See codegen for requirements details. - LDefinition temp = - (lanesFromLHS == 3) ? tempCopy(ins->rhs(), 1) : LDefinition::BogusTemp(); - lir->setTemp(0, temp); - } else { - MOZ_ASSERT(ins->type() == MIRType::Int8x16 || ins->type() == MIRType::Int16x8); - LSimdShuffle* lir = new (alloc()) LSimdShuffle(); - lir->setOperand(0, useRegister(ins->lhs())); - lir->setOperand(1, useRegister(ins->rhs())); - define(lir, ins); - // We need a GPR temp register for pre-SSSE3 codegen, and an SSE temp - // when using pshufb. - if (Assembler::HasSSSE3()) { - lir->setTemp(0, temp(LDefinition::SIMD128INT)); - } else { - // The temp must be a GPR usable with 8-bit loads and stores. -#if defined(JS_CODEGEN_X86) - lir->setTemp(0, tempFixed(ebx)); -#else - lir->setTemp(0, temp()); -#endif - } - } -} - -void -LIRGeneratorX86Shared::visitSimdGeneralShuffle(MSimdGeneralShuffle* ins) -{ - MOZ_ASSERT(IsSimdType(ins->type())); - - LSimdGeneralShuffleBase* lir; - if (IsIntegerSimdType(ins->type())) { -#if defined(JS_CODEGEN_X86) - // The temp register must be usable with 8-bit load and store - // instructions, so one of %eax-%edx. - LDefinition t; - if (ins->type() == MIRType::Int8x16) - t = tempFixed(ebx); - else - t = temp(); -#else - LDefinition t = temp(); -#endif - lir = new (alloc()) LSimdGeneralShuffleI(t); - } else if (ins->type() == MIRType::Float32x4) { - lir = new (alloc()) LSimdGeneralShuffleF(temp()); - } else { - MOZ_CRASH("Unknown SIMD kind when doing a shuffle"); - } - - if (!lir->init(alloc(), ins->numVectors() + ins->numLanes())) - return; - - for (unsigned i = 0; i < ins->numVectors(); i++) { - MOZ_ASSERT(IsSimdType(ins->vector(i)->type())); - lir->setOperand(i, useRegister(ins->vector(i))); - } - - for (unsigned i = 0; i < ins->numLanes(); i++) { - MOZ_ASSERT(ins->lane(i)->type() == MIRType::Int32); - // Note that there can be up to 16 lane arguments, so we can't assume - // that they all get an allocated register. - lir->setOperand(i + ins->numVectors(), use(ins->lane(i))); - } - - assignSnapshot(lir, Bailout_BoundsCheck); - define(lir, ins); -} - -void LIRGeneratorX86Shared::visitCopySign(MCopySign* ins) { MDefinition* lhs = ins->lhs(); diff --git a/js/src/jit/x86-shared/Lowering-x86-shared.h b/js/src/jit/x86-shared/Lowering-x86-shared.h index fc76203fe2..515de50503 100644 --- a/js/src/jit/x86-shared/Lowering-x86-shared.h +++ b/js/src/jit/x86-shared/Lowering-x86-shared.h @@ -38,10 +38,6 @@ class LIRGeneratorX86Shared : public LIRGeneratorShared template<size_t Temps> void lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir, MDefinition* lhs, MDefinition* rhs); - void lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir, - MDefinition* lhs, MDefinition* rhs); - void lowerForCompFx4(LSimdBinaryCompFx4* ins, MSimdBinaryComp* mir, - MDefinition* lhs, MDefinition* rhs); void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir, MDefinition* lhs, MDefinition* rhs); void visitAsmJSNeg(MAsmJSNeg* ins); @@ -55,16 +51,6 @@ class LIRGeneratorX86Shared : public LIRGeneratorShared void lowerUrshD(MUrsh* mir); void lowerTruncateDToInt32(MTruncateToInt32* ins); void lowerTruncateFToInt32(MTruncateToInt32* ins); - void visitSimdInsertElement(MSimdInsertElement* ins); - void visitSimdExtractElement(MSimdExtractElement* ins); - void visitSimdBinaryArith(MSimdBinaryArith* ins); - void visitSimdBinarySaturating(MSimdBinarySaturating* ins); - void visitSimdSelect(MSimdSelect* ins); - void visitSimdSplat(MSimdSplat* ins); - void visitSimdSwizzle(MSimdSwizzle* ins); - void visitSimdShuffle(MSimdShuffle* ins); - void visitSimdGeneralShuffle(MSimdGeneralShuffle* ins); - void visitSimdValueX4(MSimdValueX4* ins); void lowerCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins, bool useI386ByteRegisters); void lowerAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins, diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h index f308e41fd8..902731f2b4 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -1106,29 +1106,6 @@ MacroAssembler::branchTestMagicImpl(Condition cond, const T& t, L label) } // ======================================================================== -// Canonicalization primitives. -void -MacroAssembler::canonicalizeFloat32x4(FloatRegister reg, FloatRegister scratch) -{ - ScratchSimd128Scope scratch2(*this); - - MOZ_ASSERT(scratch.asSimd128() != scratch2.asSimd128()); - MOZ_ASSERT(reg.asSimd128() != scratch2.asSimd128()); - MOZ_ASSERT(reg.asSimd128() != scratch.asSimd128()); - - FloatRegister mask = scratch; - vcmpordps(Operand(reg), reg, mask); - - FloatRegister ifFalse = scratch2; - float nanf = float(JS::GenericNaN()); - loadConstantSimd128Float(SimdConstant::SplatX4(nanf), ifFalse); - - bitwiseAndFloat32x4(reg, Operand(mask), reg); - bitwiseAndNotFloat32x4(mask, Operand(ifFalse), mask); - bitwiseOrFloat32x4(reg, Operand(mask), reg); -} - -// ======================================================================== // Memory access primitives. void MacroAssembler::storeUncanonicalizedDouble(FloatRegister src, const Address& dest) diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h index 25b3b846da..0afd4ae6bd 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h @@ -1015,37 +1015,6 @@ class MacroAssemblerX86Shared : public Assembler template <class T> inline void loadAlignedVector(const Address& src, FloatRegister dest); template <class T> inline void storeAlignedVector(FloatRegister src, const Address& dest); - void loadInt32x1(const Address& src, FloatRegister dest) { - vmovd(Operand(src), dest); - } - void loadInt32x1(const BaseIndex& src, FloatRegister dest) { - vmovd(Operand(src), dest); - } - void loadInt32x2(const Address& src, FloatRegister dest) { - vmovq(Operand(src), dest); - } - void loadInt32x2(const BaseIndex& src, FloatRegister dest) { - vmovq(Operand(src), dest); - } - void loadInt32x3(const BaseIndex& src, FloatRegister dest) { - BaseIndex srcZ(src); - srcZ.offset += 2 * sizeof(int32_t); - - ScratchSimd128Scope scratch(asMasm()); - vmovq(Operand(src), dest); - vmovd(Operand(srcZ), scratch); - vmovlhps(scratch, dest, dest); - } - void loadInt32x3(const Address& src, FloatRegister dest) { - Address srcZ(src); - srcZ.offset += 2 * sizeof(int32_t); - - ScratchSimd128Scope scratch(asMasm()); - vmovq(Operand(src), dest); - vmovd(Operand(srcZ), scratch); - vmovlhps(scratch, dest, dest); - } - void loadAlignedSimd128Int(const Address& src, FloatRegister dest) { vmovdqa(Operand(src), dest); } @@ -1080,35 +1049,6 @@ class MacroAssemblerX86Shared : public Assembler vmovdqu(src, dest); } - void storeInt32x1(FloatRegister src, const Address& dest) { - vmovd(src, Operand(dest)); - } - void storeInt32x1(FloatRegister src, const BaseIndex& dest) { - vmovd(src, Operand(dest)); - } - void storeInt32x2(FloatRegister src, const Address& dest) { - vmovq(src, Operand(dest)); - } - void storeInt32x2(FloatRegister src, const BaseIndex& dest) { - vmovq(src, Operand(dest)); - } - void storeInt32x3(FloatRegister src, const Address& dest) { - Address destZ(dest); - destZ.offset += 2 * sizeof(int32_t); - vmovq(src, Operand(dest)); - ScratchSimd128Scope scratch(asMasm()); - vmovhlps(src, scratch, scratch); - vmovd(scratch, Operand(destZ)); - } - void storeInt32x3(FloatRegister src, const BaseIndex& dest) { - BaseIndex destZ(dest); - destZ.offset += 2 * sizeof(int32_t); - vmovq(src, Operand(dest)); - ScratchSimd128Scope scratch(asMasm()); - vmovhlps(src, scratch, scratch); - vmovd(scratch, Operand(destZ)); - } - void storeUnalignedSimd128Int(FloatRegister src, const Address& dest) { vmovdqu(src, Operand(dest)); } @@ -1191,23 +1131,6 @@ class MacroAssemblerX86Shared : public Assembler vpsrld(count, dest, dest); } - void loadFloat32x3(const Address& src, FloatRegister dest) { - Address srcZ(src); - srcZ.offset += 2 * sizeof(float); - vmovsd(src, dest); - ScratchSimd128Scope scratch(asMasm()); - vmovss(srcZ, scratch); - vmovlhps(scratch, dest, dest); - } - void loadFloat32x3(const BaseIndex& src, FloatRegister dest) { - BaseIndex srcZ(src); - srcZ.offset += 2 * sizeof(float); - vmovsd(src, dest); - ScratchSimd128Scope scratch(asMasm()); - vmovss(srcZ, scratch); - vmovlhps(scratch, dest, dest); - } - void loadAlignedSimd128Float(const Address& src, FloatRegister dest) { vmovaps(Operand(src), dest); } diff --git a/js/src/jit/x86/Assembler-x86.h b/js/src/jit/x86/Assembler-x86.h index 39460b5676..2e9c6b88f2 100644 --- a/js/src/jit/x86/Assembler-x86.h +++ b/js/src/jit/x86/Assembler-x86.h @@ -143,7 +143,9 @@ static_assert(JitStackAlignment % sizeof(Value) == 0 && JitStackValueAlignment > // this architecture or not. Rather than a method in the LIRGenerator, it is // here such that it is accessible from the entire codebase. Once full support // for SIMD is reached on all tier-1 platforms, this constant can be deleted. -static constexpr bool SupportsSimd = true; +// XXX: As of issue #2307 this is set to false and will no longer compile. +// to-do: remove this. +static constexpr bool SupportsSimd = false; static constexpr uint32_t SimdMemoryAlignment = 16; static_assert(CodeAlignment % SimdMemoryAlignment == 0, diff --git a/js/src/jit/x86/CodeGenerator-x86.cpp b/js/src/jit/x86/CodeGenerator-x86.cpp index 7e90076a26..f255ed362b 100644 --- a/js/src/jit/x86/CodeGenerator-x86.cpp +++ b/js/src/jit/x86/CodeGenerator-x86.cpp @@ -419,7 +419,6 @@ CodeGeneratorX86::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins) AnyRegister out = ToAnyRegister(ins->output()); Scalar::Type accessType = mir->accessType(); - MOZ_ASSERT(!Scalar::isSimdType(accessType)); OutOfLineLoadTypedArrayOutOfBounds* ool = nullptr; if (mir->needsBoundsCheck()) { @@ -498,7 +497,6 @@ CodeGeneratorX86::visitAsmJSStoreHeap(LAsmJSStoreHeap* ins) const LAllocation* value = ins->value(); Scalar::Type accessType = mir->accessType(); - MOZ_ASSERT(!Scalar::isSimdType(accessType)); canonicalizeIfDeterministic(accessType, value); Operand dstAddr = ptr->isBogus() diff --git a/js/src/jit/x86/LOpcodes-x86.h b/js/src/jit/x86/LOpcodes-x86.h index d5881f6a9a..7b561818d1 100644 --- a/js/src/jit/x86/LOpcodes-x86.h +++ b/js/src/jit/x86/LOpcodes-x86.h @@ -11,8 +11,6 @@ #define LIR_CPU_OPCODE_LIST(_) \ _(BoxFloatingPoint) \ _(DivOrModConstantI) \ - _(SimdValueInt32x4) \ - _(SimdValueFloat32x4) \ _(UDivOrMod) \ _(UDivOrModConstant) \ _(UDivOrModI64) \ diff --git a/js/src/jit/x86/Lowering-x86.cpp b/js/src/jit/x86/Lowering-x86.cpp index 27859c0772..39aa040fad 100644 --- a/js/src/jit/x86/Lowering-x86.cpp +++ b/js/src/jit/x86/Lowering-x86.cpp @@ -312,10 +312,6 @@ LIRGeneratorX86::visitWasmStore(MWasmStore* ins) case Scalar::Int16: case Scalar::Uint16: case Scalar::Int32: case Scalar::Uint32: case Scalar::Float32: case Scalar::Float64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: // For now, don't allow constant values. The immediate operand affects // instruction layout which affects patching. valueAlloc = useRegisterAtStart(ins->value()); @@ -373,10 +369,6 @@ LIRGeneratorX86::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins) case Scalar::Int16: case Scalar::Uint16: case Scalar::Int32: case Scalar::Uint32: case Scalar::Float32: case Scalar::Float64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: // For now, don't allow constant values. The immediate operand affects // instruction layout which affects patching. lir = new (alloc()) LAsmJSStoreHeap(baseAlloc, useRegisterAtStart(ins->value())); diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index 9962b9c594..fbefd9e77a 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -587,34 +587,6 @@ MacroAssembler::wasmLoad(const wasm::MemoryAccessDesc& access, Operand srcAddr, case Scalar::Float64: vmovsdWithPatch(srcAddr, out.fpu()); break; - case Scalar::Float32x4: - switch (access.numSimdElems()) { - // In memory-to-register mode, movss zeroes out the high lanes. - case 1: vmovssWithPatch(srcAddr, out.fpu()); break; - // See comment above, which also applies to movsd. - case 2: vmovsdWithPatch(srcAddr, out.fpu()); break; - case 4: vmovupsWithPatch(srcAddr, out.fpu()); break; - default: MOZ_CRASH("unexpected size for partial load"); - } - break; - case Scalar::Int32x4: - switch (access.numSimdElems()) { - // In memory-to-register mode, movd zeroes out the high lanes. - case 1: vmovdWithPatch(srcAddr, out.fpu()); break; - // See comment above, which also applies to movq. - case 2: vmovqWithPatch(srcAddr, out.fpu()); break; - case 4: vmovdquWithPatch(srcAddr, out.fpu()); break; - default: MOZ_CRASH("unexpected size for partial load"); - } - break; - case Scalar::Int8x16: - MOZ_ASSERT(access.numSimdElems() == 16, "unexpected partial load"); - vmovdquWithPatch(srcAddr, out.fpu()); - break; - case Scalar::Int16x8: - MOZ_ASSERT(access.numSimdElems() == 8, "unexpected partial load"); - vmovdquWithPatch(srcAddr, out.fpu()); - break; case Scalar::Int64: case Scalar::BigInt64: case Scalar::BigUint64: @@ -632,7 +604,6 @@ void MacroAssembler::wasmLoadI64(const wasm::MemoryAccessDesc& access, Operand srcAddr, Register64 out) { MOZ_ASSERT(!access.isAtomic()); - MOZ_ASSERT(!access.isSimd()); size_t loadOffset = size(); switch (access.type()) { @@ -724,10 +695,6 @@ MacroAssembler::wasmLoadI64(const wasm::MemoryAccessDesc& access, Operand srcAdd break; case Scalar::Float32: case Scalar::Float64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: MOZ_CRASH("non-int64 loads should use load()"); case Scalar::BigInt64: case Scalar::BigUint64: @@ -763,34 +730,6 @@ MacroAssembler::wasmStore(const wasm::MemoryAccessDesc& access, AnyRegister valu case Scalar::Float64: vmovsdWithPatch(value.fpu(), dstAddr); break; - case Scalar::Float32x4: - switch (access.numSimdElems()) { - // In memory-to-register mode, movss zeroes out the high lanes. - case 1: vmovssWithPatch(value.fpu(), dstAddr); break; - // See comment above, which also applies to movsd. - case 2: vmovsdWithPatch(value.fpu(), dstAddr); break; - case 4: vmovupsWithPatch(value.fpu(), dstAddr); break; - default: MOZ_CRASH("unexpected size for partial load"); - } - break; - case Scalar::Int32x4: - switch (access.numSimdElems()) { - // In memory-to-register mode, movd zeroes out the high lanes. - case 1: vmovdWithPatch(value.fpu(), dstAddr); break; - // See comment above, which also applies to movsd. - case 2: vmovqWithPatch(value.fpu(), dstAddr); break; - case 4: vmovdquWithPatch(value.fpu(), dstAddr); break; - default: MOZ_CRASH("unexpected size for partial load"); - } - break; - case Scalar::Int8x16: - MOZ_ASSERT(access.numSimdElems() == 16, "unexpected partial store"); - vmovdquWithPatch(value.fpu(), dstAddr); - break; - case Scalar::Int16x8: - MOZ_ASSERT(access.numSimdElems() == 8, "unexpected partial store"); - vmovdquWithPatch(value.fpu(), dstAddr); - break; case Scalar::Int64: MOZ_CRASH("Should be handled in storeI64."); case Scalar::MaxTypedArrayViewType: @@ -808,7 +747,6 @@ void MacroAssembler::wasmStoreI64(const wasm::MemoryAccessDesc& access, Register64 value, Operand dstAddr) { MOZ_ASSERT(!access.isAtomic()); - MOZ_ASSERT(!access.isSimd()); size_t storeOffset = size(); if (dstAddr.kind() == Operand::MEM_ADDRESS32) { diff --git a/js/src/js.msg b/js/src/js.msg index 340cfd6ad2..e651b10137 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -331,7 +331,6 @@ MSG_DEF(JSMSG_STMT_AFTER_RETURN, 0, JSEXN_WARN, "unreachable code after re MSG_DEF(JSMSG_STRICT_CODE_WITH, 0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements") MSG_DEF(JSMSG_STRICT_NON_SIMPLE_PARAMS, 1, JSEXN_SYNTAXERR, "\"use strict\" not allowed in function with {0} parameter") MSG_DEF(JSMSG_TEMPLSTR_UNTERM_EXPR, 0, JSEXN_SYNTAXERR, "missing } in template string") -MSG_DEF(JSMSG_SIMD_NOT_A_VECTOR, 2, JSEXN_TYPEERR, "expecting a SIMD {0} object as argument {1}") MSG_DEF(JSMSG_TOO_MANY_CASES, 0, JSEXN_INTERNALERR, "too many switch cases") MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS, 0, JSEXN_SYNTAXERR, "too many catch variables") MSG_DEF(JSMSG_TOO_MANY_CON_ARGS, 0, JSEXN_SYNTAXERR, "too many constructor arguments") @@ -533,15 +532,13 @@ MSG_DEF(JSMSG_INVALID_NAMED_CAPTURE_REF, 0, JSEXN_SYNTAXERR, "invalid named ca MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR, 0, JSEXN_ERR, "internal error getting the default locale") MSG_DEF(JSMSG_NO_SUCH_SELF_HOSTED_PROP,1, JSEXN_ERR, "No such property on self-hosted object: {0}") -// Typed object / SIMD +// Typed object MSG_DEF(JSMSG_INVALID_PROTOTYPE, 0, JSEXN_TYPEERR, "prototype field is not an object") MSG_DEF(JSMSG_TYPEDOBJECT_BAD_ARGS, 0, JSEXN_TYPEERR, "invalid arguments") MSG_DEF(JSMSG_TYPEDOBJECT_BINARYARRAY_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index") MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED, 0, JSEXN_TYPEERR, "handle unattached") MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS, 0, JSEXN_RANGEERR, "invalid field descriptor") MSG_DEF(JSMSG_TYPEDOBJECT_TOO_BIG, 0, JSEXN_ERR, "Type is too large to allocate") -MSG_DEF(JSMSG_SIMD_FAILED_CONVERSION, 0, JSEXN_RANGEERR, "SIMD conversion loses precision") -MSG_DEF(JSMSG_SIMD_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert SIMD value to number") // Array MSG_DEF(JSMSG_TOO_LONG_ARRAY, 0, JSEXN_TYPEERR, "Too long array") diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 0e29f02176..0fd82f7c2d 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -47,9 +47,6 @@ #include "builtin/Promise.h" #include "builtin/RegExp.h" #include "builtin/SymbolObject.h" -#ifdef ENABLE_SIMD -# include "builtin/SIMD.h" -#endif #ifdef ENABLE_BINARYDATA # include "builtin/TypedObject.h" #endif diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 66a548d6e8..a77f3d1809 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -35,6 +35,12 @@ #include "gc/Marking.h" #include "jit/Ion.h" #include "js/CharacterEncoding.h" +#ifdef JS_SIMULATOR_ARM64 +# include "jit/arm64/vixl/Simulator-vixl.h" +#endif +#ifdef JS_SIMULATOR_ARM +# include "jit/arm/Simulator-arm.h" +#endif #include "vm/HelperThreads.h" #include "vm/Shape.h" diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 6a873e15da..b4c4e15801 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1501,10 +1501,6 @@ enum Type { MaxTypedArrayViewType, Int64, - Float32x4, - Int8x16, - Int16x8, - Int32x4 }; static inline size_t @@ -1527,11 +1523,6 @@ byteSize(Type atype) case BigInt64: case BigUint64: return 8; - case Int8x16: - case Int16x8: - case Int32x4: - case Float32x4: - return 16; default: MOZ_CRASH("invalid scalar type"); } @@ -1544,9 +1535,6 @@ isSignedIntType(Type atype) { case Int16: case Int32: case Int64: - case Int8x16: - case Int16x8: - case Int32x4: case BigInt64: return true; case Uint8: @@ -1555,7 +1543,6 @@ isSignedIntType(Type atype) { case Uint32: case Float32: case Float64: - case Float32x4: case BigUint64: return false; default: @@ -1578,10 +1565,6 @@ static inline bool isBigIntType(Type atype) { case Uint32: case Float32: case Float64: - case Int8x16: - case Int16x8: - case Int32x4: - case Float32x4: return false; case MaxTypedArrayViewType: break; @@ -1589,61 +1572,6 @@ static inline bool isBigIntType(Type atype) { MOZ_CRASH("invalid scalar type"); } -static inline bool -isSimdType(Type atype) { - switch (atype) { - case Int8: - case Uint8: - case Uint8Clamped: - case Int16: - case Uint16: - case Int32: - case Uint32: - case Int64: - case Float32: - case Float64: - case BigInt64: - case BigUint64: - return false; - case Int8x16: - case Int16x8: - case Int32x4: - case Float32x4: - return true; - case MaxTypedArrayViewType: - break; - } - MOZ_CRASH("invalid scalar type"); -} - -static inline size_t -scalarByteSize(Type atype) { - switch (atype) { - case Int8x16: - return 1; - case Int16x8: - return 2; - case Int32x4: - case Float32x4: - return 4; - case Int8: - case Uint8: - case Uint8Clamped: - case Int16: - case Uint16: - case Int32: - case Uint32: - case Int64: - case Float32: - case Float64: - case BigInt64: - case BigUint64: - case MaxTypedArrayViewType: - break; - } - MOZ_CRASH("invalid simd type"); -} - } /* namespace Scalar */ } /* namespace js */ diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h index 34f835bc1d..52d0d8ea4a 100644 --- a/js/src/jsprototypes.h +++ b/js/src/jsprototypes.h @@ -43,12 +43,6 @@ #define IF_BDATA(real,imaginary) imaginary #endif -#ifdef ENABLE_SIMD -# define IF_SIMD(real,imaginary) real -#else -# define IF_SIMD(real,imaginary) imaginary -#endif - #ifdef ENABLE_SHARED_ARRAY_BUFFER #define IF_SAB(real,imaginary) real #else @@ -104,7 +98,6 @@ IF_SAB(real,imaginary)(SharedArrayBuffer, InitViaClassSpec, OCLASP(SharedArr IF_INTL(real,imaginary) (Intl, InitIntlClass, CLASP(Intl)) \ IF_BDATA(real,imaginary)(TypedObject, InitTypedObjectModuleObject, OCLASP(TypedObjectModule)) \ real(Reflect, InitReflect, nullptr) \ -IF_SIMD(real,imaginary)(SIMD, InitSimdClass, OCLASP(Simd)) \ real(WeakSet, InitWeakSetClass, OCLASP(WeakSet)) \ real(TypedArray, InitViaClassSpec, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \ IF_SAB(real,imaginary)(Atomics, InitAtomicsClass, OCLASP(Atomics)) \ diff --git a/js/src/moz.build b/js/src/moz.build index 59feedf22d..5429888a2c 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -132,7 +132,6 @@ main_deunified_sources = [ 'builtin/Promise.cpp', 'builtin/Reflect.cpp', 'builtin/ReflectParse.cpp', - 'builtin/SIMD.cpp', 'builtin/SymbolObject.cpp', 'builtin/TestingFunctions.cpp', 'builtin/TypedObject.cpp', @@ -206,7 +205,6 @@ main_deunified_sources = [ 'jit/CodeGenerator.cpp', 'jit/CompileWrappers.cpp', 'jit/Disassembler.cpp', - 'jit/EagerSimdUnbox.cpp', 'jit/EdgeCaseAnalysis.cpp', 'jit/EffectiveAddressAnalysis.cpp', 'jit/ExecutableAllocator.cpp', diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 3bed40af47..db1d7c798f 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -777,8 +777,8 @@ ArrayBufferObject::prepareForAsmJS(JSContext* cx, Handle<ArrayBufferObject*> buf return true; // Non-prepared-for-asm.js wasm buffers can be detached at any time. - // This error can only be triggered for SIMD.js (which isn't shipping) - // on !WASM_HUGE_MEMORY so this error is only visible in testing. + // This error can only be triggered for Atomics on !WASM_HUGE_MEMORY, + // so this error is only visible in testing. if (buffer->isWasm() || buffer->isPreparedForAsmJS()) return false; diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index c4d9cf7287..355d055fb6 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -25,9 +25,6 @@ class Debugger; class TypedObjectModuleObject; class LexicalEnvironmentObject; -class SimdTypeDescr; -enum class SimdType; - /* * Global object slots are reserved as follows: * @@ -482,17 +479,6 @@ class GlobalObject : public NativeObject initTypedObjectModule); } - static JSObject* - getOrCreateSimdGlobalObject(JSContext* cx, Handle<GlobalObject*> global) { - return getOrCreateObject(cx, global, APPLICATION_SLOTS + JSProto_SIMD, initSimdObject); - } - - // Get the type descriptor for one of the SIMD types. - // simdType is one of the JS_SIMDTYPEREPR_* constants. - // Implemented in builtin/SIMD.cpp. - static SimdTypeDescr* - getOrCreateSimdTypeDescr(JSContext* cx, Handle<GlobalObject*> global, SimdType simdType); - TypedObjectModuleObject& getTypedObjectModule() const; JSObject* getLegacyIteratorPrototype() { @@ -869,10 +855,6 @@ class GlobalObject : public NativeObject // Implemented in builtin/TypedObject.cpp static bool initTypedObjectModule(JSContext* cx, Handle<GlobalObject*> global); - // Implemented in builtin/SIMD.cpp - static bool initSimdObject(JSContext* cx, Handle<GlobalObject*> global); - static bool initSimdType(JSContext* cx, Handle<GlobalObject*> global, SimdType simdType); - static bool initStandardClasses(JSContext* cx, Handle<GlobalObject*> global); static bool initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> global, const JSFunctionSpec* builtins); diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 2a60a1885c..e9c72d1bf1 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -36,7 +36,6 @@ #include "builtin/Promise.h" #include "builtin/Reflect.h" #include "builtin/SelfHostingDefines.h" -#include "builtin/SIMD.h" #include "builtin/TypedObject.h" #include "builtin/WeakSetObject.h" #include "gc/Marking.h" @@ -2299,19 +2298,6 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("std_WeakMap_set", WeakMap_set, 2,0), JS_FN("std_WeakMap_delete", WeakMap_delete, 1,0), - JS_FN("std_SIMD_Int8x16_extractLane", simd_int8x16_extractLane, 2,0), - JS_FN("std_SIMD_Int16x8_extractLane", simd_int16x8_extractLane, 2,0), - JS_INLINABLE_FN("std_SIMD_Int32x4_extractLane", simd_int32x4_extractLane, 2,0, SimdInt32x4_extractLane), - JS_FN("std_SIMD_Uint8x16_extractLane", simd_uint8x16_extractLane, 2,0), - JS_FN("std_SIMD_Uint16x8_extractLane", simd_uint16x8_extractLane, 2,0), - JS_FN("std_SIMD_Uint32x4_extractLane", simd_uint32x4_extractLane, 2,0), - JS_INLINABLE_FN("std_SIMD_Float32x4_extractLane", simd_float32x4_extractLane,2,0, SimdFloat32x4_extractLane), - JS_FN("std_SIMD_Float64x2_extractLane", simd_float64x2_extractLane, 2,0), - JS_FN("std_SIMD_Bool8x16_extractLane", simd_bool8x16_extractLane, 2,0), - JS_FN("std_SIMD_Bool16x8_extractLane", simd_bool16x8_extractLane, 2,0), - JS_FN("std_SIMD_Bool32x4_extractLane", simd_bool32x4_extractLane, 2,0), - JS_FN("std_SIMD_Bool64x2_extractLane", simd_bool64x2_extractLane, 2,0), - // Helper funtions after this point. JS_INLINABLE_FN("ToObject", intrinsic_ToObject, 1,0, IntrinsicToObject), JS_INLINABLE_FN("IsObject", intrinsic_IsObject, 1,0, IntrinsicIsObject), @@ -2513,7 +2499,6 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("TypedObjectTypeDescr", js::TypedObjectTypeDescr, 1, 0), JS_FN("ClampToUint8", js::ClampToUint8, 1, 0), JS_FN("GetTypedObjectModule", js::GetTypedObjectModule, 0, 0), - JS_FN("GetSimdTypeDescr", js::GetSimdTypeDescr, 1, 0), JS_INLINABLE_FN("ObjectIsTypeDescr" , js::ObjectIsTypeDescr, 1, 0, IntrinsicObjectIsTypeDescr), diff --git a/js/src/vm/TypedArrayCommon.h b/js/src/vm/TypedArrayCommon.h index 8e66587a1e..59ffd78b24 100644 --- a/js/src/vm/TypedArrayCommon.h +++ b/js/src/vm/TypedArrayCommon.h @@ -849,10 +849,6 @@ class TypedArrayMethods return ElementSpecific<Uint8ClampedArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset); return ElementSpecific<Uint8ClampedArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset); case Scalar::Int64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: case Scalar::MaxTypedArrayViewType: break; } @@ -913,11 +909,6 @@ class TypedArrayMethods if (isShared) return ElementSpecific<Uint8ClampedArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset); return ElementSpecific<Uint8ClampedArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset); - case Scalar::Int64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: case Scalar::MaxTypedArrayViewType: break; } @@ -976,10 +967,6 @@ class TypedArrayMethods return ElementSpecific<Uint8ClampedArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source); return ElementSpecific<Uint8ClampedArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source); case Scalar::Int64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: case Scalar::MaxTypedArrayViewType: break; } diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 28e4090eb8..fc3d6c5df2 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -2741,10 +2741,6 @@ bool TypedArrayObject::getElement<CanGC>(ExclusiveContext* cx, uint32_t index, M JS_FOR_EACH_TYPED_ARRAY(GET_ELEMENT) #undef GET_ELEMENT case Scalar::Int64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: case Scalar::MaxTypedArrayViewType: break; } @@ -2770,10 +2766,6 @@ bool TypedArrayObject::getElementPure(uint32_t index, Value* vp) JS_FOR_EACH_TYPED_ARRAY(GET_ELEMENT_PURE) #undef GET_ELEMENT case Scalar::Int64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: case Scalar::MaxTypedArrayViewType: break; } @@ -2803,10 +2795,6 @@ bool TypedArrayObject::getElements(JSContext* cx, Handle<TypedArrayObject*> tarr MOZ_CRASH("Unknown TypedArray type"); case Scalar::MaxTypedArrayViewType: case Scalar::Int64: - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: break; } diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h index 06aaea0617..8b4b0b5092 100644 --- a/js/src/vm/TypedArrayObject.h +++ b/js/src/vm/TypedArrayObject.h @@ -413,11 +413,6 @@ TypedArrayShift(Scalar::Type viewType) case Scalar::Int64: case Scalar::Float64: return 3; - case Scalar::Float32x4: - case Scalar::Int8x16: - case Scalar::Int16x8: - case Scalar::Int32x4: - return 4; default:; } MOZ_CRASH("Unexpected array type"); diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 3eee8c4c18..7923c57c0c 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -1,7 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2014 Mozilla Foundation - * Copyright 2022 Moonchild Productions + * Copyright 2022, 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,6 @@ #include "jswrapper.h" -#include "builtin/SIMD.h" #include "frontend/Parser.h" #include "gc/Policy.h" #include "js/MemoryMetrics.h" @@ -121,7 +120,7 @@ class AsmJSGlobal { public: enum Which { Variable, FFI, ArrayView, ArrayViewCtor, MathBuiltinFunction, - AtomicsBuiltinFunction, Constant, SimdCtor, SimdOp }; + AtomicsBuiltinFunction, Constant }; enum VarInitKind { InitConstant, InitImport }; enum ConstantKind { GlobalConstant, MathConstant }; @@ -141,11 +140,6 @@ class AsmJSGlobal Scalar::Type viewType_; AsmJSMathBuiltinFunction mathBuiltinFunc_; AsmJSAtomicsBuiltinFunction atomicsBuiltinFunc_; - SimdType simdCtorType_; - struct { - SimdType type_; - SimdOperation which_; - } simdOp; struct { ConstantKind kind_; double value_; @@ -204,18 +198,6 @@ class AsmJSGlobal MOZ_ASSERT(pod.which_ == AtomicsBuiltinFunction); return pod.u.atomicsBuiltinFunc_; } - SimdType simdCtorType() const { - MOZ_ASSERT(pod.which_ == SimdCtor); - return pod.u.simdCtorType_; - } - SimdOperation simdOperation() const { - MOZ_ASSERT(pod.which_ == SimdOp); - return pod.u.simdOp.which_; - } - SimdType simdOperationType() const { - MOZ_ASSERT(pod.which_ == SimdOp); - return pod.u.simdOp.type_; - } ConstantKind constantKind() const { MOZ_ASSERT(pod.which_ == Constant); return pod.u.constant.kind_; @@ -292,7 +274,6 @@ struct AsmJSMetadataCacheablePod uint32_t numFFIs = 0; uint32_t srcLength = 0; uint32_t srcLengthWithRightBrace = 0; - bool usesSimd = false; AsmJSMetadataCacheablePod() = default; }; @@ -809,9 +790,6 @@ ParseVarOrConstStatement(AsmJSParser& parser, ParseNode** var) // Lastly, a literal may be a float literal which is any double or integer // literal coerced with Math.fround. // -// This class distinguishes between signed and unsigned integer SIMD types like -// Int32x4 and Uint32x4, and so does Type below. The wasm ValType and ExprType -// enums, and the wasm::Val class do not. class NumLit { public: @@ -821,16 +799,6 @@ class NumLit BigUnsigned, Double, Float, - Int8x16, - Int16x8, - Int32x4, - Uint8x16, - Uint16x8, - Uint32x4, - Float32x4, - Bool8x16, - Bool16x8, - Bool32x4, OutOfRangeInt = -1 }; @@ -838,7 +806,6 @@ class NumLit Which which_; union { JS::UninitializedValue scalar_; - SimdConstant simd_; } u; public: @@ -849,11 +816,6 @@ class NumLit MOZ_ASSERT(!isSimd()); } - NumLit(Which w, SimdConstant c) : which_(w) { - u.simd_ = c; - MOZ_ASSERT(isSimd()); - } - Which which() const { return which_; } @@ -882,19 +844,6 @@ class NumLit return u.scalar_.asValueRef(); } - bool isSimd() const - { - return which_ == Int8x16 || which_ == Uint8x16 || which_ == Int16x8 || - which_ == Uint16x8 || which_ == Int32x4 || which_ == Uint32x4 || - which_ == Float32x4 || which_ == Bool8x16 || which_ == Bool16x8 || - which_ == Bool32x4; - } - - const SimdConstant& simdValue() const { - MOZ_ASSERT(isSimd()); - return u.simd_; - } - bool valid() const { return which_ != OutOfRangeInt; } @@ -910,20 +859,6 @@ class NumLit return toDouble().bits() == 0; case NumLit::Float: return toFloat().bits() == 0; - case NumLit::Int8x16: - case NumLit::Uint8x16: - case NumLit::Bool8x16: - return simdValue() == SimdConstant::SplatX16(0); - case NumLit::Int16x8: - case NumLit::Uint16x8: - case NumLit::Bool16x8: - return simdValue() == SimdConstant::SplatX8(0); - case NumLit::Int32x4: - case NumLit::Uint32x4: - case NumLit::Bool32x4: - return simdValue() == SimdConstant::SplatX4(0); - case NumLit::Float32x4: - return simdValue() == SimdConstant::SplatX4(0.f); case NumLit::OutOfRangeInt: MOZ_CRASH("can't be here because of valid() check above"); } @@ -940,23 +875,6 @@ class NumLit return Val(toFloat()); case NumLit::Double: return Val(toDouble()); - case NumLit::Int8x16: - case NumLit::Uint8x16: - return Val(simdValue().asInt8x16()); - case NumLit::Int16x8: - case NumLit::Uint16x8: - return Val(simdValue().asInt16x8()); - case NumLit::Int32x4: - case NumLit::Uint32x4: - return Val(simdValue().asInt32x4()); - case NumLit::Float32x4: - return Val(simdValue().asFloat32x4()); - case NumLit::Bool8x16: - return Val(simdValue().asInt8x16(), ValType::B8x16); - case NumLit::Bool16x8: - return Val(simdValue().asInt16x8(), ValType::B16x8); - case NumLit::Bool32x4: - return Val(simdValue().asInt32x4(), ValType::B32x4); case NumLit::OutOfRangeInt:; } MOZ_CRASH("bad literal"); @@ -966,17 +884,10 @@ class NumLit // Represents the type of a general asm.js expression. // // A canonical subset of types representing the coercion targets: Int, Float, -// Double, and the SIMD types. This is almost equivalent to wasm::ValType, -// except the integer SIMD types have signed/unsigned variants. +// Double. // // Void is also part of the canonical subset which then maps to wasm::ExprType. -// -// Note that while the canonical subset distinguishes signed and unsigned SIMD -// types, it only uses |Int| to represent signed and unsigned 32-bit integers. -// This is because the scalar coersions x|0 and x>>>0 work with any kind of -// integer input, while the SIMD check functions throw a TypeError if the passed -// type doesn't match. -// + class Type { public: @@ -986,16 +897,6 @@ class Type Unsigned = NumLit::BigUnsigned, DoubleLit = NumLit::Double, Float = NumLit::Float, - Int8x16 = NumLit::Int8x16, - Int16x8 = NumLit::Int16x8, - Int32x4 = NumLit::Int32x4, - Uint8x16 = NumLit::Uint8x16, - Uint16x8 = NumLit::Uint16x8, - Uint32x4 = NumLit::Uint32x4, - Float32x4 = NumLit::Float32x4, - Bool8x16 = NumLit::Bool8x16, - Bool16x8 = NumLit::Bool16x8, - Bool32x4 = NumLit::Bool32x4, Double, MaybeDouble, MaybeFloat, @@ -1011,22 +912,6 @@ class Type public: Type() = default; MOZ_IMPLICIT Type(Which w) : which_(w) {} - MOZ_IMPLICIT Type(SimdType type) { - switch (type) { - case SimdType::Int8x16: which_ = Int8x16; return; - case SimdType::Int16x8: which_ = Int16x8; return; - case SimdType::Int32x4: which_ = Int32x4; return; - case SimdType::Uint8x16: which_ = Uint8x16; return; - case SimdType::Uint16x8: which_ = Uint16x8; return; - case SimdType::Uint32x4: which_ = Uint32x4; return; - case SimdType::Float32x4: which_ = Float32x4; return; - case SimdType::Bool8x16: which_ = Bool8x16; return; - case SimdType::Bool16x8: which_ = Bool16x8; return; - case SimdType::Bool32x4: which_ = Bool32x4; return; - default: break; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad SimdType"); - } // Map an already canonicalized Type to the return type of a function call. static Type ret(Type t) { @@ -1038,7 +923,7 @@ class Type static Type lit(const NumLit& lit) { MOZ_ASSERT(lit.valid()); Which which = Type::Which(lit.which()); - MOZ_ASSERT(which >= Fixnum && which <= Bool32x4); + MOZ_ASSERT(which >= Fixnum && which <= Float); Type t; t.which_ = which; return t; @@ -1064,18 +949,6 @@ class Type case Void: return Void; - case Int8x16: - case Int16x8: - case Int32x4: - case Uint8x16: - case Uint16x8: - case Uint32x4: - case Float32x4: - case Bool8x16: - case Bool16x8: - case Bool32x4: - return t; - case MaybeDouble: case MaybeFloat: case Floatish: @@ -1099,16 +972,6 @@ class Type case DoubleLit: return isDoubleLit(); case Double: return isDouble(); case Float: return isFloat(); - case Int8x16: return isInt8x16(); - case Int16x8: return isInt16x8(); - case Int32x4: return isInt32x4(); - case Uint8x16: return isUint8x16(); - case Uint16x8: return isUint16x8(); - case Uint32x4: return isUint32x4(); - case Float32x4: return isFloat32x4(); - case Bool8x16: return isBool8x16(); - case Bool16x8: return isBool16x8(); - case Bool32x4: return isBool32x4(); case MaybeDouble: return isMaybeDouble(); case MaybeFloat: return isMaybeFloat(); case Floatish: return isFloatish(); @@ -1172,64 +1035,14 @@ class Type return isDouble() || isSigned(); } - bool isInt8x16() const { - return which_ == Int8x16; - } - - bool isInt16x8() const { - return which_ == Int16x8; - } - - bool isInt32x4() const { - return which_ == Int32x4; - } - - bool isUint8x16() const { - return which_ == Uint8x16; - } - - bool isUint16x8() const { - return which_ == Uint16x8; - } - - bool isUint32x4() const { - return which_ == Uint32x4; - } - - bool isFloat32x4() const { - return which_ == Float32x4; - } - - bool isBool8x16() const { - return which_ == Bool8x16; - } - - bool isBool16x8() const { - return which_ == Bool16x8; - } - - bool isBool32x4() const { - return which_ == Bool32x4; - } - - bool isSimd() const { - return isInt8x16() || isInt16x8() || isInt32x4() || isUint8x16() || isUint16x8() || - isUint32x4() || isFloat32x4() || isBool8x16() || isBool16x8() || isBool32x4(); - } - - bool isUnsignedSimd() const { - return isUint8x16() || isUint16x8() || isUint32x4(); - } - // Check if this is one of the valid types for a function argument. bool isArgType() const { - return isInt() || isFloat() || isDouble() || (isSimd() && !isUnsignedSimd()); + return isInt() || isFloat() || isDouble(); } // Check if this is one of the valid types for a function return value. bool isReturnType() const { - return isSigned() || isFloat() || isDouble() || (isSimd() && !isUnsignedSimd()) || - isVoid(); + return isSigned() || isFloat() || isDouble() || isVoid(); } // Check if this is one of the valid types for a global variable. @@ -1247,7 +1060,7 @@ class Type case Void: return true; default: - return isSimd(); + return false; } } @@ -1263,16 +1076,6 @@ class Type case Float: return ExprType::F32; case Double: return ExprType::F64; case Void: return ExprType::Void; - case Uint8x16: - case Int8x16: return ExprType::I8x16; - case Uint16x8: - case Int16x8: return ExprType::I16x8; - case Uint32x4: - case Int32x4: return ExprType::I32x4; - case Float32x4: return ExprType::F32x4; - case Bool8x16: return ExprType::B8x16; - case Bool16x8: return ExprType::B16x8; - case Bool32x4: return ExprType::B32x4; default: MOZ_CRASH("Need canonical type"); } } @@ -1307,17 +1110,6 @@ class Type case Void: return ExprType::Void; - - case Uint8x16: - case Int8x16: return ExprType::I8x16; - case Uint16x8: - case Int16x8: return ExprType::I16x8; - case Uint32x4: - case Int32x4: return ExprType::I32x4; - case Float32x4: return ExprType::F32x4; - case Bool8x16: return ExprType::B8x16; - case Bool16x8: return ExprType::B16x8; - case Bool32x4: return ExprType::B32x4; } MOZ_CRASH("Invalid Type"); } @@ -1335,16 +1127,6 @@ class Type case Signed: return "signed"; case Unsigned: return "unsigned"; case Intish: return "intish"; - case Int8x16: return "int8x16"; - case Int16x8: return "int16x8"; - case Int32x4: return "int32x4"; - case Uint8x16: return "uint8x16"; - case Uint16x8: return "uint16x8"; - case Uint32x4: return "uint32x4"; - case Float32x4: return "float32x4"; - case Bool8x16: return "bool8x16"; - case Bool16x8: return "bool16x8"; - case Bool32x4: return "bool32x4"; case Void: return "void"; } MOZ_CRASH("Invalid Type"); @@ -1442,9 +1224,7 @@ class MOZ_STACK_CLASS ModuleValidator ArrayView, ArrayViewCtor, MathBuiltinFunction, - AtomicsBuiltinFunction, - SimdCtor, - SimdOp + AtomicsBuiltinFunction }; private: @@ -1463,19 +1243,15 @@ class MOZ_STACK_CLASS ModuleValidator } viewInfo; AsmJSMathBuiltinFunction mathBuiltinFunc_; AsmJSAtomicsBuiltinFunction atomicsBuiltinFunc_; - SimdType simdCtorType_; - struct { - SimdType type_; - SimdOperation which_; - } simdOp; } u; friend class ModuleValidator; friend class js::LifoAlloc; explicit Global(Which which) : which_(which) {} - + public: + Which which() const { return which_; } @@ -1527,24 +1303,6 @@ class MOZ_STACK_CLASS ModuleValidator MOZ_ASSERT(which_ == AtomicsBuiltinFunction); return u.atomicsBuiltinFunc_; } - bool isSimdCtor() const { - return which_ == SimdCtor; - } - SimdType simdCtorType() const { - MOZ_ASSERT(which_ == SimdCtor); - return u.simdCtorType_; - } - bool isSimdOperation() const { - return which_ == SimdOp; - } - SimdOperation simdOperation() const { - MOZ_ASSERT(which_ == SimdOp); - return u.simdOp.which_; - } - SimdType simdOperationType() const { - MOZ_ASSERT(which_ == SimdOp); - return u.simdOp.type_; - } }; struct MathBuiltin @@ -1611,7 +1369,6 @@ class MOZ_STACK_CLASS ModuleValidator typedef HashMap<PropertyName*, Global*> GlobalMap; typedef HashMap<PropertyName*, MathBuiltin> MathNameMap; typedef HashMap<PropertyName*, AsmJSAtomicsBuiltinFunction> AtomicsNameMap; - typedef HashMap<PropertyName*, SimdOperation> SimdOperationNameMap; typedef Vector<ArrayView> ArrayViewVector; ExclusiveContext* cx_; @@ -1623,7 +1380,6 @@ class MOZ_STACK_CLASS ModuleValidator PropertyName* bufferArgumentName_; MathNameMap standardLibraryMathNames_; AtomicsNameMap standardLibraryAtomicsNames_; - SimdOperationNameMap standardLibrarySimdOpNames_; RootedFunction dummyFunction_; // Validation-internal state: @@ -1635,7 +1391,6 @@ class MOZ_STACK_CLASS ModuleValidator ImportMap importMap_; ArrayViewVector arrayViews_; bool atomicsPresent_; - bool simdPresent_; // State used to build the AsmJSModule in finish(): ModuleGenerator mg_; @@ -1667,12 +1422,6 @@ class MOZ_STACK_CLASS ModuleValidator return false; return standardLibraryAtomicsNames_.putNew(atom->asPropertyName(), func); } - bool addStandardLibrarySimdOpName(const char* name, SimdOperation op) { - JSAtom* atom = Atomize(cx_, name, strlen(name)); - if (!atom) - return false; - return standardLibrarySimdOpNames_.putNew(atom->asPropertyName(), op); - } bool newSig(Sig&& sig, uint32_t* sigIndex) { *sigIndex = 0; if (mg_.numSigs() >= MaxSigs) @@ -1705,7 +1454,6 @@ class MOZ_STACK_CLASS ModuleValidator bufferArgumentName_(nullptr), standardLibraryMathNames_(cx), standardLibraryAtomicsNames_(cx), - standardLibrarySimdOpNames_(cx), dummyFunction_(cx), validationLifo_(VALIDATION_LIFO_DEFAULT_CHUNK_SIZE), functions_(cx), @@ -1715,7 +1463,6 @@ class MOZ_STACK_CLASS ModuleValidator importMap_(cx), arrayViews_(cx), atomicsPresent_(false), - simdPresent_(false), mg_(ImportVector()), errorString_(nullptr), errorOffset_(UINT32_MAX), @@ -1795,14 +1542,6 @@ class MOZ_STACK_CLASS ModuleValidator return false; } -#define ADDSTDLIBSIMDOPNAME(op) || !addStandardLibrarySimdOpName(#op, SimdOperation::Fn_##op) - if (!standardLibrarySimdOpNames_.init() - FORALL_SIMD_ASMJS_OP(ADDSTDLIBSIMDOPNAME)) - { - return false; - } -#undef ADDSTDLIBSIMDOPNAME - // This flows into FunctionBox, so must be tenured. dummyFunction_ = NewScriptedFunction(cx_, 0, JSFunction::INTERPRETED, nullptr, /* proto = */ nullptr, gc::AllocKind::FUNCTION, @@ -1850,7 +1589,6 @@ class MOZ_STACK_CLASS ModuleValidator AsmJSParser& parser() const { return parser_; } TokenStream& tokenStream() const { return parser_.tokenStream; } RootedFunction& dummyFunction() { return dummyFunction_; } - bool supportsSimd() const { return cx_->jitSupportsSimd(); } bool atomicsPresent() const { return atomicsPresent_; } uint32_t minMemoryLength() const { return mg_.minMemoryLength(); } @@ -2037,44 +1775,6 @@ class MOZ_STACK_CLASS ModuleValidator g.pod.u.atomicsBuiltinFunc_ = func; return asmJSMetadata_->asmJSGlobals.append(Move(g)); } - bool addSimdCtor(PropertyName* var, SimdType type, PropertyName* field) { - simdPresent_ = true; - - UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field); - if (!fieldChars) - return false; - - Global* global = validationLifo_.new_<Global>(Global::SimdCtor); - if (!global) - return false; - global->u.simdCtorType_ = type; - if (!globalMap_.putNew(var, global)) - return false; - - AsmJSGlobal g(AsmJSGlobal::SimdCtor, Move(fieldChars)); - g.pod.u.simdCtorType_ = type; - return asmJSMetadata_->asmJSGlobals.append(Move(g)); - } - bool addSimdOperation(PropertyName* var, SimdType type, SimdOperation op, PropertyName* field) { - simdPresent_ = true; - - UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field); - if (!fieldChars) - return false; - - Global* global = validationLifo_.new_<Global>(Global::SimdOp); - if (!global) - return false; - global->u.simdOp.type_ = type; - global->u.simdOp.which_ = op; - if (!globalMap_.putNew(var, global)) - return false; - - AsmJSGlobal g(AsmJSGlobal::SimdOp, Move(fieldChars)); - g.pod.u.simdOp.type_ = type; - g.pod.u.simdOp.which_ = op; - return asmJSMetadata_->asmJSGlobals.append(Move(g)); - } bool addArrayViewCtor(PropertyName* var, Scalar::Type vt, PropertyName* field) { UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field); if (!fieldChars) @@ -2320,13 +2020,6 @@ class MOZ_STACK_CLASS ModuleValidator } return false; } - bool lookupStandardSimdOpName(PropertyName* name, SimdOperation* op) const { - if (SimdOperationNameMap::Ptr p = standardLibrarySimdOpNames_.lookup(name)) { - *op = p->value(); - return true; - } - return false; - } bool startFunctionBodies() { return mg_.startFuncDefs(); @@ -2338,8 +2031,6 @@ class MOZ_STACK_CLASS ModuleValidator if (!arrayViews_.empty()) mg_.initMemoryUsage(atomicsPresent_ ? MemoryUsage::Shared : MemoryUsage::Unshared); - asmJSMetadata_->usesSimd = simdPresent_; - MOZ_ASSERT(asmJSMetadata_->asmJSFuncNames.empty()); for (const Func* func : functions_) { CacheableChars funcName = StringToNewUTF8CharsZ(cx_, *func->name()); @@ -2409,11 +2100,6 @@ IsCoercionCall(ModuleValidator& m, ParseNode* pn, Type* coerceTo, ParseNode** co return true; } - if (global->isSimdOperation() && global->simdOperation() == SimdOperation::Fn_check) { - *coerceTo = global->simdOperationType(); - return true; - } - return false; } @@ -2431,23 +2117,6 @@ IsFloatLiteral(ModuleValidator& m, ParseNode* pn) } static bool -IsSimdTuple(ModuleValidator& m, ParseNode* pn, SimdType* type) -{ - const ModuleValidator::Global* global; - if (!IsCallToGlobal(m, pn, &global)) - return false; - - if (!global->isSimdCtor()) - return false; - - if (CallArgListLength(pn) != GetSimdLanes(global->simdCtorType())) - return false; - - *type = global->simdCtorType(); - return true; -} - -static bool IsNumericLiteral(ModuleValidator& m, ParseNode* pn, bool* isSimd = nullptr); static NumLit @@ -2457,57 +2126,10 @@ static inline bool IsLiteralInt(ModuleValidator& m, ParseNode* pn, uint32_t* u32); static bool -IsSimdLiteral(ModuleValidator& m, ParseNode* pn) -{ - SimdType type; - if (!IsSimdTuple(m, pn, &type)) - return false; - - ParseNode* arg = CallArgList(pn); - unsigned length = GetSimdLanes(type); - for (unsigned i = 0; i < length; i++) { - if (!IsNumericLiteral(m, arg)) - return false; - - uint32_t _; - switch (type) { - case SimdType::Int8x16: - case SimdType::Int16x8: - case SimdType::Int32x4: - case SimdType::Uint8x16: - case SimdType::Uint16x8: - case SimdType::Uint32x4: - case SimdType::Bool8x16: - case SimdType::Bool16x8: - case SimdType::Bool32x4: - if (!IsLiteralInt(m, arg, &_)) - return false; - break; - case SimdType::Float32x4: - if (!IsNumericNonFloatLiteral(arg)) - return false; - break; - default: - MOZ_CRASH("unhandled simd type"); - } - - arg = NextNode(arg); - } - - MOZ_ASSERT(arg == nullptr); - return true; -} - -static bool IsNumericLiteral(ModuleValidator& m, ParseNode* pn, bool* isSimd) { if (IsNumericNonFloatLiteral(pn) || IsFloatLiteral(m, pn)) return true; - if (IsSimdLiteral(m, pn)) { - if (isSimd) - *isSimd = true; - return true; - } return false; } @@ -2531,104 +2153,6 @@ ExtractNumericNonFloatValue(ParseNode* pn, ParseNode** out = nullptr) } static NumLit -ExtractSimdValue(ModuleValidator& m, ParseNode* pn) -{ - MOZ_ASSERT(IsSimdLiteral(m, pn)); - - SimdType type = SimdType::Count; - JS_ALWAYS_TRUE(IsSimdTuple(m, pn, &type)); - MOZ_ASSERT(CallArgListLength(pn) == GetSimdLanes(type)); - - ParseNode* arg = CallArgList(pn); - switch (type) { - case SimdType::Int8x16: - case SimdType::Uint8x16: { - MOZ_ASSERT(GetSimdLanes(type) == 16); - int8_t val[16]; - for (size_t i = 0; i < 16; i++, arg = NextNode(arg)) { - uint32_t u32; - JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32)); - val[i] = int8_t(u32); - } - MOZ_ASSERT(arg == nullptr); - NumLit::Which w = type == SimdType::Uint8x16 ? NumLit::Uint8x16 : NumLit::Int8x16; - return NumLit(w, SimdConstant::CreateX16(val)); - } - case SimdType::Int16x8: - case SimdType::Uint16x8: { - MOZ_ASSERT(GetSimdLanes(type) == 8); - int16_t val[8]; - for (size_t i = 0; i < 8; i++, arg = NextNode(arg)) { - uint32_t u32; - JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32)); - val[i] = int16_t(u32); - } - MOZ_ASSERT(arg == nullptr); - NumLit::Which w = type == SimdType::Uint16x8 ? NumLit::Uint16x8 : NumLit::Int16x8; - return NumLit(w, SimdConstant::CreateX8(val)); - } - case SimdType::Int32x4: - case SimdType::Uint32x4: { - MOZ_ASSERT(GetSimdLanes(type) == 4); - int32_t val[4]; - for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) { - uint32_t u32; - JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32)); - val[i] = int32_t(u32); - } - MOZ_ASSERT(arg == nullptr); - NumLit::Which w = type == SimdType::Uint32x4 ? NumLit::Uint32x4 : NumLit::Int32x4; - return NumLit(w, SimdConstant::CreateX4(val)); - } - case SimdType::Float32x4: { - MOZ_ASSERT(GetSimdLanes(type) == 4); - float val[4]; - for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) - val[i] = float(ExtractNumericNonFloatValue(arg)); - MOZ_ASSERT(arg == nullptr); - return NumLit(NumLit::Float32x4, SimdConstant::CreateX4(val)); - } - case SimdType::Bool8x16: { - MOZ_ASSERT(GetSimdLanes(type) == 16); - int8_t val[16]; - for (size_t i = 0; i < 16; i++, arg = NextNode(arg)) { - uint32_t u32; - JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32)); - val[i] = u32 ? -1 : 0; - } - MOZ_ASSERT(arg == nullptr); - return NumLit(NumLit::Bool8x16, SimdConstant::CreateX16(val)); - } - case SimdType::Bool16x8: { - MOZ_ASSERT(GetSimdLanes(type) == 8); - int16_t val[8]; - for (size_t i = 0; i < 8; i++, arg = NextNode(arg)) { - uint32_t u32; - JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32)); - val[i] = u32 ? -1 : 0; - } - MOZ_ASSERT(arg == nullptr); - return NumLit(NumLit::Bool16x8, SimdConstant::CreateX8(val)); - } - case SimdType::Bool32x4: { - MOZ_ASSERT(GetSimdLanes(type) == 4); - int32_t val[4]; - for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) { - uint32_t u32; - JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32)); - val[i] = u32 ? -1 : 0; - } - MOZ_ASSERT(arg == nullptr); - return NumLit(NumLit::Bool32x4, SimdConstant::CreateX4(val)); - } - default: - break; - } - - MOZ_CRASH("Unexpected SIMD type."); -} - -static NumLit ExtractNumericLiteral(ModuleValidator& m, ParseNode* pn) { MOZ_ASSERT(IsNumericLiteral(m, pn)); @@ -2636,13 +2160,10 @@ ExtractNumericLiteral(ModuleValidator& m, ParseNode* pn) if (pn->isKind(PNK_CALL)) { // Float literals are explicitly coerced and thus the coerced literal may be // any valid (non-float) numeric literal. - if (CallArgListLength(pn) == 1) { - pn = CallArgList(pn); - double d = ExtractNumericNonFloatValue(pn); - return NumLit(NumLit::Float, DoubleValue(d)); - } - - return ExtractSimdValue(m, pn); + MOZ_ASSERT((CallArgListLength(pn) == 1)); + pn = CallArgList(pn); + double d = ExtractNumericNonFloatValue(pn); + return NumLit(NumLit::Float, DoubleValue(d)); } double d = ExtractNumericNonFloatValue(pn, &pn); @@ -2688,16 +2209,6 @@ IsLiteralInt(const NumLit& lit, uint32_t* u32) case NumLit::Double: case NumLit::Float: case NumLit::OutOfRangeInt: - case NumLit::Int8x16: - case NumLit::Uint8x16: - case NumLit::Int16x8: - case NumLit::Uint16x8: - case NumLit::Int32x4: - case NumLit::Uint32x4: - case NumLit::Float32x4: - case NumLit::Bool8x16: - case NumLit::Bool16x8: - case NumLit::Bool32x4: return false; } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad literal type"); @@ -2714,138 +2225,6 @@ IsLiteralInt(ModuleValidator& m, ParseNode* pn, uint32_t* u32) namespace { -#define CASE(TYPE, OP) case SimdOperation::Fn_##OP: return Op::TYPE##OP; -#define I8x16CASE(OP) CASE(I8x16, OP) -#define I16x8CASE(OP) CASE(I16x8, OP) -#define I32x4CASE(OP) CASE(I32x4, OP) -#define F32x4CASE(OP) CASE(F32x4, OP) -#define B8x16CASE(OP) CASE(B8x16, OP) -#define B16x8CASE(OP) CASE(B16x8, OP) -#define B32x4CASE(OP) CASE(B32x4, OP) -#define ENUMERATE(TYPE, FOR_ALL, DO) \ - switch(op) { \ - case SimdOperation::Constructor: return Op::TYPE##Constructor; \ - FOR_ALL(DO) \ - default: break; \ - } - -static inline Op -SimdToOp(SimdType type, SimdOperation op) -{ - switch (type) { - case SimdType::Uint8x16: - // Handle the special unsigned opcodes, then fall through to Int8x16. - switch (op) { - case SimdOperation::Fn_addSaturate: return Op::I8x16addSaturateU; - case SimdOperation::Fn_subSaturate: return Op::I8x16subSaturateU; - case SimdOperation::Fn_extractLane: return Op::I8x16extractLaneU; - case SimdOperation::Fn_shiftRightByScalar: return Op::I8x16shiftRightByScalarU; - case SimdOperation::Fn_lessThan: return Op::I8x16lessThanU; - case SimdOperation::Fn_lessThanOrEqual: return Op::I8x16lessThanOrEqualU; - case SimdOperation::Fn_greaterThan: return Op::I8x16greaterThanU; - case SimdOperation::Fn_greaterThanOrEqual: return Op::I8x16greaterThanOrEqualU; - case SimdOperation::Fn_fromInt8x16Bits: return Op::Limit; - default: break; - } - MOZ_FALLTHROUGH; - case SimdType::Int8x16: - // Bitcasts Uint8x16 <--> Int8x16 become noops. - switch (op) { - case SimdOperation::Fn_fromUint8x16Bits: return Op::Limit; - case SimdOperation::Fn_fromUint16x8Bits: return Op::I8x16fromInt16x8Bits; - case SimdOperation::Fn_fromUint32x4Bits: return Op::I8x16fromInt32x4Bits; - default: break; - } - ENUMERATE(I8x16, FORALL_INT8X16_ASMJS_OP, I8x16CASE) - break; - - case SimdType::Uint16x8: - // Handle the special unsigned opcodes, then fall through to Int16x8. - switch(op) { - case SimdOperation::Fn_addSaturate: return Op::I16x8addSaturateU; - case SimdOperation::Fn_subSaturate: return Op::I16x8subSaturateU; - case SimdOperation::Fn_extractLane: return Op::I16x8extractLaneU; - case SimdOperation::Fn_shiftRightByScalar: return Op::I16x8shiftRightByScalarU; - case SimdOperation::Fn_lessThan: return Op::I16x8lessThanU; - case SimdOperation::Fn_lessThanOrEqual: return Op::I16x8lessThanOrEqualU; - case SimdOperation::Fn_greaterThan: return Op::I16x8greaterThanU; - case SimdOperation::Fn_greaterThanOrEqual: return Op::I16x8greaterThanOrEqualU; - case SimdOperation::Fn_fromInt16x8Bits: return Op::Limit; - default: break; - } - MOZ_FALLTHROUGH; - case SimdType::Int16x8: - // Bitcasts Uint16x8 <--> Int16x8 become noops. - switch (op) { - case SimdOperation::Fn_fromUint8x16Bits: return Op::I16x8fromInt8x16Bits; - case SimdOperation::Fn_fromUint16x8Bits: return Op::Limit; - case SimdOperation::Fn_fromUint32x4Bits: return Op::I16x8fromInt32x4Bits; - default: break; - } - ENUMERATE(I16x8, FORALL_INT16X8_ASMJS_OP, I16x8CASE) - break; - - case SimdType::Uint32x4: - // Handle the special unsigned opcodes, then fall through to Int32x4. - switch(op) { - case SimdOperation::Fn_shiftRightByScalar: return Op::I32x4shiftRightByScalarU; - case SimdOperation::Fn_lessThan: return Op::I32x4lessThanU; - case SimdOperation::Fn_lessThanOrEqual: return Op::I32x4lessThanOrEqualU; - case SimdOperation::Fn_greaterThan: return Op::I32x4greaterThanU; - case SimdOperation::Fn_greaterThanOrEqual: return Op::I32x4greaterThanOrEqualU; - case SimdOperation::Fn_fromFloat32x4: return Op::I32x4fromFloat32x4U; - case SimdOperation::Fn_fromInt32x4Bits: return Op::Limit; - default: break; - } - MOZ_FALLTHROUGH; - case SimdType::Int32x4: - // Bitcasts Uint32x4 <--> Int32x4 become noops. - switch (op) { - case SimdOperation::Fn_fromUint8x16Bits: return Op::I32x4fromInt8x16Bits; - case SimdOperation::Fn_fromUint16x8Bits: return Op::I32x4fromInt16x8Bits; - case SimdOperation::Fn_fromUint32x4Bits: return Op::Limit; - default: break; - } - ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32x4CASE) - break; - - case SimdType::Float32x4: - switch (op) { - case SimdOperation::Fn_fromUint8x16Bits: return Op::F32x4fromInt8x16Bits; - case SimdOperation::Fn_fromUint16x8Bits: return Op::F32x4fromInt16x8Bits; - case SimdOperation::Fn_fromUint32x4Bits: return Op::F32x4fromInt32x4Bits; - default: break; - } - ENUMERATE(F32x4, FORALL_FLOAT32X4_ASMJS_OP, F32x4CASE) - break; - - case SimdType::Bool8x16: - ENUMERATE(B8x16, FORALL_BOOL_SIMD_OP, B8x16CASE) - break; - - case SimdType::Bool16x8: - ENUMERATE(B16x8, FORALL_BOOL_SIMD_OP, B16x8CASE) - break; - - case SimdType::Bool32x4: - ENUMERATE(B32x4, FORALL_BOOL_SIMD_OP, B32x4CASE) - break; - - default: break; - } - MOZ_CRASH("unexpected SIMD (type, operator) combination"); -} - -#undef CASE -#undef I8x16CASE -#undef I16x8CASE -#undef I32x4CASE -#undef F32x4CASE -#undef B8x16CASE -#undef B16x8CASE -#undef B32x4CASE -#undef ENUMERATE - typedef Vector<PropertyName*, 4, SystemAllocPolicy> NameVector; // Encapsulates the building of an asm bytecode function from an asm.js function @@ -2918,12 +2297,6 @@ class MOZ_STACK_CLASS FunctionValidator MOZ_ASSERT(continuableStack_.empty()); MOZ_ASSERT(breakLabels_.empty()); MOZ_ASSERT(continueLabels_.empty()); - for (auto iter = locals_.all(); !iter.empty(); iter.popFront()) { - if (iter.front().value().type.isSimd()) { - setUsesSimd(); - break; - } - } return m_.mg().finishFuncDef(funcIndex, &fg_); } @@ -3148,33 +2521,6 @@ class MOZ_STACK_CLASS FunctionValidator case NumLit::Double: return encoder().writeOp(Op::F64Const) && encoder().writeFixedF64(lit.toDouble()); - case NumLit::Int8x16: - case NumLit::Uint8x16: - return encoder().writeOp(Op::I8x16Const) && - encoder().writeFixedI8x16(lit.simdValue().asInt8x16()); - case NumLit::Int16x8: - case NumLit::Uint16x8: - return encoder().writeOp(Op::I16x8Const) && - encoder().writeFixedI16x8(lit.simdValue().asInt16x8()); - case NumLit::Int32x4: - case NumLit::Uint32x4: - return encoder().writeOp(Op::I32x4Const) && - encoder().writeFixedI32x4(lit.simdValue().asInt32x4()); - case NumLit::Float32x4: - return encoder().writeOp(Op::F32x4Const) && - encoder().writeFixedF32x4(lit.simdValue().asFloat32x4()); - case NumLit::Bool8x16: - // Boolean vectors use the Int8x16 memory representation. - return encoder().writeOp(Op::B8x16Const) && - encoder().writeFixedI8x16(lit.simdValue().asInt8x16()); - case NumLit::Bool16x8: - // Boolean vectors use the Int16x8 memory representation. - return encoder().writeOp(Op::B16x8Const) && - encoder().writeFixedI16x8(lit.simdValue().asInt16x8()); - case NumLit::Bool32x4: - // Boolean vectors use the Int32x4 memory representation. - return encoder().writeOp(Op::B32x4Const) && - encoder().writeFixedI32x4(lit.simdValue().asInt32x4()); case NumLit::OutOfRangeInt: break; } @@ -3187,12 +2533,6 @@ class MOZ_STACK_CLASS FunctionValidator MOZ_MUST_USE bool prepareCall(ParseNode* pn) { return fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin)); } - MOZ_MUST_USE bool writeSimdOp(SimdType simdType, SimdOperation simdOp) { - Op op = SimdToOp(simdType, simdOp); - if (op == Op::Limit) - return true; - return encoder().writeOp(op); - } }; } /* anonymous namespace */ @@ -3356,7 +2696,7 @@ CheckTypeAnnotation(ModuleValidator& m, ParseNode* coercionNode, Type* coerceTo, default:; } - return m.fail(coercionNode, "must be of the form +x, x|0, fround(x), or a SIMD check(x)"); + return m.fail(coercionNode, "must be of the form +x, x|0 or fround(x)"); } static bool @@ -3474,97 +2814,6 @@ CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr) } static bool -IsSimdValidOperationType(SimdType type, SimdOperation op) -{ -#define CASE(op) case SimdOperation::Fn_##op: - switch(type) { - case SimdType::Int8x16: - switch (op) { - case SimdOperation::Constructor: - case SimdOperation::Fn_fromUint8x16Bits: - case SimdOperation::Fn_fromUint16x8Bits: - case SimdOperation::Fn_fromUint32x4Bits: - FORALL_INT8X16_ASMJS_OP(CASE) return true; - default: return false; - } - break; - case SimdType::Int16x8: - switch (op) { - case SimdOperation::Constructor: - case SimdOperation::Fn_fromUint8x16Bits: - case SimdOperation::Fn_fromUint16x8Bits: - case SimdOperation::Fn_fromUint32x4Bits: - FORALL_INT16X8_ASMJS_OP(CASE) return true; - default: return false; - } - break; - case SimdType::Int32x4: - switch (op) { - case SimdOperation::Constructor: - case SimdOperation::Fn_fromUint8x16Bits: - case SimdOperation::Fn_fromUint16x8Bits: - case SimdOperation::Fn_fromUint32x4Bits: - FORALL_INT32X4_ASMJS_OP(CASE) return true; - default: return false; - } - break; - case SimdType::Uint8x16: - switch (op) { - case SimdOperation::Constructor: - case SimdOperation::Fn_fromInt8x16Bits: - case SimdOperation::Fn_fromUint16x8Bits: - case SimdOperation::Fn_fromUint32x4Bits: - FORALL_INT8X16_ASMJS_OP(CASE) return true; - default: return false; - } - break; - case SimdType::Uint16x8: - switch (op) { - case SimdOperation::Constructor: - case SimdOperation::Fn_fromUint8x16Bits: - case SimdOperation::Fn_fromInt16x8Bits: - case SimdOperation::Fn_fromUint32x4Bits: - FORALL_INT16X8_ASMJS_OP(CASE) return true; - default: return false; - } - break; - case SimdType::Uint32x4: - switch (op) { - case SimdOperation::Constructor: - case SimdOperation::Fn_fromUint8x16Bits: - case SimdOperation::Fn_fromUint16x8Bits: - case SimdOperation::Fn_fromInt32x4Bits: - FORALL_INT32X4_ASMJS_OP(CASE) return true; - default: return false; - } - break; - case SimdType::Float32x4: - switch (op) { - case SimdOperation::Constructor: - case SimdOperation::Fn_fromUint8x16Bits: - case SimdOperation::Fn_fromUint16x8Bits: - case SimdOperation::Fn_fromUint32x4Bits: - FORALL_FLOAT32X4_ASMJS_OP(CASE) return true; - default: return false; - } - break; - case SimdType::Bool8x16: - case SimdType::Bool16x8: - case SimdType::Bool32x4: - switch (op) { - case SimdOperation::Constructor: - FORALL_BOOL_SIMD_OP(CASE) return true; - default: return false; - } - break; - default: - // Unimplemented SIMD type. - return false; - } -#undef CASE -} - -static bool CheckGlobalMathImport(ModuleValidator& m, ParseNode* initNode, PropertyName* varName, PropertyName* field) { @@ -3597,42 +2846,6 @@ CheckGlobalAtomicsImport(ModuleValidator& m, ParseNode* initNode, PropertyName* } static bool -CheckGlobalSimdImport(ModuleValidator& m, ParseNode* initNode, PropertyName* varName, - PropertyName* field) -{ - if (!m.supportsSimd()) - return m.fail(initNode, "SIMD is not supported on this platform"); - - // SIMD constructor, with the form glob.SIMD.[[type]] - SimdType simdType; - if (!IsSimdTypeName(m.cx()->names(), field, &simdType)) - return m.failName(initNode, "'%s' is not a standard SIMD type", field); - - // IsSimdTypeName will return true for any SIMD type supported by the VM. - // - // Since we may not support all of those SIMD types in asm.js, use the - // asm.js-specific IsSimdValidOperationType() to check if this specific - // constructor is supported in asm.js. - if (!IsSimdValidOperationType(simdType, SimdOperation::Constructor)) - return m.failName(initNode, "'%s' is not a supported SIMD type", field); - - return m.addSimdCtor(varName, simdType, field); -} - -static bool -CheckGlobalSimdOperationImport(ModuleValidator& m, const ModuleValidator::Global* global, - ParseNode* initNode, PropertyName* varName, PropertyName* opName) -{ - SimdType simdType = global->simdCtorType(); - SimdOperation simdOp; - if (!m.lookupStandardSimdOpName(opName, &simdOp)) - return m.failName(initNode, "'%s' is not a standard SIMD operation", opName); - if (!IsSimdValidOperationType(simdType, simdOp)) - return m.failName(initNode, "'%s' is not an operation supported by the SIMD type", opName); - return m.addSimdOperation(varName, simdType, simdOp, opName); -} - -static bool CheckGlobalDotImport(ModuleValidator& m, PropertyName* varName, ParseNode* initNode) { ParseNode* base = DotBase(initNode); @@ -3640,7 +2853,7 @@ CheckGlobalDotImport(ModuleValidator& m, PropertyName* varName, ParseNode* initN if (base->isKind(PNK_DOT)) { ParseNode* global = DotBase(base); - PropertyName* mathOrAtomicsOrSimd = DotMember(base); + PropertyName* mathOrAtomics = DotMember(base); PropertyName* globalName = m.globalArgumentName(); if (!globalName) @@ -3654,13 +2867,11 @@ CheckGlobalDotImport(ModuleValidator& m, PropertyName* varName, ParseNode* initN return m.failName(base, "expecting %s.*", globalName); } - if (mathOrAtomicsOrSimd == m.cx()->names().Math) + if (mathOrAtomics == m.cx()->names().Math) return CheckGlobalMathImport(m, initNode, varName, field); - if (mathOrAtomicsOrSimd == m.cx()->names().Atomics) + if (mathOrAtomics == m.cx()->names().Atomics) return CheckGlobalAtomicsImport(m, initNode, varName, field); - if (mathOrAtomicsOrSimd == m.cx()->names().SIMD) - return CheckGlobalSimdImport(m, initNode, varName, field); - return m.failName(base, "expecting %s.{Math|SIMD}", globalName); + return m.failName(base, "expecting %s.{Math|Atomics}", globalName); } if (!base->isKind(PNK_NAME)) @@ -3678,18 +2889,10 @@ CheckGlobalDotImport(ModuleValidator& m, PropertyName* varName, ParseNode* initN return m.failName(initNode, "'%s' is not a standard constant or typed array name", field); } + if (base->name() != m.importArgumentName()) + return m.fail(base, "expected global or import name"); - if (base->name() == m.importArgumentName()) - return m.addFFI(varName, field); - - const ModuleValidator::Global* global = m.lookupGlobal(base->name()); - if (!global) - return m.failName(initNode, "%s not found in module global scope", base->name()); - - if (!global->isSimdCtor()) - return m.failName(base, "expecting SIMD constructor name, got %s", field); - - return CheckGlobalSimdOperationImport(m, global, initNode, varName, field); + return m.addFFI(varName, field); } static bool @@ -3988,8 +3191,6 @@ CheckVarRef(FunctionValidator& f, ParseNode* varRef, Type* type) case ModuleValidator::Global::FuncPtrTable: case ModuleValidator::Global::ArrayView: case ModuleValidator::Global::ArrayViewCtor: - case ModuleValidator::Global::SimdCtor: - case ModuleValidator::Global::SimdOp: break; } return f.failName(varRef, "'%s' may not be accessed by ordinary expressions", name); @@ -4009,12 +3210,10 @@ IsLiteralOrConstInt(FunctionValidator& f, ParseNode* pn, uint32_t* u32) } static const int32_t NoMask = -1; -static const bool YesSimd = true; -static const bool NoSimd = false; static bool CheckArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr, - bool isSimd, Scalar::Type* viewType) + Scalar::Type* viewType) { if (!viewName->isKind(PNK_NAME)) return f.fail(viewName, "base of array access must be a typed array view name"); @@ -4028,7 +3227,7 @@ CheckArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr uint32_t index; if (IsLiteralOrConstInt(f, indexExpr, &index)) { uint64_t byteOffset = uint64_t(index) << TypedArrayShift(*viewType); - uint64_t width = isSimd ? Simd128DataSize : TypedArrayElemSize(*viewType); + uint64_t width = TypedArrayElemSize(*viewType); if (!f.m().tryConstantAccess(byteOffset, width)) return f.fail(indexExpr, "constant index out of range"); @@ -4060,8 +3259,7 @@ CheckArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr if (!pointerType.isIntish()) return f.failf(pointerNode, "%s is not a subtype of int", pointerType.toChars()); } else { - // For SIMD access, and legacy scalar access compatibility, accept - // Int8/Uint8 accesses with no shift. + // For legacy scalar access compatibility, accept Int8/Uint8 accesses with no shift. if (TypedArrayShift(*viewType) != 0) return f.fail(indexExpr, "index expression isn't shifted; must be an Int8/Uint8 access"); @@ -4073,17 +3271,12 @@ CheckArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr if (!CheckExpr(f, pointerNode, &pointerType)) return false; - if (isSimd) { - if (!pointerType.isIntish()) - return f.failf(pointerNode, "%s is not a subtype of intish", pointerType.toChars()); - } else { - if (!pointerType.isInt()) - return f.failf(pointerNode, "%s is not a subtype of int", pointerType.toChars()); - } + if (!pointerType.isInt()) + return f.failf(pointerNode, "%s is not a subtype of int", pointerType.toChars()); } - // Don't generate the mask op if there is no need for it which could happen for - // a shift of zero or a SIMD access. + // Don't generate the mask op if there is no need for it which could happen + // for a shift of zero. if (mask != NoMask) { return f.writeInt32Lit(mask) && f.encoder().writeOp(Op::I32And); @@ -4093,13 +3286,6 @@ CheckArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr } static bool -CheckAndPrepareArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr, - bool isSimd, Scalar::Type* viewType) -{ - return CheckArrayAccess(f, viewName, indexExpr, isSimd, viewType); -} - -static bool WriteArrayAccessFlags(FunctionValidator& f, Scalar::Type viewType) { // asm.js only has naturally-aligned accesses. @@ -4120,7 +3306,7 @@ CheckLoadArray(FunctionValidator& f, ParseNode* elem, Type* type) { Scalar::Type viewType; - if (!CheckAndPrepareArrayAccess(f, ElemBase(elem), ElemIndex(elem), NoSimd, &viewType)) + if (!CheckArrayAccess(f, ElemBase(elem), ElemIndex(elem), &viewType)) return false; switch (viewType) { @@ -4163,7 +3349,7 @@ static bool CheckStoreArray(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type) { Scalar::Type viewType; - if (!CheckAndPrepareArrayAccess(f, ElemBase(lhs), ElemIndex(lhs), NoSimd, &viewType)) + if (!CheckArrayAccess(f, ElemBase(lhs), ElemIndex(lhs), &viewType)) return false; Type rhsType; @@ -4448,7 +3634,7 @@ static bool CheckSharedArrayAtomicAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr, Scalar::Type* viewType) { - if (!CheckAndPrepareArrayAccess(f, viewName, indexExpr, NoSimd, viewType)) + if (!CheckArrayAccess(f, viewName, indexExpr, viewType)) return false; // The global will be sane, CheckArrayAccess checks it. @@ -4753,9 +3939,7 @@ static bool CheckIsArgType(FunctionValidator& f, ParseNode* argNode, Type type) { if (!type.isArgType()) - return f.failf(argNode, - "%s is not a subtype of int, float, double, or an allowed SIMD type", - type.toChars()); + return f.failf(argNode, "%s is not a subtype of int, float or double", type.toChars()); return true; } @@ -4887,8 +4071,6 @@ CheckFFICall(FunctionValidator& f, ParseNode* callNode, unsigned ffiIndex, Type if (ret.isFloat()) return f.fail(callNode, "FFI calls can't return float"); - if (ret.isSimd()) - return f.fail(callNode, "FFI calls can't return SIMD values"); ValTypeVector args; if (!CheckCallArgs<CheckIsExternType>(f, callNode, &args)) @@ -4944,9 +4126,6 @@ CheckCoercionArg(FunctionValidator& f, ParseNode* arg, Type expected, Type* type if (expected.isFloat()) { if (!CheckFloatCoercionArg(f, arg, argType)) return false; - } else if (expected.isSimd()) { - if (!(argType <= expected)) - return f.fail(arg, "argument to SIMD coercion isn't from the correct SIMD type"); } else { MOZ_CRASH("not call coercions"); } @@ -5044,639 +4223,6 @@ CheckMathBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSMathBuiltin return true; } -namespace { -// Include CheckSimdCallArgs in unnamed namespace to avoid MSVC name lookup bug. - -template<class CheckArgOp> -static bool -CheckSimdCallArgs(FunctionValidator& f, ParseNode* call, unsigned expectedArity, - const CheckArgOp& checkArg) -{ - unsigned numArgs = CallArgListLength(call); - if (numArgs != expectedArity) - return f.failf(call, "expected %u arguments to SIMD call, got %u", expectedArity, numArgs); - - ParseNode* arg = CallArgList(call); - for (size_t i = 0; i < numArgs; i++, arg = NextNode(arg)) { - MOZ_ASSERT(!!arg); - Type argType; - if (!CheckExpr(f, arg, &argType)) - return false; - if (!checkArg(f, arg, i, argType)) - return false; - } - - return true; -} - - -class CheckArgIsSubtypeOf -{ - Type formalType_; - - public: - explicit CheckArgIsSubtypeOf(SimdType t) : formalType_(t) {} - - bool operator()(FunctionValidator& f, ParseNode* arg, unsigned argIndex, Type actualType) const - { - if (!(actualType <= formalType_)) { - return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(), - formalType_.toChars()); - } - return true; - } -}; - -static inline Type -SimdToCoercedScalarType(SimdType t) -{ - switch (t) { - case SimdType::Int8x16: - case SimdType::Int16x8: - case SimdType::Int32x4: - case SimdType::Uint8x16: - case SimdType::Uint16x8: - case SimdType::Uint32x4: - case SimdType::Bool8x16: - case SimdType::Bool16x8: - case SimdType::Bool32x4: - return Type::Intish; - case SimdType::Float32x4: - return Type::Floatish; - default: - break; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected SIMD type"); -} - -class CheckSimdScalarArgs -{ - SimdType simdType_; - Type formalType_; - - public: - explicit CheckSimdScalarArgs(SimdType simdType) - : simdType_(simdType), formalType_(SimdToCoercedScalarType(simdType)) - {} - - bool operator()(FunctionValidator& f, ParseNode* arg, unsigned argIndex, Type actualType) const - { - if (!(actualType <= formalType_)) { - // As a special case, accept doublelit arguments to float32x4 ops by - // re-emitting them as float32 constants. - if (simdType_ != SimdType::Float32x4 || !actualType.isDoubleLit()) { - return f.failf(arg, "%s is not a subtype of %s%s", - actualType.toChars(), formalType_.toChars(), - simdType_ == SimdType::Float32x4 ? " or doublelit" : ""); - } - - // We emitted a double literal and actually want a float32. - return f.encoder().writeOp(Op::F32DemoteF64); - } - - return true; - } -}; - -class CheckSimdSelectArgs -{ - Type formalType_; - Type maskType_; - - public: - explicit CheckSimdSelectArgs(SimdType t) : formalType_(t), maskType_(GetBooleanSimdType(t)) {} - - bool operator()(FunctionValidator& f, ParseNode* arg, unsigned argIndex, Type actualType) const - { - // The first argument is the boolean selector, the next two are the - // values to choose from. - Type wantedType = argIndex == 0 ? maskType_ : formalType_; - - if (!(actualType <= wantedType)) { - return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(), - wantedType.toChars()); - } - return true; - } -}; - -class CheckSimdVectorScalarArgs -{ - SimdType formalSimdType_; - - public: - explicit CheckSimdVectorScalarArgs(SimdType t) : formalSimdType_(t) {} - - bool operator()(FunctionValidator& f, ParseNode* arg, unsigned argIndex, Type actualType) const - { - MOZ_ASSERT(argIndex < 2); - if (argIndex == 0) { - // First argument is the vector - if (!(actualType <= Type(formalSimdType_))) { - return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(), - Type(formalSimdType_).toChars()); - } - - return true; - } - - // Second argument is the scalar - return CheckSimdScalarArgs(formalSimdType_)(f, arg, argIndex, actualType); - } -}; - -} // namespace - -static bool -CheckSimdUnary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, - Type* type) -{ - if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType))) - return false; - if (!f.writeSimdOp(opType, op)) - return false; - *type = opType; - return true; -} - -static bool -CheckSimdBinaryShift(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, - Type *type) -{ - if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorScalarArgs(opType))) - return false; - if (!f.writeSimdOp(opType, op)) - return false; - *type = opType; - return true; -} - -static bool -CheckSimdBinaryComp(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, - Type *type) -{ - if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType))) - return false; - if (!f.writeSimdOp(opType, op)) - return false; - *type = GetBooleanSimdType(opType); - return true; -} - -static bool -CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, - Type* type) -{ - if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType))) - return false; - if (!f.writeSimdOp(opType, op)) - return false; - *type = opType; - return true; -} - -static bool -CheckSimdExtractLane(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) -{ - switch (opType) { - case SimdType::Int8x16: - case SimdType::Int16x8: - case SimdType::Int32x4: *type = Type::Signed; break; - case SimdType::Uint8x16: - case SimdType::Uint16x8: - case SimdType::Uint32x4: *type = Type::Unsigned; break; - case SimdType::Float32x4: *type = Type::Float; break; - case SimdType::Bool8x16: - case SimdType::Bool16x8: - case SimdType::Bool32x4: *type = Type::Int; break; - default: MOZ_CRASH("unhandled simd type"); - } - - unsigned numArgs = CallArgListLength(call); - if (numArgs != 2) - return f.failf(call, "expected 2 arguments to SIMD extract, got %u", numArgs); - - ParseNode* arg = CallArgList(call); - - // First argument is the vector - Type vecType; - if (!CheckExpr(f, arg, &vecType)) - return false; - if (!(vecType <= Type(opType))) { - return f.failf(arg, "%s is not a subtype of %s", vecType.toChars(), - Type(opType).toChars()); - } - - arg = NextNode(arg); - - // Second argument is the lane < vector length - uint32_t lane; - if (!IsLiteralOrConstInt(f, arg, &lane)) - return f.failf(arg, "lane selector should be a constant integer literal"); - if (lane >= GetSimdLanes(opType)) - return f.failf(arg, "lane selector should be in bounds"); - - if (!f.writeSimdOp(opType, SimdOperation::Fn_extractLane)) - return false; - if (!f.encoder().writeVarU32(lane)) - return false; - return true; -} - -static bool -CheckSimdReplaceLane(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) -{ - unsigned numArgs = CallArgListLength(call); - if (numArgs != 3) - return f.failf(call, "expected 2 arguments to SIMD replace, got %u", numArgs); - - ParseNode* arg = CallArgList(call); - - // First argument is the vector - Type vecType; - if (!CheckExpr(f, arg, &vecType)) - return false; - if (!(vecType <= Type(opType))) { - return f.failf(arg, "%s is not a subtype of %s", vecType.toChars(), - Type(opType).toChars()); - } - - arg = NextNode(arg); - - // Second argument is the lane < vector length - uint32_t lane; - if (!IsLiteralOrConstInt(f, arg, &lane)) - return f.failf(arg, "lane selector should be a constant integer literal"); - if (lane >= GetSimdLanes(opType)) - return f.failf(arg, "lane selector should be in bounds"); - - arg = NextNode(arg); - - // Third argument is the scalar - Type scalarType; - if (!CheckExpr(f, arg, &scalarType)) - return false; - if (!(scalarType <= SimdToCoercedScalarType(opType))) { - if (opType == SimdType::Float32x4 && scalarType.isDoubleLit()) { - if (!f.encoder().writeOp(Op::F32DemoteF64)) - return false; - } else { - return f.failf(arg, "%s is not the correct type to replace an element of %s", - scalarType.toChars(), vecType.toChars()); - } - } - - if (!f.writeSimdOp(opType, SimdOperation::Fn_replaceLane)) - return false; - if (!f.encoder().writeVarU32(lane)) - return false; - *type = opType; - return true; -} - -typedef bool Bitcast; - -namespace { -// Include CheckSimdCast in unnamed namespace to avoid MSVC name lookup bug (due to the use of Type). - -static bool -CheckSimdCast(FunctionValidator& f, ParseNode* call, SimdType fromType, SimdType toType, - SimdOperation op, Type* type) -{ - if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(fromType))) - return false; - if (!f.writeSimdOp(toType, op)) - return false; - *type = toType; - return true; -} - -} // namespace - -static bool -CheckSimdShuffleSelectors(FunctionValidator& f, ParseNode* lane, - mozilla::Array<uint8_t, 16>& lanes, unsigned numLanes, unsigned maxLane) -{ - for (unsigned i = 0; i < numLanes; i++, lane = NextNode(lane)) { - uint32_t u32; - if (!IsLiteralInt(f.m(), lane, &u32)) - return f.failf(lane, "lane selector should be a constant integer literal"); - if (u32 >= maxLane) - return f.failf(lane, "lane selector should be less than %u", maxLane); - lanes[i] = uint8_t(u32); - } - return true; -} - -static bool -CheckSimdSwizzle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) -{ - const unsigned numLanes = GetSimdLanes(opType); - unsigned numArgs = CallArgListLength(call); - if (numArgs != 1 + numLanes) - return f.failf(call, "expected %u arguments to SIMD swizzle, got %u", 1 + numLanes, - numArgs); - - Type retType = opType; - ParseNode* vec = CallArgList(call); - Type vecType; - if (!CheckExpr(f, vec, &vecType)) - return false; - if (!(vecType <= retType)) - return f.failf(vec, "%s is not a subtype of %s", vecType.toChars(), retType.toChars()); - - if (!f.writeSimdOp(opType, SimdOperation::Fn_swizzle)) - return false; - - mozilla::Array<uint8_t, 16> lanes; - if (!CheckSimdShuffleSelectors(f, NextNode(vec), lanes, numLanes, numLanes)) - return false; - - for (unsigned i = 0; i < numLanes; i++) { - if (!f.encoder().writeFixedU8(lanes[i])) - return false; - } - - *type = retType; - return true; -} - -static bool -CheckSimdShuffle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) -{ - const unsigned numLanes = GetSimdLanes(opType); - unsigned numArgs = CallArgListLength(call); - if (numArgs != 2 + numLanes) - return f.failf(call, "expected %u arguments to SIMD shuffle, got %u", 2 + numLanes, - numArgs); - - Type retType = opType; - ParseNode* arg = CallArgList(call); - for (unsigned i = 0; i < 2; i++, arg = NextNode(arg)) { - Type type; - if (!CheckExpr(f, arg, &type)) - return false; - if (!(type <= retType)) - return f.failf(arg, "%s is not a subtype of %s", type.toChars(), retType.toChars()); - } - - if (!f.writeSimdOp(opType, SimdOperation::Fn_shuffle)) - return false; - - mozilla::Array<uint8_t, 16> lanes; - if (!CheckSimdShuffleSelectors(f, arg, lanes, numLanes, 2 * numLanes)) - return false; - - for (unsigned i = 0; i < numLanes; i++) { - if (!f.encoder().writeFixedU8(uint8_t(lanes[i]))) - return false; - } - - *type = retType; - return true; -} - -static bool -CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call, Scalar::Type* viewType) -{ - ParseNode* view = CallArgList(call); - if (!view->isKind(PNK_NAME)) - return f.fail(view, "expected Uint8Array view as SIMD.*.load/store first argument"); - - ParseNode* indexExpr = NextNode(view); - - if (!CheckAndPrepareArrayAccess(f, view, indexExpr, YesSimd, viewType)) - return false; - - if (*viewType != Scalar::Uint8) - return f.fail(view, "expected Uint8Array view as SIMD.*.load/store first argument"); - - return true; -} - -static bool -CheckSimdLoad(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, - Type* type) -{ - unsigned numArgs = CallArgListLength(call); - if (numArgs != 2) - return f.failf(call, "expected 2 arguments to SIMD load, got %u", numArgs); - - Scalar::Type viewType; - if (!CheckSimdLoadStoreArgs(f, call, &viewType)) - return false; - - if (!f.writeSimdOp(opType, op)) - return false; - - if (!WriteArrayAccessFlags(f, viewType)) - return false; - - *type = opType; - return true; -} - -static bool -CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, - Type* type) -{ - unsigned numArgs = CallArgListLength(call); - if (numArgs != 3) - return f.failf(call, "expected 3 arguments to SIMD store, got %u", numArgs); - - Scalar::Type viewType; - if (!CheckSimdLoadStoreArgs(f, call, &viewType)) - return false; - - Type retType = opType; - ParseNode* vecExpr = NextNode(NextNode(CallArgList(call))); - Type vecType; - if (!CheckExpr(f, vecExpr, &vecType)) - return false; - - if (!f.writeSimdOp(opType, op)) - return false; - - if (!WriteArrayAccessFlags(f, viewType)) - return false; - - if (!(vecType <= retType)) - return f.failf(vecExpr, "%s is not a subtype of %s", vecType.toChars(), retType.toChars()); - - *type = vecType; - return true; -} - -static bool -CheckSimdSelect(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) -{ - if (!CheckSimdCallArgs(f, call, 3, CheckSimdSelectArgs(opType))) - return false; - if (!f.writeSimdOp(opType, SimdOperation::Fn_select)) - return false; - *type = opType; - return true; -} - -static bool -CheckSimdAllTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) -{ - if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType))) - return false; - if (!f.writeSimdOp(opType, SimdOperation::Fn_allTrue)) - return false; - *type = Type::Int; - return true; -} - -static bool -CheckSimdAnyTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) -{ - if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType))) - return false; - if (!f.writeSimdOp(opType, SimdOperation::Fn_anyTrue)) - return false; - *type = Type::Int; - return true; -} - -static bool -CheckSimdCheck(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) -{ - Type coerceTo; - ParseNode* argNode; - if (!IsCoercionCall(f.m(), call, &coerceTo, &argNode)) - return f.failf(call, "expected 1 argument in call to check"); - return CheckCoercionArg(f, argNode, coerceTo, type); -} - -static bool -CheckSimdSplat(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) -{ - if (!CheckSimdCallArgs(f, call, 1, CheckSimdScalarArgs(opType))) - return false; - if (!f.writeSimdOp(opType, SimdOperation::Fn_splat)) - return false; - *type = opType; - return true; -} - -static bool -CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValidator::Global* global, - Type* type) -{ - f.setUsesSimd(); - - MOZ_ASSERT(global->isSimdOperation()); - - SimdType opType = global->simdOperationType(); - - switch (SimdOperation op = global->simdOperation()) { - case SimdOperation::Fn_check: - return CheckSimdCheck(f, call, opType, type); - -#define _CASE(OP) case SimdOperation::Fn_##OP: - FOREACH_SHIFT_SIMD_OP(_CASE) - return CheckSimdBinaryShift(f, call, opType, op, type); - - FOREACH_COMP_SIMD_OP(_CASE) - return CheckSimdBinaryComp(f, call, opType, op, type); - - FOREACH_NUMERIC_SIMD_BINOP(_CASE) - FOREACH_FLOAT_SIMD_BINOP(_CASE) - FOREACH_BITWISE_SIMD_BINOP(_CASE) - FOREACH_SMINT_SIMD_BINOP(_CASE) - return CheckSimdBinary(f, call, opType, op, type); -#undef _CASE - - case SimdOperation::Fn_extractLane: - return CheckSimdExtractLane(f, call, opType, type); - case SimdOperation::Fn_replaceLane: - return CheckSimdReplaceLane(f, call, opType, type); - - case SimdOperation::Fn_fromInt8x16Bits: - return CheckSimdCast(f, call, SimdType::Int8x16, opType, op, type); - case SimdOperation::Fn_fromUint8x16Bits: - return CheckSimdCast(f, call, SimdType::Uint8x16, opType, op, type); - case SimdOperation::Fn_fromInt16x8Bits: - return CheckSimdCast(f, call, SimdType::Int16x8, opType, op, type); - case SimdOperation::Fn_fromUint16x8Bits: - return CheckSimdCast(f, call, SimdType::Uint16x8, opType, op, type); - case SimdOperation::Fn_fromInt32x4: - case SimdOperation::Fn_fromInt32x4Bits: - return CheckSimdCast(f, call, SimdType::Int32x4, opType, op, type); - case SimdOperation::Fn_fromUint32x4: - case SimdOperation::Fn_fromUint32x4Bits: - return CheckSimdCast(f, call, SimdType::Uint32x4, opType, op, type); - case SimdOperation::Fn_fromFloat32x4: - case SimdOperation::Fn_fromFloat32x4Bits: - return CheckSimdCast(f, call, SimdType::Float32x4, opType, op, type); - - case SimdOperation::Fn_abs: - case SimdOperation::Fn_neg: - case SimdOperation::Fn_not: - case SimdOperation::Fn_sqrt: - case SimdOperation::Fn_reciprocalApproximation: - case SimdOperation::Fn_reciprocalSqrtApproximation: - return CheckSimdUnary(f, call, opType, op, type); - - case SimdOperation::Fn_swizzle: - return CheckSimdSwizzle(f, call, opType, type); - case SimdOperation::Fn_shuffle: - return CheckSimdShuffle(f, call, opType, type); - - case SimdOperation::Fn_load: - case SimdOperation::Fn_load1: - case SimdOperation::Fn_load2: - return CheckSimdLoad(f, call, opType, op, type); - case SimdOperation::Fn_store: - case SimdOperation::Fn_store1: - case SimdOperation::Fn_store2: - return CheckSimdStore(f, call, opType, op, type); - - case SimdOperation::Fn_select: - return CheckSimdSelect(f, call, opType, type); - - case SimdOperation::Fn_splat: - return CheckSimdSplat(f, call, opType, type); - - case SimdOperation::Fn_allTrue: - return CheckSimdAllTrue(f, call, opType, type); - case SimdOperation::Fn_anyTrue: - return CheckSimdAnyTrue(f, call, opType, type); - - case SimdOperation::Fn_load3: - case SimdOperation::Fn_store3: - return f.fail(call, "asm.js does not support 3-element SIMD loads or stores"); - - case SimdOperation::Constructor: - MOZ_CRASH("constructors are handled in CheckSimdCtorCall"); - case SimdOperation::Fn_fromFloat64x2Bits: - MOZ_CRASH("NYI"); - } - MOZ_CRASH("unexpected simd operation in CheckSimdOperationCall"); -} - -static bool -CheckSimdCtorCall(FunctionValidator& f, ParseNode* call, const ModuleValidator::Global* global, - Type* type) -{ - f.setUsesSimd(); - - MOZ_ASSERT(call->isKind(PNK_CALL)); - - SimdType simdType = global->simdCtorType(); - unsigned length = GetSimdLanes(simdType); - if (!CheckSimdCallArgs(f, call, length, CheckSimdScalarArgs(simdType))) - return false; - - if (!f.writeSimdOp(simdType, SimdOperation::Constructor)) - return false; - - *type = simdType; - return true; -} - static bool CheckUncoercedCall(FunctionValidator& f, ParseNode* expr, Type* type) { @@ -5688,16 +4234,12 @@ CheckUncoercedCall(FunctionValidator& f, ParseNode* expr, Type* type) return CheckMathBuiltinCall(f, expr, global->mathBuiltinFunction(), type); if (global->isAtomicsFunction()) return CheckAtomicsBuiltinCall(f, expr, global->atomicsBuiltinFunction(), type); - if (global->isSimdCtor()) - return CheckSimdCtorCall(f, expr, global, type); - if (global->isSimdOperation()) - return CheckSimdOperationCall(f, expr, global, type); } return f.fail(expr, "all function calls must either be calls to standard lib math functions, " - "standard atomic functions, standard SIMD constructors or operations, " - "ignored (via f(); or comma-expression), coerced to signed (via f()|0), " - "coerced to float (via fround(f())) or coerced to double (via +f())"); + "standard atomic functions ignored (via f(); or comma-expression), coerced" + " to signed (via f()|0), coerced to float (via fround(f())) or coerced to " + "double (via +f())"); } static bool @@ -5740,10 +4282,7 @@ CoerceResult(FunctionValidator& f, ParseNode* expr, Type expected, Type actual, } break; default: - MOZ_ASSERT(expected.isSimd(), "Incomplete switch"); - if (actual != expected) - return f.failf(expr, "got type %s, expected %s", actual.toChars(), expected.toChars()); - break; + MOZ_CRASH("unexpected uncoerced result type"); } *type = Type::ret(expected); @@ -5761,26 +4300,6 @@ CheckCoercedMathBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSMath } static bool -CheckCoercedSimdCall(FunctionValidator& f, ParseNode* call, const ModuleValidator::Global* global, - Type ret, Type* type) -{ - MOZ_ASSERT(ret.isCanonical()); - - Type actual; - if (global->isSimdCtor()) { - if (!CheckSimdCtorCall(f, call, global, &actual)) - return false; - MOZ_ASSERT(actual.isSimd()); - } else { - MOZ_ASSERT(global->isSimdOperation()); - if (!CheckSimdOperationCall(f, call, global, &actual)) - return false; - } - - return CoerceResult(f, call, ret, actual, type); -} - -static bool CheckCoercedAtomicsBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSAtomicsBuiltinFunction func, Type ret, Type* type) { @@ -5834,9 +4353,6 @@ CheckCoercedCall(FunctionValidator& f, ParseNode* call, Type ret, Type* type) case ModuleValidator::Global::ArrayView: case ModuleValidator::Global::ArrayViewCtor: return f.failName(callee, "'%s' is not callable function", callee->name()); - case ModuleValidator::Global::SimdCtor: - case ModuleValidator::Global::SimdOp: - return CheckCoercedSimdCall(f, call, global, ret, type); case ModuleValidator::Global::Function: break; } @@ -6021,11 +4537,9 @@ CheckConditional(FunctionValidator& f, ParseNode* ternary, Type* type) *type = Type::Double; } else if (thenType.isFloat() && elseType.isFloat()) { *type = Type::Float; - } else if (thenType.isSimd() && elseType == thenType) { - *type = thenType; } else { return f.failf(ternary, "then/else branches of conditional must both produce int, float, " - "double or SIMD types, current types are %s and %s", + "or double; current types are %s and %s", thenType.toChars(), elseType.toChars()); } @@ -6052,16 +4566,6 @@ IsValidIntMultiplyConstant(ModuleValidator& m, ParseNode* expr) case NumLit::Double: case NumLit::Float: case NumLit::OutOfRangeInt: - case NumLit::Int8x16: - case NumLit::Uint8x16: - case NumLit::Int16x8: - case NumLit::Uint16x8: - case NumLit::Int32x4: - case NumLit::Uint32x4: - case NumLit::Float32x4: - case NumLit::Bool8x16: - case NumLit::Bool16x8: - case NumLit::Bool32x4: return false; } @@ -6714,16 +5218,6 @@ CheckCaseExpr(FunctionValidator& f, ParseNode* caseExpr, int32_t* value) return f.fail(caseExpr, "switch case expression out of integer range"); case NumLit::Double: case NumLit::Float: - case NumLit::Int8x16: - case NumLit::Uint8x16: - case NumLit::Int16x8: - case NumLit::Uint16x8: - case NumLit::Int32x4: - case NumLit::Uint32x4: - case NumLit::Float32x4: - case NumLit::Bool8x16: - case NumLit::Bool16x8: - case NumLit::Bool32x4: return f.fail(caseExpr, "switch case expression must be an integer literal"); } @@ -7463,17 +5957,13 @@ HasObjectValueOfMethodPure(JSObject* obj, JSContext* cx) static bool HasPureCoercion(JSContext* cx, HandleValue v) { - // Unsigned SIMD types are not allowed in function signatures. - if (IsVectorObject<Int32x4>(v) || IsVectorObject<Float32x4>(v) || IsVectorObject<Bool32x4>(v)) - return true; - - // Ideally, we'd reject all non-SIMD non-primitives, but Emscripten has a - // bug that generates code that passes functions for some imports. To avoid - // breaking all the code that contains this bug, we make an exception for - // functions that don't have user-defined valueOf or toString, for their - // coercions are not observable and coercion via ToNumber/ToInt32 - // definitely produces NaN/0. We should remove this special case later once - // most apps have been built with newer Emscripten. + // Ideally, we'd reject all non-primitives, but Emscripten has a bug that + // generates code that passes functions for some imports. To avoid breaking + // all the code that contains this bug, we make an exception for functions + // that don't have user-defined valueOf or toString, for their coercions + // are not observable and coercion via ToNumber/ToInt32 definitely produces + // NaN/0. We should remove this special case later once most apps have been + // built with newer Emscripten. if (v.toObject().is<JSFunction>() && HasNoToPrimitiveMethodPure(&v.toObject(), cx) && HasObjectValueOfMethodPure(&v.toObject(), cx) && @@ -7525,58 +6015,6 @@ ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, HandleValue imp *val = Val(RawF64(d)); return true; } - case ValType::I8x16: { - SimdConstant simdConstant; - if (!ToSimdConstant<Int8x16>(cx, v, &simdConstant)) - return false; - *val = Val(simdConstant.asInt8x16()); - return true; - } - case ValType::I16x8: { - SimdConstant simdConstant; - if (!ToSimdConstant<Int16x8>(cx, v, &simdConstant)) - return false; - *val = Val(simdConstant.asInt16x8()); - return true; - } - case ValType::I32x4: { - SimdConstant simdConstant; - if (!ToSimdConstant<Int32x4>(cx, v, &simdConstant)) - return false; - *val = Val(simdConstant.asInt32x4()); - return true; - } - case ValType::F32x4: { - SimdConstant simdConstant; - if (!ToSimdConstant<Float32x4>(cx, v, &simdConstant)) - return false; - *val = Val(simdConstant.asFloat32x4()); - return true; - } - case ValType::B8x16: { - SimdConstant simdConstant; - if (!ToSimdConstant<Bool8x16>(cx, v, &simdConstant)) - return false; - // Bool8x16 uses the same data layout as Int8x16. - *val = Val(simdConstant.asInt8x16()); - return true; - } - case ValType::B16x8: { - SimdConstant simdConstant; - if (!ToSimdConstant<Bool16x8>(cx, v, &simdConstant)) - return false; - // Bool16x8 uses the same data layout as Int16x8. - *val = Val(simdConstant.asInt16x8()); - return true; - } - case ValType::B32x4: { - SimdConstant simdConstant; - if (!ToSimdConstant<Bool32x4>(cx, v, &simdConstant)) - return false; - // Bool32x4 uses the same data layout as Int32x4. - *val = Val(simdConstant.asInt32x4()); - return true; - } } } } @@ -7656,167 +6094,6 @@ ValidateMathBuiltinFunction(JSContext* cx, const AsmJSGlobal& global, HandleValu } static bool -ValidateSimdType(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal, - MutableHandleValue out) -{ - RootedValue v(cx); - if (!GetDataProperty(cx, globalVal, cx->names().SIMD, &v)) - return false; - - SimdType type; - if (global.which() == AsmJSGlobal::SimdCtor) - type = global.simdCtorType(); - else - type = global.simdOperationType(); - - RootedPropertyName simdTypeName(cx, SimdTypeToName(cx->names(), type)); - if (!GetDataProperty(cx, v, simdTypeName, &v)) - return false; - - if (!v.isObject()) - return LinkFail(cx, "bad SIMD type"); - - RootedObject simdDesc(cx, &v.toObject()); - if (!simdDesc->is<SimdTypeDescr>()) - return LinkFail(cx, "bad SIMD type"); - - if (type != simdDesc->as<SimdTypeDescr>().type()) - return LinkFail(cx, "bad SIMD type"); - - out.set(v); - return true; -} - -static bool -ValidateSimdType(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal) -{ - RootedValue _(cx); - return ValidateSimdType(cx, global, globalVal, &_); -} - -static bool -ValidateSimdOperation(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal) -{ - RootedValue v(cx); - JS_ALWAYS_TRUE(ValidateSimdType(cx, global, globalVal, &v)); - - if (!GetDataProperty(cx, v, global.field(), &v)) - return false; - - Native native = nullptr; - switch (global.simdOperationType()) { -#define SET_NATIVE_INT8X16(op) case SimdOperation::Fn_##op: native = simd_int8x16_##op; break; -#define SET_NATIVE_INT16X8(op) case SimdOperation::Fn_##op: native = simd_int16x8_##op; break; -#define SET_NATIVE_INT32X4(op) case SimdOperation::Fn_##op: native = simd_int32x4_##op; break; -#define SET_NATIVE_UINT8X16(op) case SimdOperation::Fn_##op: native = simd_uint8x16_##op; break; -#define SET_NATIVE_UINT16X8(op) case SimdOperation::Fn_##op: native = simd_uint16x8_##op; break; -#define SET_NATIVE_UINT32X4(op) case SimdOperation::Fn_##op: native = simd_uint32x4_##op; break; -#define SET_NATIVE_FLOAT32X4(op) case SimdOperation::Fn_##op: native = simd_float32x4_##op; break; -#define SET_NATIVE_BOOL8X16(op) case SimdOperation::Fn_##op: native = simd_bool8x16_##op; break; -#define SET_NATIVE_BOOL16X8(op) case SimdOperation::Fn_##op: native = simd_bool16x8_##op; break; -#define SET_NATIVE_BOOL32X4(op) case SimdOperation::Fn_##op: native = simd_bool32x4_##op; break; -#define FALLTHROUGH(op) case SimdOperation::Fn_##op: - case SimdType::Int8x16: - switch (global.simdOperation()) { - FORALL_INT8X16_ASMJS_OP(SET_NATIVE_INT8X16) - SET_NATIVE_INT8X16(fromUint8x16Bits) - SET_NATIVE_INT8X16(fromUint16x8Bits) - SET_NATIVE_INT8X16(fromUint32x4Bits) - default: MOZ_CRASH("shouldn't have been validated in the first place"); - } - break; - case SimdType::Int16x8: - switch (global.simdOperation()) { - FORALL_INT16X8_ASMJS_OP(SET_NATIVE_INT16X8) - SET_NATIVE_INT16X8(fromUint8x16Bits) - SET_NATIVE_INT16X8(fromUint16x8Bits) - SET_NATIVE_INT16X8(fromUint32x4Bits) - default: MOZ_CRASH("shouldn't have been validated in the first place"); - } - break; - case SimdType::Int32x4: - switch (global.simdOperation()) { - FORALL_INT32X4_ASMJS_OP(SET_NATIVE_INT32X4) - SET_NATIVE_INT32X4(fromUint8x16Bits) - SET_NATIVE_INT32X4(fromUint16x8Bits) - SET_NATIVE_INT32X4(fromUint32x4Bits) - default: MOZ_CRASH("shouldn't have been validated in the first place"); - } - break; - case SimdType::Uint8x16: - switch (global.simdOperation()) { - FORALL_INT8X16_ASMJS_OP(SET_NATIVE_UINT8X16) - SET_NATIVE_UINT8X16(fromInt8x16Bits) - SET_NATIVE_UINT8X16(fromUint16x8Bits) - SET_NATIVE_UINT8X16(fromUint32x4Bits) - default: MOZ_CRASH("shouldn't have been validated in the first place"); - } - break; - case SimdType::Uint16x8: - switch (global.simdOperation()) { - FORALL_INT16X8_ASMJS_OP(SET_NATIVE_UINT16X8) - SET_NATIVE_UINT16X8(fromUint8x16Bits) - SET_NATIVE_UINT16X8(fromInt16x8Bits) - SET_NATIVE_UINT16X8(fromUint32x4Bits) - default: MOZ_CRASH("shouldn't have been validated in the first place"); - } - break; - case SimdType::Uint32x4: - switch (global.simdOperation()) { - FORALL_INT32X4_ASMJS_OP(SET_NATIVE_UINT32X4) - SET_NATIVE_UINT32X4(fromUint8x16Bits) - SET_NATIVE_UINT32X4(fromUint16x8Bits) - SET_NATIVE_UINT32X4(fromInt32x4Bits) - default: MOZ_CRASH("shouldn't have been validated in the first place"); - } - break; - case SimdType::Float32x4: - switch (global.simdOperation()) { - FORALL_FLOAT32X4_ASMJS_OP(SET_NATIVE_FLOAT32X4) - SET_NATIVE_FLOAT32X4(fromUint8x16Bits) - SET_NATIVE_FLOAT32X4(fromUint16x8Bits) - SET_NATIVE_FLOAT32X4(fromUint32x4Bits) - default: MOZ_CRASH("shouldn't have been validated in the first place"); - } - break; - case SimdType::Bool8x16: - switch (global.simdOperation()) { - FORALL_BOOL_SIMD_OP(SET_NATIVE_BOOL8X16) - default: MOZ_CRASH("shouldn't have been validated in the first place"); - } - break; - case SimdType::Bool16x8: - switch (global.simdOperation()) { - FORALL_BOOL_SIMD_OP(SET_NATIVE_BOOL16X8) - default: MOZ_CRASH("shouldn't have been validated in the first place"); - } - break; - case SimdType::Bool32x4: - switch (global.simdOperation()) { - FORALL_BOOL_SIMD_OP(SET_NATIVE_BOOL32X4) - default: MOZ_CRASH("shouldn't have been validated in the first place"); - } - break; - default: MOZ_CRASH("unhandled simd type"); -#undef FALLTHROUGH -#undef SET_NATIVE_INT8X16 -#undef SET_NATIVE_INT16X8 -#undef SET_NATIVE_INT32X4 -#undef SET_NATIVE_UINT8X16 -#undef SET_NATIVE_UINT16X8 -#undef SET_NATIVE_UINT32X4 -#undef SET_NATIVE_FLOAT32X4 -#undef SET_NATIVE_BOOL8X16 -#undef SET_NATIVE_BOOL16X8 -#undef SET_NATIVE_BOOL32X4 -#undef SET_NATIVE - } - if (!native || !IsNativeFunction(v, native)) - return LinkFail(cx, "bad SIMD.type.* operation"); - return true; -} - -static bool ValidateAtomicsBuiltinFunction(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal) { RootedValue v(cx); @@ -7918,12 +6195,11 @@ CheckBuffer(JSContext* cx, const AsmJSMetadata& metadata, HandleValue bufferVal, // On 64-bit, bounds checks are statically removed so the huge guard // region is always necessary. On 32-bit, allocating a guard page // requires reallocating the incoming ArrayBuffer which could trigger - // OOM. Thus, only ask for a guard page when SIMD is used since SIMD - // allows unaligned memory access (see MaxMemoryAccessSize comment); + // OOM. Thus, don't ask for a guard page in this case. #ifdef WASM_HUGE_MEMORY bool needGuard = true; #else - bool needGuard = metadata.usesSimd; + bool needGuard = false; #endif Rooted<ArrayBufferObject*> arrayBuffer(cx, &buffer->as<ArrayBufferObject>()); if (!ArrayBufferObject::prepareForAsmJS(cx, arrayBuffer, needGuard)) @@ -7976,14 +6252,6 @@ GetImports(JSContext* cx, const AsmJSMetadata& metadata, HandleValue globalVal, if (!ValidateConstant(cx, global, globalVal)) return false; break; - case AsmJSGlobal::SimdCtor: - if (!ValidateSimdType(cx, global, globalVal)) - return false; - break; - case AsmJSGlobal::SimdOp: - if (!ValidateSimdOperation(cx, global, globalVal)) - return false; - break; } } diff --git a/js/src/wasm/AsmJS.h b/js/src/wasm/AsmJS.h index 296617c79b..2bad4b3e4e 100644 --- a/js/src/wasm/AsmJS.h +++ b/js/src/wasm/AsmJS.h @@ -1,6 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2014 Mozilla Foundation + * Copyright 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp index 7a905ecbea..729ce73f35 100644 --- a/js/src/wasm/WasmBaselineCompile.cpp +++ b/js/src/wasm/WasmBaselineCompile.cpp @@ -7094,70 +7094,6 @@ BaseCompiler::emitBody() case uint16_t(Op::F64Ge): CHECK_NEXT(emitComparison(emitCompareF64, ValType::F64, JSOP_GE, MCompare::Compare_Double)); - // SIMD -#define CASE(TYPE, OP, SIGN) \ - case uint16_t(Op::TYPE##OP): \ - MOZ_CRASH("Unimplemented SIMD"); -#define I8x16CASE(OP) CASE(I8x16, OP, SimdSign::Signed) -#define I16x8CASE(OP) CASE(I16x8, OP, SimdSign::Signed) -#define I32x4CASE(OP) CASE(I32x4, OP, SimdSign::Signed) -#define F32x4CASE(OP) CASE(F32x4, OP, SimdSign::NotApplicable) -#define B8x16CASE(OP) CASE(B8x16, OP, SimdSign::NotApplicable) -#define B16x8CASE(OP) CASE(B16x8, OP, SimdSign::NotApplicable) -#define B32x4CASE(OP) CASE(B32x4, OP, SimdSign::NotApplicable) -#define ENUMERATE(TYPE, FORALL, DO) \ - case uint16_t(Op::TYPE##Constructor): \ - FORALL(DO) - - ENUMERATE(I8x16, FORALL_INT8X16_ASMJS_OP, I8x16CASE) - ENUMERATE(I16x8, FORALL_INT16X8_ASMJS_OP, I16x8CASE) - ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32x4CASE) - ENUMERATE(F32x4, FORALL_FLOAT32X4_ASMJS_OP, F32x4CASE) - ENUMERATE(B8x16, FORALL_BOOL_SIMD_OP, B8x16CASE) - ENUMERATE(B16x8, FORALL_BOOL_SIMD_OP, B16x8CASE) - ENUMERATE(B32x4, FORALL_BOOL_SIMD_OP, B32x4CASE) - -#undef CASE -#undef I8x16CASE -#undef I16x8CASE -#undef I32x4CASE -#undef F32x4CASE -#undef B8x16CASE -#undef B16x8CASE -#undef B32x4CASE -#undef ENUMERATE - - case uint16_t(Op::I8x16Const): - case uint16_t(Op::I16x8Const): - case uint16_t(Op::I32x4Const): - case uint16_t(Op::F32x4Const): - case uint16_t(Op::B8x16Const): - case uint16_t(Op::B16x8Const): - case uint16_t(Op::B32x4Const): - case uint16_t(Op::I32x4shiftRightByScalarU): - case uint16_t(Op::I8x16addSaturateU): - case uint16_t(Op::I8x16subSaturateU): - case uint16_t(Op::I8x16shiftRightByScalarU): - case uint16_t(Op::I8x16lessThanU): - case uint16_t(Op::I8x16lessThanOrEqualU): - case uint16_t(Op::I8x16greaterThanU): - case uint16_t(Op::I8x16greaterThanOrEqualU): - case uint16_t(Op::I8x16extractLaneU): - case uint16_t(Op::I16x8addSaturateU): - case uint16_t(Op::I16x8subSaturateU): - case uint16_t(Op::I16x8shiftRightByScalarU): - case uint16_t(Op::I16x8lessThanU): - case uint16_t(Op::I16x8lessThanOrEqualU): - case uint16_t(Op::I16x8greaterThanU): - case uint16_t(Op::I16x8greaterThanOrEqualU): - case uint16_t(Op::I16x8extractLaneU): - case uint16_t(Op::I32x4lessThanU): - case uint16_t(Op::I32x4lessThanOrEqualU): - case uint16_t(Op::I32x4greaterThanU): - case uint16_t(Op::I32x4greaterThanOrEqualU): - case uint16_t(Op::I32x4fromFloat32x4U): - MOZ_CRASH("Unimplemented SIMD"); - // Atomics case uint16_t(Op::I32AtomicsLoad): case uint16_t(Op::I32AtomicsStore): diff --git a/js/src/wasm/WasmBinaryConstants.h b/js/src/wasm/WasmBinaryConstants.h index 4a5ec36b3d..f662814c9e 100644 --- a/js/src/wasm/WasmBinaryConstants.h +++ b/js/src/wasm/WasmBinaryConstants.h @@ -1,6 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2015 Mozilla Foundation + * Copyright 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +19,6 @@ #ifndef wasm_binary_h #define wasm_binary_h -#include "builtin/SIMD.h" - namespace js { namespace wasm { @@ -54,15 +53,6 @@ enum class TypeCode F32 = 0x7d, // SLEB128(-0x03) F64 = 0x7c, // SLEB128(-0x04) - // Only emitted internally for asm.js, likely to get collapsed into I128 - I8x16 = 0x7b, - I16x8 = 0x7a, - I32x4 = 0x79, - F32x4 = 0x78, - B8x16 = 0x77, - B16x8 = 0x76, - B32x4 = 0x75, - // A function pointer with any signature AnyFunc = 0x70, // SLEB128(-0x10) @@ -81,18 +71,6 @@ enum class ValType I64 = uint8_t(TypeCode::I64), F32 = uint8_t(TypeCode::F32), F64 = uint8_t(TypeCode::F64), - - // ------------------------------------------------------------------------ - // The rest of these types are currently only emitted internally when - // compiling asm.js and are rejected by wasm validation. - - I8x16 = uint8_t(TypeCode::I8x16), - I16x8 = uint8_t(TypeCode::I16x8), - I32x4 = uint8_t(TypeCode::I32x4), - F32x4 = uint8_t(TypeCode::F32x4), - B8x16 = uint8_t(TypeCode::B8x16), - B16x8 = uint8_t(TypeCode::B16x8), - B32x4 = uint8_t(TypeCode::B32x4) }; typedef Vector<ValType, 8, SystemAllocPolicy> ValTypeVector; @@ -354,82 +332,6 @@ enum class Op I32AtomicsStore, I32AtomicsBinOp, - // SIMD -#define SIMD_OPCODE(TYPE, OP) TYPE##OP, -#define _(OP) SIMD_OPCODE(I8x16, OP) - FORALL_INT8X16_ASMJS_OP(_) - I8x16Constructor, - I8x16Const, -#undef _ - // Unsigned I8x16 operations. These are the SIMD.Uint8x16 operations that - // behave differently from their SIMD.Int8x16 counterparts. - I8x16extractLaneU, - I8x16addSaturateU, - I8x16subSaturateU, - I8x16shiftRightByScalarU, - I8x16lessThanU, - I8x16lessThanOrEqualU, - I8x16greaterThanU, - I8x16greaterThanOrEqualU, - -#define SIMD_OPCODE(TYPE, OP) TYPE##OP, -#define _(OP) SIMD_OPCODE(I16x8, OP) - FORALL_INT16X8_ASMJS_OP(_) - I16x8Constructor, - I16x8Const, -#undef _ - // Unsigned I16x8 operations. These are the SIMD.Uint16x8 operations that - // behave differently from their SIMD.Int16x8 counterparts. - I16x8extractLaneU, - I16x8addSaturateU, - I16x8subSaturateU, - I16x8shiftRightByScalarU, - I16x8lessThanU, - I16x8lessThanOrEqualU, - I16x8greaterThanU, - I16x8greaterThanOrEqualU, - -#define SIMD_OPCODE(TYPE, OP) TYPE##OP, -#define _(OP) SIMD_OPCODE(I32x4, OP) - FORALL_INT32X4_ASMJS_OP(_) - I32x4Constructor, - I32x4Const, -#undef _ - // Unsigned I32x4 operations. These are the SIMD.Uint32x4 operations that - // behave differently from their SIMD.Int32x4 counterparts. - I32x4shiftRightByScalarU, - I32x4lessThanU, - I32x4lessThanOrEqualU, - I32x4greaterThanU, - I32x4greaterThanOrEqualU, - I32x4fromFloat32x4U, -#define _(OP) SIMD_OPCODE(F32x4, OP) - FORALL_FLOAT32X4_ASMJS_OP(_) - F32x4Constructor, - F32x4Const, -#undef _ - -#define _(OP) SIMD_OPCODE(B8x16, OP) - FORALL_BOOL_SIMD_OP(_) - B8x16Constructor, - B8x16Const, -#undef _ -#undef OPCODE - -#define _(OP) SIMD_OPCODE(B16x8, OP) - FORALL_BOOL_SIMD_OP(_) - B16x8Constructor, - B16x8Const, -#undef _ -#undef OPCODE - -#define _(OP) SIMD_OPCODE(B32x4, OP) - FORALL_BOOL_SIMD_OP(_) - B32x4Constructor, - B32x4Const, -#undef _ -#undef OPCODE - Limit }; diff --git a/js/src/wasm/WasmBinaryFormat.cpp b/js/src/wasm/WasmBinaryFormat.cpp index 1e3914d515..92b634c583 100644 --- a/js/src/wasm/WasmBinaryFormat.cpp +++ b/js/src/wasm/WasmBinaryFormat.cpp @@ -57,17 +57,6 @@ DecodeValType(Decoder& d, ModuleKind kind, ValType* type) case uint8_t(ValType::I64): *type = ValType(unchecked); return true; - case uint8_t(ValType::I8x16): - case uint8_t(ValType::I16x8): - case uint8_t(ValType::I32x4): - case uint8_t(ValType::F32x4): - case uint8_t(ValType::B8x16): - case uint8_t(ValType::B16x8): - case uint8_t(ValType::B32x4): - if (kind != ModuleKind::AsmJS) - return d.fail("bad type"); - *type = ValType(unchecked); - return true; default: break; } diff --git a/js/src/wasm/WasmBinaryFormat.h b/js/src/wasm/WasmBinaryFormat.h index 4db90e999d..0279597cb8 100644 --- a/js/src/wasm/WasmBinaryFormat.h +++ b/js/src/wasm/WasmBinaryFormat.h @@ -1,6 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2016 Mozilla Foundation + * Copyright 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -126,18 +127,6 @@ class Encoder MOZ_MUST_USE bool writeFixedF64(RawF64 d) { return write<uint64_t>(d.bits()); } - MOZ_MUST_USE bool writeFixedI8x16(const I8x16& i8x16) { - return write<I8x16>(i8x16); - } - MOZ_MUST_USE bool writeFixedI16x8(const I16x8& i16x8) { - return write<I16x8>(i16x8); - } - MOZ_MUST_USE bool writeFixedI32x4(const I32x4& i32x4) { - return write<I32x4>(i32x4); - } - MOZ_MUST_USE bool writeFixedF32x4(const F32x4& f32x4) { - return write<F32x4>(f32x4); - } // Variable-length encodings that all use LEB128. @@ -375,18 +364,6 @@ class Decoder *d = RawF64::fromBits(u); return true; } - MOZ_MUST_USE bool readFixedI8x16(I8x16* i8x16) { - return read<I8x16>(i8x16); - } - MOZ_MUST_USE bool readFixedI16x8(I16x8* i16x8) { - return read<I16x8>(i16x8); - } - MOZ_MUST_USE bool readFixedI32x4(I32x4* i32x4) { - return read<I32x4>(i32x4); - } - MOZ_MUST_USE bool readFixedF32x4(F32x4* f32x4) { - return read<F32x4>(f32x4); - } // Variable-length encodings that all use LEB128. @@ -599,26 +576,6 @@ class Decoder ? Op(u8) : Op(uncheckedReadFixedU8() + UINT8_MAX); } - void uncheckedReadFixedI8x16(I8x16* i8x16) { - struct T { I8x16 v; }; - T t = uncheckedRead<T>(); - memcpy(i8x16, &t, sizeof(t)); - } - void uncheckedReadFixedI16x8(I16x8* i16x8) { - struct T { I16x8 v; }; - T t = uncheckedRead<T>(); - memcpy(i16x8, &t, sizeof(t)); - } - void uncheckedReadFixedI32x4(I32x4* i32x4) { - struct T { I32x4 v; }; - T t = uncheckedRead<T>(); - memcpy(i32x4, &t, sizeof(t)); - } - void uncheckedReadFixedF32x4(F32x4* f32x4) { - struct T { F32x4 v; }; - T t = uncheckedRead<T>(); - memcpy(f32x4, &t, sizeof(t)); - } }; // Reusable macro encoding/decoding functions reused by both the two diff --git a/js/src/wasm/WasmBinaryIterator.cpp b/js/src/wasm/WasmBinaryIterator.cpp index 14371e8f22..cedd97eb97 100644 --- a/js/src/wasm/WasmBinaryIterator.cpp +++ b/js/src/wasm/WasmBinaryIterator.cpp @@ -1,6 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2015 Mozilla Foundation + * Copyright 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,20 +43,6 @@ wasm::Classify(Op op) return OpKind::F32; case Op::F64Const: return OpKind::F64; - case Op::I8x16Const: - return OpKind::I8x16; - case Op::I16x8Const: - return OpKind::I16x8; - case Op::I32x4Const: - return OpKind::I32x4; - case Op::B8x16Const: - return OpKind::B8x16; - case Op::B16x8Const: - return OpKind::B16x8; - case Op::B32x4Const: - return OpKind::B32x4; - case Op::F32x4Const: - return OpKind::F32x4; case Op::Br: return OpKind::Br; case Op::BrIf: @@ -95,20 +82,6 @@ wasm::Classify(Op op) case Op::F64Exp: case Op::F64Log: case Op::I32Neg: - case Op::I8x16neg: - case Op::I8x16not: - case Op::I16x8neg: - case Op::I16x8not: - case Op::I32x4neg: - case Op::I32x4not: - case Op::F32x4neg: - case Op::F32x4sqrt: - case Op::F32x4abs: - case Op::F32x4reciprocalApproximation: - case Op::F32x4reciprocalSqrtApproximation: - case Op::B8x16not: - case Op::B16x8not: - case Op::B32x4not: return OpKind::Unary; case Op::I32Add: case Op::I32Sub: @@ -159,49 +132,6 @@ wasm::Classify(Op op) case Op::F64Mod: case Op::F64Pow: case Op::F64Atan2: - case Op::I8x16add: - case Op::I8x16sub: - case Op::I8x16mul: - case Op::I8x16addSaturate: - case Op::I8x16subSaturate: - case Op::I8x16addSaturateU: - case Op::I8x16subSaturateU: - case Op::I8x16and: - case Op::I8x16or: - case Op::I8x16xor: - case Op::I16x8add: - case Op::I16x8sub: - case Op::I16x8mul: - case Op::I16x8addSaturate: - case Op::I16x8subSaturate: - case Op::I16x8addSaturateU: - case Op::I16x8subSaturateU: - case Op::I16x8and: - case Op::I16x8or: - case Op::I16x8xor: - case Op::I32x4add: - case Op::I32x4sub: - case Op::I32x4mul: - case Op::I32x4and: - case Op::I32x4or: - case Op::I32x4xor: - case Op::F32x4add: - case Op::F32x4sub: - case Op::F32x4mul: - case Op::F32x4div: - case Op::F32x4min: - case Op::F32x4max: - case Op::F32x4minNum: - case Op::F32x4maxNum: - case Op::B8x16and: - case Op::B8x16or: - case Op::B8x16xor: - case Op::B16x8and: - case Op::B16x8or: - case Op::B16x8xor: - case Op::B32x4and: - case Op::B32x4or: - case Op::B32x4xor: return OpKind::Binary; case Op::I32Eq: case Op::I32Ne: @@ -263,22 +193,6 @@ wasm::Classify(Op op) case Op::F64ConvertUI64: case Op::F64ReinterpretI64: case Op::F64PromoteF32: - case Op::I32x4fromFloat32x4: - case Op::I32x4fromFloat32x4U: - case Op::F32x4fromInt32x4: - case Op::F32x4fromUint32x4: - case Op::I32x4fromFloat32x4Bits: - case Op::I32x4fromInt8x16Bits: - case Op::I32x4fromInt16x8Bits: - case Op::I16x8fromInt8x16Bits: - case Op::I16x8fromInt32x4Bits: - case Op::I16x8fromFloat32x4Bits: - case Op::I8x16fromInt16x8Bits: - case Op::I8x16fromInt32x4Bits: - case Op::I8x16fromFloat32x4Bits: - case Op::F32x4fromInt8x16Bits: - case Op::F32x4fromInt16x8Bits: - case Op::F32x4fromInt32x4Bits: return OpKind::Conversion; case Op::I32Load8S: case Op::I32Load8U: @@ -294,16 +208,6 @@ wasm::Classify(Op op) case Op::I64Load: case Op::F32Load: case Op::F64Load: - case Op::I8x16load: - case Op::I16x8load: - case Op::I32x4load: - case Op::I32x4load1: - case Op::I32x4load2: - case Op::I32x4load3: - case Op::F32x4load: - case Op::F32x4load1: - case Op::F32x4load2: - case Op::F32x4load3: return OpKind::Load; case Op::I32Store8: case Op::I32Store16: @@ -326,16 +230,6 @@ wasm::Classify(Op op) case Op::F64TeeStore: case Op::F32TeeStoreF64: case Op::F64TeeStoreF32: - case Op::I8x16store: - case Op::I16x8store: - case Op::I32x4store: - case Op::I32x4store1: - case Op::I32x4store2: - case Op::I32x4store3: - case Op::F32x4store: - case Op::F32x4store1: - case Op::F32x4store2: - case Op::F32x4store3: return OpKind::TeeStore; case Op::Select: return OpKind::Select; @@ -377,116 +271,6 @@ wasm::Classify(Op op) return OpKind::AtomicCompareExchange; case Op::I32AtomicsExchange: return OpKind::AtomicExchange; - case Op::I8x16extractLane: - case Op::I8x16extractLaneU: - case Op::I16x8extractLane: - case Op::I16x8extractLaneU: - case Op::I32x4extractLane: - case Op::F32x4extractLane: - case Op::B8x16extractLane: - case Op::B16x8extractLane: - case Op::B32x4extractLane: - return OpKind::ExtractLane; - case Op::I8x16replaceLane: - case Op::I16x8replaceLane: - case Op::I32x4replaceLane: - case Op::F32x4replaceLane: - case Op::B8x16replaceLane: - case Op::B16x8replaceLane: - case Op::B32x4replaceLane: - return OpKind::ReplaceLane; - case Op::I8x16swizzle: - case Op::I16x8swizzle: - case Op::I32x4swizzle: - case Op::F32x4swizzle: - return OpKind::Swizzle; - case Op::I8x16shuffle: - case Op::I16x8shuffle: - case Op::I32x4shuffle: - case Op::F32x4shuffle: - return OpKind::Shuffle; - case Op::I16x8check: - case Op::I16x8splat: - case Op::I32x4check: - case Op::I32x4splat: - case Op::I8x16check: - case Op::I8x16splat: - case Op::F32x4check: - case Op::F32x4splat: - case Op::B16x8check: - case Op::B16x8splat: - case Op::B32x4check: - case Op::B32x4splat: - case Op::B8x16check: - case Op::B8x16splat: - return OpKind::Splat; - case Op::I8x16select: - case Op::I16x8select: - case Op::I32x4select: - case Op::F32x4select: - return OpKind::SimdSelect; - case Op::I8x16Constructor: - case Op::I16x8Constructor: - case Op::I32x4Constructor: - case Op::F32x4Constructor: - case Op::B8x16Constructor: - case Op::B16x8Constructor: - case Op::B32x4Constructor: - return OpKind::SimdCtor; - case Op::B8x16allTrue: - case Op::B8x16anyTrue: - case Op::B16x8allTrue: - case Op::B16x8anyTrue: - case Op::B32x4allTrue: - case Op::B32x4anyTrue: - return OpKind::SimdBooleanReduction; - case Op::I8x16shiftLeftByScalar: - case Op::I8x16shiftRightByScalar: - case Op::I8x16shiftRightByScalarU: - case Op::I16x8shiftLeftByScalar: - case Op::I16x8shiftRightByScalar: - case Op::I16x8shiftRightByScalarU: - case Op::I32x4shiftLeftByScalar: - case Op::I32x4shiftRightByScalar: - case Op::I32x4shiftRightByScalarU: - return OpKind::SimdShiftByScalar; - case Op::I8x16equal: - case Op::I8x16notEqual: - case Op::I8x16greaterThan: - case Op::I8x16greaterThanOrEqual: - case Op::I8x16lessThan: - case Op::I8x16lessThanOrEqual: - case Op::I8x16greaterThanU: - case Op::I8x16greaterThanOrEqualU: - case Op::I8x16lessThanU: - case Op::I8x16lessThanOrEqualU: - case Op::I16x8equal: - case Op::I16x8notEqual: - case Op::I16x8greaterThan: - case Op::I16x8greaterThanOrEqual: - case Op::I16x8lessThan: - case Op::I16x8lessThanOrEqual: - case Op::I16x8greaterThanU: - case Op::I16x8greaterThanOrEqualU: - case Op::I16x8lessThanU: - case Op::I16x8lessThanOrEqualU: - case Op::I32x4equal: - case Op::I32x4notEqual: - case Op::I32x4greaterThan: - case Op::I32x4greaterThanOrEqual: - case Op::I32x4lessThan: - case Op::I32x4lessThanOrEqual: - case Op::I32x4greaterThanU: - case Op::I32x4greaterThanOrEqualU: - case Op::I32x4lessThanU: - case Op::I32x4lessThanOrEqualU: - case Op::F32x4equal: - case Op::F32x4notEqual: - case Op::F32x4greaterThan: - case Op::F32x4greaterThanOrEqual: - case Op::F32x4lessThan: - case Op::F32x4lessThanOrEqual: - return OpKind::SimdComparison; case Op::CurrentMemory: return OpKind::CurrentMemory; case Op::GrowMemory: diff --git a/js/src/wasm/WasmBinaryIterator.h b/js/src/wasm/WasmBinaryIterator.h index 522182ed92..ccad80f9dd 100644 --- a/js/src/wasm/WasmBinaryIterator.h +++ b/js/src/wasm/WasmBinaryIterator.h @@ -1,6 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2016 Mozilla Foundation + * Copyright 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,13 +49,6 @@ enum class OpKind { I64, F32, F64, - I8x16, - I16x8, - I32x4, - F32x4, - B8x16, - B16x8, - B32x4, Br, BrIf, BrTable, @@ -93,11 +87,6 @@ enum class OpKind { Swizzle, Shuffle, Splat, - SimdSelect, - SimdCtor, - SimdBooleanReduction, - SimdShiftByScalar, - SimdComparison, }; // Return the OpKind for a given Op. This is used for sanity-checking that @@ -319,30 +308,6 @@ class MOZ_STACK_CLASS OpIter : private Policy *out = d_.uncheckedReadFixedF64(); return true; } - MOZ_MUST_USE bool readFixedI8x16(I8x16* out) { - if (Validate) - return d_.readFixedI8x16(out); - d_.uncheckedReadFixedI8x16(out); - return true; - } - MOZ_MUST_USE bool readFixedI16x8(I16x8* out) { - if (Validate) - return d_.readFixedI16x8(out); - d_.uncheckedReadFixedI16x8(out); - return true; - } - MOZ_MUST_USE bool readFixedI32x4(I32x4* out) { - if (Validate) - return d_.readFixedI32x4(out); - d_.uncheckedReadFixedI32x4(out); - return true; - } - MOZ_MUST_USE bool readFixedF32x4(F32x4* out) { - if (Validate) - return d_.readFixedF32x4(out); - d_.uncheckedReadFixedF32x4(out); - return true; - } MOZ_MUST_USE bool readAtomicViewType(Scalar::Type* viewType) { uint8_t x; @@ -576,13 +541,6 @@ class MOZ_STACK_CLASS OpIter : private Policy MOZ_MUST_USE bool readI64Const(int64_t* i64); MOZ_MUST_USE bool readF32Const(RawF32* f32); MOZ_MUST_USE bool readF64Const(RawF64* f64); - MOZ_MUST_USE bool readI8x16Const(I8x16* i8x16); - MOZ_MUST_USE bool readI16x8Const(I16x8* i16x8); - MOZ_MUST_USE bool readI32x4Const(I32x4* i32x4); - MOZ_MUST_USE bool readF32x4Const(F32x4* f32x4); - MOZ_MUST_USE bool readB8x16Const(I8x16* i8x16); - MOZ_MUST_USE bool readB16x8Const(I16x8* i16x8); - MOZ_MUST_USE bool readB32x4Const(I32x4* i32x4); MOZ_MUST_USE bool readCall(uint32_t* calleeIndex); MOZ_MUST_USE bool readCallIndirect(uint32_t* sigIndex, Value* callee); MOZ_MUST_USE bool readOldCallIndirect(uint32_t* sigIndex); @@ -606,27 +564,6 @@ class MOZ_STACK_CLASS OpIter : private Policy MOZ_MUST_USE bool readAtomicExchange(LinearMemoryAddress<Value>* addr, Scalar::Type* viewType, Value* newValue); - MOZ_MUST_USE bool readSimdComparison(ValType simdType, Value* lhs, - Value* rhs); - MOZ_MUST_USE bool readSimdShiftByScalar(ValType simdType, Value* lhs, - Value* rhs); - MOZ_MUST_USE bool readSimdBooleanReduction(ValType simdType, Value* input); - MOZ_MUST_USE bool readExtractLane(ValType simdType, uint8_t* lane, - Value* vector); - MOZ_MUST_USE bool readReplaceLane(ValType simdType, uint8_t* lane, - Value* vector, Value* scalar); - MOZ_MUST_USE bool readSplat(ValType simdType, Value* scalar); - MOZ_MUST_USE bool readSwizzle(ValType simdType, uint8_t (* lanes)[16], Value* vector); - MOZ_MUST_USE bool readShuffle(ValType simdType, uint8_t (* lanes)[16], - Value* lhs, Value* rhs); - MOZ_MUST_USE bool readSimdSelect(ValType simdType, Value* trueValue, - Value* falseValue, - Value* condition); - MOZ_MUST_USE bool readSimdCtor(); - MOZ_MUST_USE bool readSimdCtorArg(ValType elementType, uint32_t numElements, uint32_t argIndex, - Value* arg); - MOZ_MUST_USE bool readSimdCtorArgsEnd(uint32_t numElements); - MOZ_MUST_USE bool readSimdCtorReturn(ValType simdType); // At a location where readOp is allowed, peek at the next opcode // without consuming it or updating any internal state. @@ -827,13 +764,6 @@ OpIter<Policy>::readBlockType(ExprType* type) case uint8_t(ExprType::I64): case uint8_t(ExprType::F32): case uint8_t(ExprType::F64): - case uint8_t(ExprType::I8x16): - case uint8_t(ExprType::I16x8): - case uint8_t(ExprType::I32x4): - case uint8_t(ExprType::F32x4): - case uint8_t(ExprType::B8x16): - case uint8_t(ExprType::B16x8): - case uint8_t(ExprType::B32x4): break; default: return fail("invalid inline block type"); @@ -1649,118 +1579,6 @@ OpIter<Policy>::readF64Const(RawF64* f64) template <typename Policy> inline bool -OpIter<Policy>::readI8x16Const(I8x16* i8x16) -{ - MOZ_ASSERT(Classify(op_) == OpKind::I8x16); - - I8x16 unused; - if (!readFixedI8x16(Output ? i8x16 : &unused)) - return false; - - if (!push(ValType::I8x16)) - return false; - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readI16x8Const(I16x8* i16x8) -{ - MOZ_ASSERT(Classify(op_) == OpKind::I16x8); - - I16x8 unused; - if (!readFixedI16x8(Output ? i16x8 : &unused)) - return false; - - if (!push(ValType::I16x8)) - return false; - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readI32x4Const(I32x4* i32x4) -{ - MOZ_ASSERT(Classify(op_) == OpKind::I32x4); - - I32x4 unused; - if (!readFixedI32x4(Output ? i32x4 : &unused)) - return false; - - if (!push(ValType::I32x4)) - return false; - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readF32x4Const(F32x4* f32x4) -{ - MOZ_ASSERT(Classify(op_) == OpKind::F32x4); - - F32x4 unused; - if (!readFixedF32x4(Output ? f32x4 : &unused)) - return false; - - if (!push(ValType::F32x4)) - return false; - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readB8x16Const(I8x16* i8x16) -{ - MOZ_ASSERT(Classify(op_) == OpKind::B8x16); - - I8x16 unused; - if (!readFixedI8x16(Output ? i8x16 : &unused)) - return false; - - if (!push(ValType::B8x16)) - return false; - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readB16x8Const(I16x8* i16x8) -{ - MOZ_ASSERT(Classify(op_) == OpKind::B16x8); - - I16x8 unused; - if (!readFixedI16x8(Output ? i16x8 : &unused)) - return false; - - if (!push(ValType::B16x8)) - return false; - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readB32x4Const(I32x4* i32x4) -{ - MOZ_ASSERT(Classify(op_) == OpKind::B32x4); - - I32x4 unused; - if (!readFixedI32x4(Output ? i32x4 : &unused)) - return false; - - if (!push(ValType::B32x4)) - return false; - - return true; -} - -template <typename Policy> -inline bool OpIter<Policy>::readCall(uint32_t* calleeIndex) { MOZ_ASSERT(Classify(op_) == OpKind::Call); @@ -1997,239 +1815,6 @@ OpIter<Policy>::readAtomicExchange(LinearMemoryAddress<Value>* addr, Scalar::Typ return true; } -template <typename Policy> -inline bool -OpIter<Policy>::readSimdComparison(ValType simdType, Value* lhs, Value* rhs) -{ - MOZ_ASSERT(Classify(op_) == OpKind::SimdComparison); - - if (!popWithType(simdType, rhs)) - return false; - - if (!popWithType(simdType, lhs)) - return false; - - infalliblePush(SimdBoolType(simdType)); - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readSimdShiftByScalar(ValType simdType, Value* lhs, Value* rhs) -{ - MOZ_ASSERT(Classify(op_) == OpKind::SimdShiftByScalar); - - if (!popWithType(ValType::I32, rhs)) - return false; - - if (!popWithType(simdType, lhs)) - return false; - - infalliblePush(simdType); - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readSimdBooleanReduction(ValType simdType, Value* input) -{ - MOZ_ASSERT(Classify(op_) == OpKind::SimdBooleanReduction); - - if (!popWithType(simdType, input)) - return false; - - infalliblePush(ValType::I32); - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readExtractLane(ValType simdType, uint8_t* lane, Value* vector) -{ - MOZ_ASSERT(Classify(op_) == OpKind::ExtractLane); - - uint32_t laneBits; - if (!readVarU32(&laneBits)) - return false; - - if (Validate && laneBits >= NumSimdElements(simdType)) - return fail("simd lane out of bounds for simd type"); - - if (!popWithType(simdType, vector)) - return false; - - infalliblePush(SimdElementType(simdType)); - - if (Output) - *lane = uint8_t(laneBits); - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readReplaceLane(ValType simdType, uint8_t* lane, Value* vector, Value* scalar) -{ - MOZ_ASSERT(Classify(op_) == OpKind::ReplaceLane); - - uint32_t laneBits; - if (!readVarU32(&laneBits)) - return false; - - if (Validate && laneBits >= NumSimdElements(simdType)) - return fail("simd lane out of bounds for simd type"); - - if (!popWithType(SimdElementType(simdType), scalar)) - return false; - - if (!popWithType(simdType, vector)) - return false; - - infalliblePush(simdType); - - if (Output) - *lane = uint8_t(laneBits); - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readSplat(ValType simdType, Value* scalar) -{ - MOZ_ASSERT(Classify(op_) == OpKind::Splat); - - if (!popWithType(SimdElementType(simdType), scalar)) - return false; - - infalliblePush(simdType); - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readSwizzle(ValType simdType, uint8_t (* lanes)[16], Value* vector) -{ - MOZ_ASSERT(Classify(op_) == OpKind::Swizzle); - - uint32_t numSimdLanes = NumSimdElements(simdType); - MOZ_ASSERT(numSimdLanes <= mozilla::ArrayLength(*lanes)); - for (uint32_t i = 0; i < numSimdLanes; ++i) { - uint8_t validateLane; - if (!readFixedU8(Output ? &(*lanes)[i] : &validateLane)) - return fail("unable to read swizzle lane"); - if (Validate && (Output ? (*lanes)[i] : validateLane) >= numSimdLanes) - return fail("swizzle index out of bounds"); - } - - if (!popWithType(simdType, vector)) - return false; - - infalliblePush(simdType); - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readShuffle(ValType simdType, uint8_t (* lanes)[16], Value* lhs, Value* rhs) -{ - MOZ_ASSERT(Classify(op_) == OpKind::Shuffle); - - uint32_t numSimdLanes = NumSimdElements(simdType); - MOZ_ASSERT(numSimdLanes <= mozilla::ArrayLength(*lanes)); - for (uint32_t i = 0; i < numSimdLanes; ++i) { - uint8_t validateLane; - if (!readFixedU8(Output ? &(*lanes)[i] : &validateLane)) - return fail("unable to read shuffle lane"); - if (Validate && (Output ? (*lanes)[i] : validateLane) >= numSimdLanes * 2) - return fail("shuffle index out of bounds"); - } - - if (!popWithType(simdType, rhs)) - return false; - - if (!popWithType(simdType, lhs)) - return false; - - infalliblePush(simdType); - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readSimdSelect(ValType simdType, Value* trueValue, Value* falseValue, - Value* condition) -{ - MOZ_ASSERT(Classify(op_) == OpKind::SimdSelect); - - if (!popWithType(simdType, falseValue)) - return false; - if (!popWithType(simdType, trueValue)) - return false; - if (!popWithType(SimdBoolType(simdType), condition)) - return false; - - infalliblePush(simdType); - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readSimdCtor() -{ - MOZ_ASSERT(Classify(op_) == OpKind::SimdCtor); - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readSimdCtorArg(ValType elementType, uint32_t numElements, uint32_t index, - Value* arg) -{ - MOZ_ASSERT(Classify(op_) == OpKind::SimdCtor); - MOZ_ASSERT(numElements > 0); - - TypeAndValue<Value> tv; - - if (!peek(numElements - index, &tv)) - return false; - if (!checkType(tv.type(), elementType)) - return false; - - *arg = tv.value(); - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readSimdCtorArgsEnd(uint32_t numElements) -{ - MOZ_ASSERT(Classify(op_) == OpKind::SimdCtor); - MOZ_ASSERT(numElements <= valueStack_.length()); - - valueStack_.shrinkBy(numElements); - - return true; -} - -template <typename Policy> -inline bool -OpIter<Policy>::readSimdCtorReturn(ValType simdType) -{ - MOZ_ASSERT(Classify(op_) == OpKind::SimdCtor); - - infalliblePush(simdType); - - return true; -} } // namespace wasm } // namespace js diff --git a/js/src/wasm/WasmGenerator.cpp b/js/src/wasm/WasmGenerator.cpp index 7bf02fbe70..daff135077 100644 --- a/js/src/wasm/WasmGenerator.cpp +++ b/js/src/wasm/WasmGenerator.cpp @@ -1,6 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2015 Mozilla Foundation + * Copyright 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -665,15 +666,6 @@ ModuleGenerator::allocateGlobal(GlobalDesc* global) case ValType::F64: width = 8; break; - case ValType::I8x16: - case ValType::I16x8: - case ValType::I32x4: - case ValType::F32x4: - case ValType::B8x16: - case ValType::B16x8: - case ValType::B32x4: - width = 16; - break; } uint32_t offset; diff --git a/js/src/wasm/WasmInstance.cpp b/js/src/wasm/WasmInstance.cpp index b98d4344f9..40197c6ed1 100644 --- a/js/src/wasm/WasmInstance.cpp +++ b/js/src/wasm/WasmInstance.cpp @@ -1,6 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2016 Mozilla Foundation + * Copyright 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -158,14 +159,10 @@ Instance::callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, con hasI64Arg = true; break; } - case ValType::I8x16: - case ValType::I16x8: - case ValType::I32x4: - case ValType::F32x4: - case ValType::B8x16: - case ValType::B16x8: - case ValType::B32x4: - MOZ_CRASH("unhandled type in callImport"); + default: { + MOZ_ASSERT("unhandled type in callImport"); + return false; + } } } @@ -230,13 +227,6 @@ Instance::callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, con case ValType::I64: MOZ_CRASH("can't happen because of above guard"); case ValType::F32: type = TypeSet::DoubleType(); break; case ValType::F64: type = TypeSet::DoubleType(); break; - case ValType::I8x16: MOZ_CRASH("NYI"); - case ValType::I16x8: MOZ_CRASH("NYI"); - case ValType::I32x4: MOZ_CRASH("NYI"); - case ValType::F32x4: MOZ_CRASH("NYI"); - case ValType::B8x16: MOZ_CRASH("NYI"); - case ValType::B16x8: MOZ_CRASH("NYI"); - case ValType::B32x4: MOZ_CRASH("NYI"); } if (!TypeScript::ArgTypes(script, i)->hasType(type)) return true; @@ -541,12 +531,12 @@ Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args) // The calling convention for an external call into wasm is to pass an // array of 16-byte values where each value contains either a coerced int32 - // (in the low word), a double value (in the low dword) or a SIMD vector - // value, with the coercions specified by the wasm signature. The external - // entry point unpacks this array into the system-ABI-specified registers - // and stack memory and then calls into the internal entry point. The return - // value is stored in the first element of the array (which, therefore, must - // have length >= 1). + // (in the low word), or a double value (in the low dword) value, with the + // coercions specified by the wasm signature. The external entry point + // unpacks this array into the system-ABI-specified registers and stack + // memory and then calls into the internal entry point. The return value is + // stored in the first element of the array (which, therefore, must have + // length >= 1). Vector<ExportArg, 8> exportArgs(cx); if (!exportArgs.resize(Max<size_t>(1, func.sig().args().length()))) return false; @@ -585,58 +575,6 @@ Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args) if (!ToNumber(cx, v, (double*)&exportArgs[i])) return false; break; - case ValType::I8x16: { - SimdConstant simd; - if (!ToSimdConstant<Int8x16>(cx, v, &simd)) - return false; - memcpy(&exportArgs[i], simd.asInt8x16(), Simd128DataSize); - break; - } - case ValType::I16x8: { - SimdConstant simd; - if (!ToSimdConstant<Int16x8>(cx, v, &simd)) - return false; - memcpy(&exportArgs[i], simd.asInt16x8(), Simd128DataSize); - break; - } - case ValType::I32x4: { - SimdConstant simd; - if (!ToSimdConstant<Int32x4>(cx, v, &simd)) - return false; - memcpy(&exportArgs[i], simd.asInt32x4(), Simd128DataSize); - break; - } - case ValType::F32x4: { - SimdConstant simd; - if (!ToSimdConstant<Float32x4>(cx, v, &simd)) - return false; - memcpy(&exportArgs[i], simd.asFloat32x4(), Simd128DataSize); - break; - } - case ValType::B8x16: { - SimdConstant simd; - if (!ToSimdConstant<Bool8x16>(cx, v, &simd)) - return false; - // Bool8x16 uses the same representation as Int8x16. - memcpy(&exportArgs[i], simd.asInt8x16(), Simd128DataSize); - break; - } - case ValType::B16x8: { - SimdConstant simd; - if (!ToSimdConstant<Bool16x8>(cx, v, &simd)) - return false; - // Bool16x8 uses the same representation as Int16x8. - memcpy(&exportArgs[i], simd.asInt16x8(), Simd128DataSize); - break; - } - case ValType::B32x4: { - SimdConstant simd; - if (!ToSimdConstant<Bool32x4>(cx, v, &simd)) - return false; - // Bool32x4 uses the same representation as Int32x4. - memcpy(&exportArgs[i], simd.asInt32x4(), Simd128DataSize); - break; - } } } @@ -703,41 +641,6 @@ Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args) } args.rval().set(NumberValue(*(double*)retAddr)); break; - case ExprType::I8x16: - retObj = CreateSimd<Int8x16>(cx, (int8_t*)retAddr); - if (!retObj) - return false; - break; - case ExprType::I16x8: - retObj = CreateSimd<Int16x8>(cx, (int16_t*)retAddr); - if (!retObj) - return false; - break; - case ExprType::I32x4: - retObj = CreateSimd<Int32x4>(cx, (int32_t*)retAddr); - if (!retObj) - return false; - break; - case ExprType::F32x4: - retObj = CreateSimd<Float32x4>(cx, (float*)retAddr); - if (!retObj) - return false; - break; - case ExprType::B8x16: - retObj = CreateSimd<Bool8x16>(cx, (int8_t*)retAddr); - if (!retObj) - return false; - break; - case ExprType::B16x8: - retObj = CreateSimd<Bool16x8>(cx, (int16_t*)retAddr); - if (!retObj) - return false; - break; - case ExprType::B32x4: - retObj = CreateSimd<Bool32x4>(cx, (int32_t*)retAddr); - if (!retObj) - return false; - break; case ExprType::Limit: MOZ_CRASH("Limit"); } diff --git a/js/src/wasm/WasmIonCompile.cpp b/js/src/wasm/WasmIonCompile.cpp index 2b16d3f053..c9839ed640 100644 --- a/js/src/wasm/WasmIonCompile.cpp +++ b/js/src/wasm/WasmIonCompile.cpp @@ -1,6 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2015 Mozilla Foundation + * Copyright 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -250,30 +251,6 @@ class FunctionCompiler case ValType::F64: ins = MConstant::New(alloc(), DoubleValue(0.0), MIRType::Double); break; - case ValType::I8x16: - ins = MSimdConstant::New(alloc(), SimdConstant::SplatX16(0), MIRType::Int8x16); - break; - case ValType::I16x8: - ins = MSimdConstant::New(alloc(), SimdConstant::SplatX8(0), MIRType::Int16x8); - break; - case ValType::I32x4: - ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0), MIRType::Int32x4); - break; - case ValType::F32x4: - ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0.f), MIRType::Float32x4); - break; - case ValType::B8x16: - // Bool8x16 uses the same data layout as Int8x16. - ins = MSimdConstant::New(alloc(), SimdConstant::SplatX16(0), MIRType::Bool8x16); - break; - case ValType::B16x8: - // Bool16x8 uses the same data layout as Int16x8. - ins = MSimdConstant::New(alloc(), SimdConstant::SplatX8(0), MIRType::Bool16x8); - break; - case ValType::B32x4: - // Bool32x4 uses the same data layout as Int32x4. - ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0), MIRType::Bool32x4); - break; } curBlock_->add(ins); @@ -323,16 +300,6 @@ class FunctionCompiler /***************************** Code generation (after local scope setup) */ - MDefinition* constant(const SimdConstant& v, MIRType type) - { - if (inDeadCode()) - return nullptr; - MInstruction* constant; - constant = MSimdConstant::New(alloc(), v, type); - curBlock_->add(constant); - return constant; - } - MDefinition* constant(const Value& v, MIRType type) { if (inDeadCode()) @@ -425,172 +392,6 @@ class FunctionCompiler return ins; } - MDefinition* unarySimd(MDefinition* input, MSimdUnaryArith::Operation op, MIRType type) - { - if (inDeadCode()) - return nullptr; - - MOZ_ASSERT(IsSimdType(input->type()) && input->type() == type); - MInstruction* ins = MSimdUnaryArith::New(alloc(), input, op); - curBlock_->add(ins); - return ins; - } - - MDefinition* binarySimd(MDefinition* lhs, MDefinition* rhs, MSimdBinaryArith::Operation op, - MIRType type) - { - if (inDeadCode()) - return nullptr; - - MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type()); - MOZ_ASSERT(lhs->type() == type); - return MSimdBinaryArith::AddLegalized(alloc(), curBlock_, lhs, rhs, op); - } - - MDefinition* binarySimd(MDefinition* lhs, MDefinition* rhs, MSimdBinaryBitwise::Operation op, - MIRType type) - { - if (inDeadCode()) - return nullptr; - - MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type()); - MOZ_ASSERT(lhs->type() == type); - auto* ins = MSimdBinaryBitwise::New(alloc(), lhs, rhs, op); - curBlock_->add(ins); - return ins; - } - - MDefinition* binarySimdComp(MDefinition* lhs, MDefinition* rhs, MSimdBinaryComp::Operation op, - SimdSign sign) - { - if (inDeadCode()) - return nullptr; - - return MSimdBinaryComp::AddLegalized(alloc(), curBlock_, lhs, rhs, op, sign); - } - - MDefinition* binarySimdSaturating(MDefinition* lhs, MDefinition* rhs, - MSimdBinarySaturating::Operation op, SimdSign sign) - { - if (inDeadCode()) - return nullptr; - - auto* ins = MSimdBinarySaturating::New(alloc(), lhs, rhs, op, sign); - curBlock_->add(ins); - return ins; - } - - MDefinition* binarySimdShift(MDefinition* lhs, MDefinition* rhs, MSimdShift::Operation op) - { - if (inDeadCode()) - return nullptr; - - return MSimdShift::AddLegalized(alloc(), curBlock_, lhs, rhs, op); - } - - MDefinition* swizzleSimd(MDefinition* vector, const uint8_t lanes[], MIRType type) - { - if (inDeadCode()) - return nullptr; - - MOZ_ASSERT(vector->type() == type); - MSimdSwizzle* ins = MSimdSwizzle::New(alloc(), vector, lanes); - curBlock_->add(ins); - return ins; - } - - MDefinition* shuffleSimd(MDefinition* lhs, MDefinition* rhs, const uint8_t lanes[], - MIRType type) - { - if (inDeadCode()) - return nullptr; - - MOZ_ASSERT(lhs->type() == type); - MInstruction* ins = MSimdShuffle::New(alloc(), lhs, rhs, lanes); - curBlock_->add(ins); - return ins; - } - - MDefinition* insertElementSimd(MDefinition* vec, MDefinition* val, unsigned lane, MIRType type) - { - if (inDeadCode()) - return nullptr; - - MOZ_ASSERT(IsSimdType(vec->type()) && vec->type() == type); - MOZ_ASSERT(SimdTypeToLaneArgumentType(vec->type()) == val->type()); - MSimdInsertElement* ins = MSimdInsertElement::New(alloc(), vec, val, lane); - curBlock_->add(ins); - return ins; - } - - MDefinition* selectSimd(MDefinition* mask, MDefinition* lhs, MDefinition* rhs, MIRType type) - { - if (inDeadCode()) - return nullptr; - - MOZ_ASSERT(IsSimdType(mask->type())); - MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type()); - MOZ_ASSERT(lhs->type() == type); - MSimdSelect* ins = MSimdSelect::New(alloc(), mask, lhs, rhs); - curBlock_->add(ins); - return ins; - } - - MDefinition* simdAllTrue(MDefinition* boolVector) - { - if (inDeadCode()) - return nullptr; - - MSimdAllTrue* ins = MSimdAllTrue::New(alloc(), boolVector, MIRType::Int32); - curBlock_->add(ins); - return ins; - } - - MDefinition* simdAnyTrue(MDefinition* boolVector) - { - if (inDeadCode()) - return nullptr; - - MSimdAnyTrue* ins = MSimdAnyTrue::New(alloc(), boolVector, MIRType::Int32); - curBlock_->add(ins); - return ins; - } - - // fromXXXBits() - MDefinition* bitcastSimd(MDefinition* vec, MIRType from, MIRType to) - { - if (inDeadCode()) - return nullptr; - - MOZ_ASSERT(vec->type() == from); - MOZ_ASSERT(IsSimdType(from) && IsSimdType(to) && from != to); - auto* ins = MSimdReinterpretCast::New(alloc(), vec, to); - curBlock_->add(ins); - return ins; - } - - // Int <--> Float conversions. - MDefinition* convertSimd(MDefinition* vec, MIRType from, MIRType to, SimdSign sign) - { - if (inDeadCode()) - return nullptr; - - MOZ_ASSERT(IsSimdType(from) && IsSimdType(to) && from != to); - return MSimdConvert::AddLegalized(alloc(), curBlock_, vec, to, sign, trapOffset()); - } - - MDefinition* splatSimd(MDefinition* v, MIRType type) - { - if (inDeadCode()) - return nullptr; - - MOZ_ASSERT(IsSimdType(type)); - MOZ_ASSERT(SimdTypeToLaneArgumentType(type) == v->type()); - MSimdSplat* ins = MSimdSplat::New(alloc(), v, type); - curBlock_->add(ins); - return ins; - } - MDefinition* minMax(MDefinition* lhs, MDefinition* rhs, MIRType type, bool isMax) { if (inDeadCode()) return nullptr; @@ -824,31 +625,6 @@ class FunctionCompiler MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers()); } - MDefinition* extractSimdElement(unsigned lane, MDefinition* base, MIRType type, SimdSign sign) - { - if (inDeadCode()) - return nullptr; - - MOZ_ASSERT(IsSimdType(base->type())); - MOZ_ASSERT(!IsSimdType(type)); - auto* ins = MSimdExtractElement::New(alloc(), base, type, lane, sign); - curBlock_->add(ins); - return ins; - } - - template<typename T> - MDefinition* constructSimd(MDefinition* x, MDefinition* y, MDefinition* z, MDefinition* w, - MIRType type) - { - if (inDeadCode()) - return nullptr; - - MOZ_ASSERT(IsSimdType(type)); - T* ins = T::New(alloc(), type, x, y, z, w); - curBlock_->add(ins); - return ins; - } - /***************************************************************** Calls */ // The IonMonkey backend maintains a single stack offset (from the stack @@ -2061,18 +1837,6 @@ EmitGetGlobal(FunctionCompiler& f) case ValType::F64: result = f.constant(value.f64()); break; - case ValType::I8x16: - result = f.constant(SimdConstant::CreateX16(value.i8x16()), mirType); - break; - case ValType::I16x8: - result = f.constant(SimdConstant::CreateX8(value.i16x8()), mirType); - break; - case ValType::I32x4: - result = f.constant(SimdConstant::CreateX4(value.i32x4()), mirType); - break; - case ValType::F32x4: - result = f.constant(SimdConstant::CreateX4(value.f32x4()), mirType); - break; default: MOZ_CRASH("unexpected type in EmitGetGlobal"); } @@ -2563,491 +2327,6 @@ EmitAtomicsExchange(FunctionCompiler& f) } static bool -EmitSimdUnary(FunctionCompiler& f, ValType type, SimdOperation simdOp) -{ - MSimdUnaryArith::Operation op; - switch (simdOp) { - case SimdOperation::Fn_abs: - op = MSimdUnaryArith::abs; - break; - case SimdOperation::Fn_neg: - op = MSimdUnaryArith::neg; - break; - case SimdOperation::Fn_not: - op = MSimdUnaryArith::not_; - break; - case SimdOperation::Fn_sqrt: - op = MSimdUnaryArith::sqrt; - break; - case SimdOperation::Fn_reciprocalApproximation: - op = MSimdUnaryArith::reciprocalApproximation; - break; - case SimdOperation::Fn_reciprocalSqrtApproximation: - op = MSimdUnaryArith::reciprocalSqrtApproximation; - break; - default: - MOZ_CRASH("not a simd unary arithmetic operation"); - } - - MDefinition* input; - if (!f.iter().readUnary(type, &input)) - return false; - - f.iter().setResult(f.unarySimd(input, op, ToMIRType(type))); - return true; -} - -template<class OpKind> -inline bool -EmitSimdBinary(FunctionCompiler& f, ValType type, OpKind op) -{ - MDefinition* lhs; - MDefinition* rhs; - if (!f.iter().readBinary(type, &lhs, &rhs)) - return false; - - f.iter().setResult(f.binarySimd(lhs, rhs, op, ToMIRType(type))); - return true; -} - -static bool -EmitSimdBinaryComp(FunctionCompiler& f, ValType operandType, MSimdBinaryComp::Operation op, - SimdSign sign) -{ - MDefinition* lhs; - MDefinition* rhs; - if (!f.iter().readSimdComparison(operandType, &lhs, &rhs)) - return false; - - f.iter().setResult(f.binarySimdComp(lhs, rhs, op, sign)); - return true; -} - -static bool -EmitSimdBinarySaturating(FunctionCompiler& f, ValType type, MSimdBinarySaturating::Operation op, - SimdSign sign) -{ - MDefinition* lhs; - MDefinition* rhs; - if (!f.iter().readBinary(type, &lhs, &rhs)) - return false; - - f.iter().setResult(f.binarySimdSaturating(lhs, rhs, op, sign)); - return true; -} - -static bool -EmitSimdShift(FunctionCompiler& f, ValType operandType, MSimdShift::Operation op) -{ - MDefinition* lhs; - MDefinition* rhs; - if (!f.iter().readSimdShiftByScalar(operandType, &lhs, &rhs)) - return false; - - f.iter().setResult(f.binarySimdShift(lhs, rhs, op)); - return true; -} - -static ValType -SimdToLaneType(ValType type) -{ - switch (type) { - case ValType::I8x16: - case ValType::I16x8: - case ValType::I32x4: return ValType::I32; - case ValType::F32x4: return ValType::F32; - case ValType::B8x16: - case ValType::B16x8: - case ValType::B32x4: return ValType::I32; // Boolean lanes are Int32 in asm. - case ValType::I32: - case ValType::I64: - case ValType::F32: - case ValType::F64: - break; - } - MOZ_CRASH("bad simd type"); -} - -static bool -EmitExtractLane(FunctionCompiler& f, ValType operandType, SimdSign sign) -{ - uint8_t lane; - MDefinition* vector; - if (!f.iter().readExtractLane(operandType, &lane, &vector)) - return false; - - f.iter().setResult(f.extractSimdElement(lane, vector, - ToMIRType(SimdToLaneType(operandType)), sign)); - return true; -} - -// Emit an I32 expression and then convert it to a boolean SIMD lane value, i.e. -1 or 0. -static MDefinition* -EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition* i32) -{ - // Compute !i32 - 1 to force the value range into {0, -1}. - MDefinition* noti32 = f.unary<MNot>(i32); - return f.binary<MSub>(noti32, f.constant(Int32Value(1), MIRType::Int32), MIRType::Int32); -} - -static bool -EmitSimdReplaceLane(FunctionCompiler& f, ValType simdType) -{ - if (IsSimdBoolType(simdType)) - f.iter().setResult(EmitSimdBooleanLaneExpr(f, f.iter().getResult())); - - uint8_t lane; - MDefinition* vector; - MDefinition* scalar; - if (!f.iter().readReplaceLane(simdType, &lane, &vector, &scalar)) - return false; - - f.iter().setResult(f.insertElementSimd(vector, scalar, lane, ToMIRType(simdType))); - return true; -} - -inline bool -EmitSimdBitcast(FunctionCompiler& f, ValType fromType, ValType toType) -{ - MDefinition* input; - if (!f.iter().readConversion(fromType, toType, &input)) - return false; - - f.iter().setResult(f.bitcastSimd(input, ToMIRType(fromType), ToMIRType(toType))); - return true; -} - -inline bool -EmitSimdConvert(FunctionCompiler& f, ValType fromType, ValType toType, SimdSign sign) -{ - MDefinition* input; - if (!f.iter().readConversion(fromType, toType, &input)) - return false; - - f.iter().setResult(f.convertSimd(input, ToMIRType(fromType), ToMIRType(toType), sign)); - return true; -} - -static bool -EmitSimdSwizzle(FunctionCompiler& f, ValType simdType) -{ - uint8_t lanes[16]; - MDefinition* vector; - if (!f.iter().readSwizzle(simdType, &lanes, &vector)) - return false; - - f.iter().setResult(f.swizzleSimd(vector, lanes, ToMIRType(simdType))); - return true; -} - -static bool -EmitSimdShuffle(FunctionCompiler& f, ValType simdType) -{ - uint8_t lanes[16]; - MDefinition* lhs; - MDefinition* rhs; - if (!f.iter().readShuffle(simdType, &lanes, &lhs, &rhs)) - return false; - - f.iter().setResult(f.shuffleSimd(lhs, rhs, lanes, ToMIRType(simdType))); - return true; -} - -static inline Scalar::Type -SimdExprTypeToViewType(ValType type, unsigned* defaultNumElems) -{ - switch (type) { - case ValType::I8x16: *defaultNumElems = 16; return Scalar::Int8x16; - case ValType::I16x8: *defaultNumElems = 8; return Scalar::Int16x8; - case ValType::I32x4: *defaultNumElems = 4; return Scalar::Int32x4; - case ValType::F32x4: *defaultNumElems = 4; return Scalar::Float32x4; - default: break; - } - MOZ_CRASH("type not handled in SimdExprTypeToViewType"); -} - -static bool -EmitSimdLoad(FunctionCompiler& f, ValType resultType, unsigned numElems) -{ - unsigned defaultNumElems; - Scalar::Type viewType = SimdExprTypeToViewType(resultType, &defaultNumElems); - - if (!numElems) - numElems = defaultNumElems; - - LinearMemoryAddress<MDefinition*> addr; - if (!f.iter().readLoad(resultType, Scalar::byteSize(viewType), &addr)) - return false; - - MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.trapOffset()), numElems); - - f.iter().setResult(f.load(addr.base, access, resultType)); - return true; -} - -static bool -EmitSimdStore(FunctionCompiler& f, ValType resultType, unsigned numElems) -{ - unsigned defaultNumElems; - Scalar::Type viewType = SimdExprTypeToViewType(resultType, &defaultNumElems); - - if (!numElems) - numElems = defaultNumElems; - - LinearMemoryAddress<MDefinition*> addr; - MDefinition* value; - if (!f.iter().readTeeStore(resultType, Scalar::byteSize(viewType), &addr, &value)) - return false; - - MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.trapOffset()), numElems); - - f.store(addr.base, access, value); - return true; -} - -static bool -EmitSimdSelect(FunctionCompiler& f, ValType simdType) -{ - MDefinition* trueValue; - MDefinition* falseValue; - MDefinition* condition; - if (!f.iter().readSimdSelect(simdType, &trueValue, &falseValue, &condition)) - return false; - - f.iter().setResult(f.selectSimd(condition, trueValue, falseValue, - ToMIRType(simdType))); - return true; -} - -static bool -EmitSimdAllTrue(FunctionCompiler& f, ValType operandType) -{ - MDefinition* input; - if (!f.iter().readSimdBooleanReduction(operandType, &input)) - return false; - - f.iter().setResult(f.simdAllTrue(input)); - return true; -} - -static bool -EmitSimdAnyTrue(FunctionCompiler& f, ValType operandType) -{ - MDefinition* input; - if (!f.iter().readSimdBooleanReduction(operandType, &input)) - return false; - - f.iter().setResult(f.simdAnyTrue(input)); - return true; -} - -static bool -EmitSimdSplat(FunctionCompiler& f, ValType simdType) -{ - if (IsSimdBoolType(simdType)) - f.iter().setResult(EmitSimdBooleanLaneExpr(f, f.iter().getResult())); - - MDefinition* input; - if (!f.iter().readSplat(simdType, &input)) - return false; - - f.iter().setResult(f.splatSimd(input, ToMIRType(simdType))); - return true; -} - -// Build a SIMD vector by inserting lanes one at a time into an initial constant. -static bool -EmitSimdChainedCtor(FunctionCompiler& f, ValType valType, MIRType type, const SimdConstant& init) -{ - const unsigned length = SimdTypeToLength(type); - MDefinition* val = f.constant(init, type); - for (unsigned i = 0; i < length; i++) { - MDefinition* scalar = 0; - if (!f.iter().readSimdCtorArg(ValType::I32, length, i, &scalar)) - return false; - val = f.insertElementSimd(val, scalar, i, type); - } - if (!f.iter().readSimdCtorArgsEnd(length) || !f.iter().readSimdCtorReturn(valType)) - return false; - f.iter().setResult(val); - return true; -} - -// Build a boolean SIMD vector by inserting lanes one at a time into an initial constant. -static bool -EmitSimdBooleanChainedCtor(FunctionCompiler& f, ValType valType, MIRType type, - const SimdConstant& init) -{ - const unsigned length = SimdTypeToLength(type); - MDefinition* val = f.constant(init, type); - for (unsigned i = 0; i < length; i++) { - MDefinition* scalar = 0; - if (!f.iter().readSimdCtorArg(ValType::I32, length, i, &scalar)) - return false; - val = f.insertElementSimd(val, EmitSimdBooleanLaneExpr(f, scalar), i, type); - } - if (!f.iter().readSimdCtorArgsEnd(length) || !f.iter().readSimdCtorReturn(valType)) - return false; - f.iter().setResult(val); - return true; -} - -static bool -EmitSimdCtor(FunctionCompiler& f, ValType type) -{ - if (!f.iter().readSimdCtor()) - return false; - - switch (type) { - case ValType::I8x16: - return EmitSimdChainedCtor(f, type, MIRType::Int8x16, SimdConstant::SplatX16(0)); - case ValType::I16x8: - return EmitSimdChainedCtor(f, type, MIRType::Int16x8, SimdConstant::SplatX8(0)); - case ValType::I32x4: { - MDefinition* args[4]; - for (unsigned i = 0; i < 4; i++) { - if (!f.iter().readSimdCtorArg(ValType::I32, 4, i, &args[i])) - return false; - } - if (!f.iter().readSimdCtorArgsEnd(4) || !f.iter().readSimdCtorReturn(type)) - return false; - f.iter().setResult(f.constructSimd<MSimdValueX4>(args[0], args[1], args[2], args[3], - MIRType::Int32x4)); - return true; - } - case ValType::F32x4: { - MDefinition* args[4]; - for (unsigned i = 0; i < 4; i++) { - if (!f.iter().readSimdCtorArg(ValType::F32, 4, i, &args[i])) - return false; - } - if (!f.iter().readSimdCtorArgsEnd(4) || !f.iter().readSimdCtorReturn(type)) - return false; - f.iter().setResult(f.constructSimd<MSimdValueX4>(args[0], args[1], args[2], args[3], - MIRType::Float32x4)); - return true; - } - case ValType::B8x16: - return EmitSimdBooleanChainedCtor(f, type, MIRType::Bool8x16, SimdConstant::SplatX16(0)); - case ValType::B16x8: - return EmitSimdBooleanChainedCtor(f, type, MIRType::Bool16x8, SimdConstant::SplatX8(0)); - case ValType::B32x4: { - MDefinition* args[4]; - for (unsigned i = 0; i < 4; i++) { - MDefinition* i32; - if (!f.iter().readSimdCtorArg(ValType::I32, 4, i, &i32)) - return false; - args[i] = EmitSimdBooleanLaneExpr(f, i32); - } - if (!f.iter().readSimdCtorArgsEnd(4) || !f.iter().readSimdCtorReturn(type)) - return false; - f.iter().setResult(f.constructSimd<MSimdValueX4>(args[0], args[1], args[2], args[3], - MIRType::Bool32x4)); - return true; - } - case ValType::I32: - case ValType::I64: - case ValType::F32: - case ValType::F64: - break; - } - MOZ_CRASH("unexpected SIMD type"); -} - -static bool -EmitSimdOp(FunctionCompiler& f, ValType type, SimdOperation op, SimdSign sign) -{ - switch (op) { - case SimdOperation::Constructor: - return EmitSimdCtor(f, type); - case SimdOperation::Fn_extractLane: - return EmitExtractLane(f, type, sign); - case SimdOperation::Fn_replaceLane: - return EmitSimdReplaceLane(f, type); - case SimdOperation::Fn_check: - MOZ_CRASH("only used in asm.js' type system"); - case SimdOperation::Fn_splat: - return EmitSimdSplat(f, type); - case SimdOperation::Fn_select: - return EmitSimdSelect(f, type); - case SimdOperation::Fn_swizzle: - return EmitSimdSwizzle(f, type); - case SimdOperation::Fn_shuffle: - return EmitSimdShuffle(f, type); - case SimdOperation::Fn_load: - return EmitSimdLoad(f, type, 0); - case SimdOperation::Fn_load1: - return EmitSimdLoad(f, type, 1); - case SimdOperation::Fn_load2: - return EmitSimdLoad(f, type, 2); - case SimdOperation::Fn_store: - return EmitSimdStore(f, type, 0); - case SimdOperation::Fn_store1: - return EmitSimdStore(f, type, 1); - case SimdOperation::Fn_store2: - return EmitSimdStore(f, type, 2); - case SimdOperation::Fn_allTrue: - return EmitSimdAllTrue(f, type); - case SimdOperation::Fn_anyTrue: - return EmitSimdAnyTrue(f, type); - case SimdOperation::Fn_abs: - case SimdOperation::Fn_neg: - case SimdOperation::Fn_not: - case SimdOperation::Fn_sqrt: - case SimdOperation::Fn_reciprocalApproximation: - case SimdOperation::Fn_reciprocalSqrtApproximation: - return EmitSimdUnary(f, type, op); - case SimdOperation::Fn_shiftLeftByScalar: - return EmitSimdShift(f, type, MSimdShift::lsh); - case SimdOperation::Fn_shiftRightByScalar: - return EmitSimdShift(f, type, MSimdShift::rshForSign(sign)); -#define _CASE(OP) \ - case SimdOperation::Fn_##OP: \ - return EmitSimdBinaryComp(f, type, MSimdBinaryComp::OP, sign); - FOREACH_COMP_SIMD_OP(_CASE) -#undef _CASE - case SimdOperation::Fn_and: - return EmitSimdBinary(f, type, MSimdBinaryBitwise::and_); - case SimdOperation::Fn_or: - return EmitSimdBinary(f, type, MSimdBinaryBitwise::or_); - case SimdOperation::Fn_xor: - return EmitSimdBinary(f, type, MSimdBinaryBitwise::xor_); -#define _CASE(OP) \ - case SimdOperation::Fn_##OP: \ - return EmitSimdBinary(f, type, MSimdBinaryArith::Op_##OP); - FOREACH_NUMERIC_SIMD_BINOP(_CASE) - FOREACH_FLOAT_SIMD_BINOP(_CASE) -#undef _CASE - case SimdOperation::Fn_addSaturate: - return EmitSimdBinarySaturating(f, type, MSimdBinarySaturating::add, sign); - case SimdOperation::Fn_subSaturate: - return EmitSimdBinarySaturating(f, type, MSimdBinarySaturating::sub, sign); - case SimdOperation::Fn_fromFloat32x4: - return EmitSimdConvert(f, ValType::F32x4, type, sign); - case SimdOperation::Fn_fromInt32x4: - return EmitSimdConvert(f, ValType::I32x4, type, SimdSign::Signed); - case SimdOperation::Fn_fromUint32x4: - return EmitSimdConvert(f, ValType::I32x4, type, SimdSign::Unsigned); - case SimdOperation::Fn_fromInt8x16Bits: - case SimdOperation::Fn_fromUint8x16Bits: - return EmitSimdBitcast(f, ValType::I8x16, type); - case SimdOperation::Fn_fromUint16x8Bits: - case SimdOperation::Fn_fromInt16x8Bits: - return EmitSimdBitcast(f, ValType::I16x8, type); - case SimdOperation::Fn_fromInt32x4Bits: - case SimdOperation::Fn_fromUint32x4Bits: - return EmitSimdBitcast(f, ValType::I32x4, type); - case SimdOperation::Fn_fromFloat32x4Bits: - return EmitSimdBitcast(f, ValType::F32x4, type); - case SimdOperation::Fn_load3: - case SimdOperation::Fn_store3: - case SimdOperation::Fn_fromFloat64x2Bits: - MOZ_CRASH("NYI"); - } - MOZ_CRASH("unexpected opcode"); -} - -static bool EmitGrowMemory(FunctionCompiler& f) { uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode(); @@ -3546,145 +2825,6 @@ EmitExpr(FunctionCompiler& f) case Op::F64Ge: return EmitComparison(f, ValType::F64, JSOP_GE, MCompare::Compare_Double); - // SIMD -#define CASE(TYPE, OP, SIGN) \ - case Op::TYPE##OP: \ - return EmitSimdOp(f, ValType::TYPE, SimdOperation::Fn_##OP, SIGN); -#define I8x16CASE(OP) CASE(I8x16, OP, SimdSign::Signed) -#define I16x8CASE(OP) CASE(I16x8, OP, SimdSign::Signed) -#define I32x4CASE(OP) CASE(I32x4, OP, SimdSign::Signed) -#define F32x4CASE(OP) CASE(F32x4, OP, SimdSign::NotApplicable) -#define B8x16CASE(OP) CASE(B8x16, OP, SimdSign::NotApplicable) -#define B16x8CASE(OP) CASE(B16x8, OP, SimdSign::NotApplicable) -#define B32x4CASE(OP) CASE(B32x4, OP, SimdSign::NotApplicable) -#define ENUMERATE(TYPE, FORALL, DO) \ - case Op::TYPE##Constructor: \ - return EmitSimdOp(f, ValType::TYPE, SimdOperation::Constructor, SimdSign::NotApplicable); \ - FORALL(DO) - - ENUMERATE(I8x16, FORALL_INT8X16_ASMJS_OP, I8x16CASE) - ENUMERATE(I16x8, FORALL_INT16X8_ASMJS_OP, I16x8CASE) - ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32x4CASE) - ENUMERATE(F32x4, FORALL_FLOAT32X4_ASMJS_OP, F32x4CASE) - ENUMERATE(B8x16, FORALL_BOOL_SIMD_OP, B8x16CASE) - ENUMERATE(B16x8, FORALL_BOOL_SIMD_OP, B16x8CASE) - ENUMERATE(B32x4, FORALL_BOOL_SIMD_OP, B32x4CASE) - -#undef CASE -#undef I8x16CASE -#undef I16x8CASE -#undef I32x4CASE -#undef F32x4CASE -#undef B8x16CASE -#undef B16x8CASE -#undef B32x4CASE -#undef ENUMERATE - - case Op::I8x16Const: { - I8x16 i8x16; - if (!f.iter().readI8x16Const(&i8x16)) - return false; - - f.iter().setResult(f.constant(SimdConstant::CreateX16(i8x16), MIRType::Int8x16)); - return true; - } - case Op::I16x8Const: { - I16x8 i16x8; - if (!f.iter().readI16x8Const(&i16x8)) - return false; - - f.iter().setResult(f.constant(SimdConstant::CreateX8(i16x8), MIRType::Int16x8)); - return true; - } - case Op::I32x4Const: { - I32x4 i32x4; - if (!f.iter().readI32x4Const(&i32x4)) - return false; - - f.iter().setResult(f.constant(SimdConstant::CreateX4(i32x4), MIRType::Int32x4)); - return true; - } - case Op::F32x4Const: { - F32x4 f32x4; - if (!f.iter().readF32x4Const(&f32x4)) - return false; - - f.iter().setResult(f.constant(SimdConstant::CreateX4(f32x4), MIRType::Float32x4)); - return true; - } - case Op::B8x16Const: { - I8x16 i8x16; - if (!f.iter().readB8x16Const(&i8x16)) - return false; - - f.iter().setResult(f.constant(SimdConstant::CreateX16(i8x16), MIRType::Bool8x16)); - return true; - } - case Op::B16x8Const: { - I16x8 i16x8; - if (!f.iter().readB16x8Const(&i16x8)) - return false; - - f.iter().setResult(f.constant(SimdConstant::CreateX8(i16x8), MIRType::Bool16x8)); - return true; - } - case Op::B32x4Const: { - I32x4 i32x4; - if (!f.iter().readB32x4Const(&i32x4)) - return false; - - f.iter().setResult(f.constant(SimdConstant::CreateX4(i32x4), MIRType::Bool32x4)); - return true; - } - - // SIMD unsigned integer operations. - case Op::I8x16addSaturateU: - return EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_addSaturate, SimdSign::Unsigned); - case Op::I8x16subSaturateU: - return EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_subSaturate, SimdSign::Unsigned); - case Op::I8x16shiftRightByScalarU: - return EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned); - case Op::I8x16lessThanU: - return EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_lessThan, SimdSign::Unsigned); - case Op::I8x16lessThanOrEqualU: - return EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned); - case Op::I8x16greaterThanU: - return EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_greaterThan, SimdSign::Unsigned); - case Op::I8x16greaterThanOrEqualU: - return EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned); - case Op::I8x16extractLaneU: - return EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_extractLane, SimdSign::Unsigned); - - case Op::I16x8addSaturateU: - return EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_addSaturate, SimdSign::Unsigned); - case Op::I16x8subSaturateU: - return EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_subSaturate, SimdSign::Unsigned); - case Op::I16x8shiftRightByScalarU: - return EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned); - case Op::I16x8lessThanU: - return EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_lessThan, SimdSign::Unsigned); - case Op::I16x8lessThanOrEqualU: - return EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned); - case Op::I16x8greaterThanU: - return EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_greaterThan, SimdSign::Unsigned); - case Op::I16x8greaterThanOrEqualU: - return EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned); - case Op::I16x8extractLaneU: - return EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_extractLane, SimdSign::Unsigned); - - case Op::I32x4shiftRightByScalarU: - return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned); - case Op::I32x4lessThanU: - return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_lessThan, SimdSign::Unsigned); - case Op::I32x4lessThanOrEqualU: - return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned); - case Op::I32x4greaterThanU: - return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThan, SimdSign::Unsigned); - case Op::I32x4greaterThanOrEqualU: - return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned); - case Op::I32x4fromFloat32x4U: - return EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_fromFloat32x4, SimdSign::Unsigned); - // Atomics case Op::I32AtomicsLoad: return EmitAtomicsLoad(f); diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp index 0479bda59f..d5e1c2acd3 100644 --- a/js/src/wasm/WasmJS.cpp +++ b/js/src/wasm/WasmJS.cpp @@ -1,6 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2016 Mozilla Foundation + * Copyright 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/js/src/wasm/WasmSignalHandlers.cpp b/js/src/wasm/WasmSignalHandlers.cpp index 36011abe90..f0d334ba39 100644 --- a/js/src/wasm/WasmSignalHandlers.cpp +++ b/js/src/wasm/WasmSignalHandlers.cpp @@ -1,6 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2014 Mozilla Foundation + * Copyright 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/js/src/wasm/WasmStubs.cpp b/js/src/wasm/WasmStubs.cpp index d4e188a23d..67d744e585 100644 --- a/js/src/wasm/WasmStubs.cpp +++ b/js/src/wasm/WasmStubs.cpp @@ -1,6 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2015 Mozilla Foundation + * Copyright 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -186,17 +187,6 @@ wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe) static_assert(sizeof(ExportArg) >= jit::Simd128DataSize, "ExportArg must be big enough to store SIMD values"); switch (type) { - case MIRType::Int8x16: - case MIRType::Int16x8: - case MIRType::Int32x4: - case MIRType::Bool8x16: - case MIRType::Bool16x8: - case MIRType::Bool32x4: - masm.loadUnalignedSimd128Int(src, iter->fpu()); - break; - case MIRType::Float32x4: - masm.loadUnalignedSimd128Float(src, iter->fpu()); - break; case MIRType::Double: masm.loadDouble(src, iter->fpu()); break; @@ -239,21 +229,6 @@ wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe) masm.storeFloat32(ScratchFloat32Reg, Address(masm.getStackPointer(), iter->offsetFromArgBase())); break; - case MIRType::Int8x16: - case MIRType::Int16x8: - case MIRType::Int32x4: - case MIRType::Bool8x16: - case MIRType::Bool16x8: - case MIRType::Bool32x4: - masm.loadUnalignedSimd128Int(src, ScratchSimd128Reg); - masm.storeAlignedSimd128Int( - ScratchSimd128Reg, Address(masm.getStackPointer(), iter->offsetFromArgBase())); - break; - case MIRType::Float32x4: - masm.loadUnalignedSimd128Float(src, ScratchSimd128Reg); - masm.storeAlignedSimd128Float( - ScratchSimd128Reg, Address(masm.getStackPointer(), iter->offsetFromArgBase())); - break; default: MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected stack arg type"); } @@ -293,19 +268,6 @@ wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe) masm.canonicalizeDouble(ReturnDoubleReg); masm.storeDouble(ReturnDoubleReg, Address(argv, 0)); break; - case ExprType::I8x16: - case ExprType::I16x8: - case ExprType::I32x4: - case ExprType::B8x16: - case ExprType::B16x8: - case ExprType::B32x4: - // We don't have control on argv alignment, do an unaligned access. - masm.storeUnalignedSimd128Int(ReturnSimd128Reg, Address(argv, 0)); - break; - case ExprType::F32x4: - // We don't have control on argv alignment, do an unaligned access. - masm.storeUnalignedSimd128Float(ReturnSimd128Reg, Address(argv, 0)); - break; case ExprType::Limit: MOZ_CRASH("Limit"); } @@ -593,14 +555,6 @@ wasm::GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi, uint3 masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel); masm.loadDouble(argv, ReturnDoubleReg); break; - case ExprType::I8x16: - case ExprType::I16x8: - case ExprType::I32x4: - case ExprType::F32x4: - case ExprType::B8x16: - case ExprType::B16x8: - case ExprType::B32x4: - MOZ_CRASH("SIMD types shouldn't be returned from a FFI"); case ExprType::Limit: MOZ_CRASH("Limit"); } @@ -781,14 +735,6 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t case ExprType::F64: masm.convertValueToDouble(JSReturnOperand, ReturnDoubleReg, &oolConvert); break; - case ExprType::I8x16: - case ExprType::I16x8: - case ExprType::I32x4: - case ExprType::F32x4: - case ExprType::B8x16: - case ExprType::B16x8: - case ExprType::B32x4: - MOZ_CRASH("SIMD types shouldn't be returned from an import"); case ExprType::Limit: MOZ_CRASH("Limit"); } @@ -903,13 +849,12 @@ wasm::GenerateTrapExit(MacroAssembler& masm, Trap trap, Label* throwLabel) } // Generate a stub which is only used by the signal handlers to handle out of -// bounds access by experimental SIMD.js and Atomics and unaligned accesses on -// ARM. This stub is executed by direct PC transfer from the faulting memory -// access and thus the stack depth is unknown. Since WasmActivation::fp is not -// set before calling the error reporter, the current wasm activation will be -// lost. This stub should be removed when SIMD.js and Atomics are moved to wasm -// and given proper traps and when we use a non-faulting strategy for unaligned -// ARM access. +// bounds access by Atomics and unaligned accesses on ARM. This stub is +// executed by direct PC transfer from the faulting memory access and thus the +// stack depth is unknown. Since JitActivation::packedExitFP() is not set +// before calling the error reporter, the current wasm activation will be lost. +// This stub should be removed when Atomics are moved to wasm and given proper +// traps and when we use a non-faulting strategy for unaligned ARM access. static Offsets GenerateGenericMemoryAccessTrap(MacroAssembler& masm, SymbolicAddress reporter, Label* throwLabel) { diff --git a/js/src/wasm/WasmTextUtils.cpp b/js/src/wasm/WasmTextUtils.cpp index 78367f3984..197a211f19 100644 --- a/js/src/wasm/WasmTextUtils.cpp +++ b/js/src/wasm/WasmTextUtils.cpp @@ -1,6 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2016 Mozilla Foundation + * Copyright 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/js/src/wasm/WasmTypes.cpp b/js/src/wasm/WasmTypes.cpp index be8af3ada1..993c4903be 100644 --- a/js/src/wasm/WasmTypes.cpp +++ b/js/src/wasm/WasmTypes.cpp @@ -1,6 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2015 Mozilla Foundation + * Copyright 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,15 +53,6 @@ Val::writePayload(uint8_t* dst) const case ValType::F64: memcpy(dst, &u.i64_, sizeof(u.i64_)); return; - case ValType::I8x16: - case ValType::I16x8: - case ValType::I32x4: - case ValType::F32x4: - case ValType::B8x16: - case ValType::B16x8: - case ValType::B32x4: - memcpy(dst, &u, jit::Simd128DataSize); - return; } } @@ -125,9 +117,6 @@ WasmReportTrap(int32_t trapIndex) case Trap::IndirectCallBadSig: errorNumber = JSMSG_WASM_IND_CALL_BAD_SIG; break; - case Trap::ImpreciseSimdConversion: - errorNumber = JSMSG_SIMD_FAILED_CONVERSION; - break; case Trap::OutOfBounds: errorNumber = JSMSG_WASM_OUT_OF_BOUNDS; break; @@ -463,14 +452,6 @@ IsImmediateType(ValType vt) case ValType::F32: case ValType::F64: return true; - case ValType::I8x16: - case ValType::I16x8: - case ValType::I32x4: - case ValType::F32x4: - case ValType::B8x16: - case ValType::B16x8: - case ValType::B32x4: - return false; } MOZ_CRASH("bad ValType"); } @@ -488,14 +469,6 @@ EncodeImmediateType(ValType vt) return 2; case ValType::F64: return 3; - case ValType::I8x16: - case ValType::I16x8: - case ValType::I32x4: - case ValType::F32x4: - case ValType::B8x16: - case ValType::B16x8: - case ValType::B32x4: - break; } MOZ_CRASH("bad ValType"); } diff --git a/js/src/wasm/WasmTypes.h b/js/src/wasm/WasmTypes.h index 4e2caabfe9..57c737e454 100644 --- a/js/src/wasm/WasmTypes.h +++ b/js/src/wasm/WasmTypes.h @@ -1,6 +1,7 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright 2015 Mozilla Foundation + * Copyright 2023 Moonchild Productions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -83,11 +84,6 @@ using mozilla::Unused; typedef Vector<uint32_t, 0, SystemAllocPolicy> Uint32Vector; typedef Vector<uint8_t, 0, SystemAllocPolicy> Bytes; -typedef int8_t I8x16[16]; -typedef int16_t I16x8[8]; -typedef int32_t I32x4[4]; -typedef float F32x4[4]; - class Code; class CodeRange; class Memory; @@ -151,89 +147,6 @@ struct ShareableBase : RefCounted<T> // ValType utilities -static inline bool -IsSimdType(ValType vt) -{ - switch (vt) { - case ValType::I8x16: - case ValType::I16x8: - case ValType::I32x4: - case ValType::F32x4: - case ValType::B8x16: - case ValType::B16x8: - case ValType::B32x4: - return true; - default: - return false; - } -} - -static inline uint32_t -NumSimdElements(ValType vt) -{ - MOZ_ASSERT(IsSimdType(vt)); - switch (vt) { - case ValType::I8x16: - case ValType::B8x16: - return 16; - case ValType::I16x8: - case ValType::B16x8: - return 8; - case ValType::I32x4: - case ValType::F32x4: - case ValType::B32x4: - return 4; - default: - MOZ_CRASH("Unhandled SIMD type"); - } -} - -static inline ValType -SimdElementType(ValType vt) -{ - MOZ_ASSERT(IsSimdType(vt)); - switch (vt) { - case ValType::I8x16: - case ValType::I16x8: - case ValType::I32x4: - return ValType::I32; - case ValType::F32x4: - return ValType::F32; - case ValType::B8x16: - case ValType::B16x8: - case ValType::B32x4: - return ValType::I32; - default: - MOZ_CRASH("Unhandled SIMD type"); - } -} - -static inline ValType -SimdBoolType(ValType vt) -{ - MOZ_ASSERT(IsSimdType(vt)); - switch (vt) { - case ValType::I8x16: - case ValType::B8x16: - return ValType::B8x16; - case ValType::I16x8: - case ValType::B16x8: - return ValType::B16x8; - case ValType::I32x4: - case ValType::F32x4: - case ValType::B32x4: - return ValType::B32x4; - default: - MOZ_CRASH("Unhandled SIMD type"); - } -} - -static inline bool -IsSimdBoolType(ValType vt) -{ - return vt == ValType::B8x16 || vt == ValType::B16x8 || vt == ValType::B32x4; -} - static inline jit::MIRType ToMIRType(ValType vt) { @@ -242,13 +155,6 @@ ToMIRType(ValType vt) case ValType::I64: return jit::MIRType::Int64; case ValType::F32: return jit::MIRType::Float32; case ValType::F64: return jit::MIRType::Double; - case ValType::I8x16: return jit::MIRType::Int8x16; - case ValType::I16x8: return jit::MIRType::Int16x8; - case ValType::I32x4: return jit::MIRType::Int32x4; - case ValType::F32x4: return jit::MIRType::Float32x4; - case ValType::B8x16: return jit::MIRType::Bool8x16; - case ValType::B16x8: return jit::MIRType::Bool16x8; - case ValType::B32x4: return jit::MIRType::Bool32x4; } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad type"); } @@ -267,14 +173,6 @@ enum class ExprType F32 = uint8_t(TypeCode::F32), F64 = uint8_t(TypeCode::F64), - I8x16 = uint8_t(TypeCode::I8x16), - I16x8 = uint8_t(TypeCode::I16x8), - I32x4 = uint8_t(TypeCode::I32x4), - F32x4 = uint8_t(TypeCode::F32x4), - B8x16 = uint8_t(TypeCode::B8x16), - B16x8 = uint8_t(TypeCode::B16x8), - B32x4 = uint8_t(TypeCode::B32x4), - Limit = uint8_t(TypeCode::Limit) }; @@ -297,12 +195,6 @@ ToExprType(ValType vt) return ExprType(vt); } -static inline bool -IsSimdType(ExprType et) -{ - return IsVoid(et) ? false : IsSimdType(ValType(et)); -} - static inline jit::MIRType ToMIRType(ExprType et) { @@ -318,13 +210,6 @@ ToCString(ExprType type) case ExprType::I64: return "i64"; case ExprType::F32: return "f32"; case ExprType::F64: return "f64"; - case ExprType::I8x16: return "i8x16"; - case ExprType::I16x8: return "i16x8"; - case ExprType::I32x4: return "i32x4"; - case ExprType::F32x4: return "f32x4"; - case ExprType::B8x16: return "b8x16"; - case ExprType::B16x8: return "b16x8"; - case ExprType::B32x4: return "b32x4"; case ExprType::Limit:; } MOZ_CRASH("bad expression type"); @@ -386,10 +271,6 @@ class Val uint64_t i64_; RawF32 f32_; RawF64 f64_; - I8x16 i8x16_; - I16x8 i16x8_; - I32x4 i32x4_; - F32x4 f32x4_; U() {} } u; @@ -404,47 +285,13 @@ class Val MOZ_IMPLICIT Val(float) = delete; MOZ_IMPLICIT Val(double) = delete; - explicit Val(const I8x16& i8x16, ValType type = ValType::I8x16) : type_(type) { - MOZ_ASSERT(type_ == ValType::I8x16 || type_ == ValType::B8x16); - memcpy(u.i8x16_, i8x16, sizeof(u.i8x16_)); - } - explicit Val(const I16x8& i16x8, ValType type = ValType::I16x8) : type_(type) { - MOZ_ASSERT(type_ == ValType::I16x8 || type_ == ValType::B16x8); - memcpy(u.i16x8_, i16x8, sizeof(u.i16x8_)); - } - explicit Val(const I32x4& i32x4, ValType type = ValType::I32x4) : type_(type) { - MOZ_ASSERT(type_ == ValType::I32x4 || type_ == ValType::B32x4); - memcpy(u.i32x4_, i32x4, sizeof(u.i32x4_)); - } - explicit Val(const F32x4& f32x4) : type_(ValType::F32x4) { - memcpy(u.f32x4_, f32x4, sizeof(u.f32x4_)); - } - ValType type() const { return type_; } - bool isSimd() const { return IsSimdType(type()); } uint32_t i32() const { MOZ_ASSERT(type_ == ValType::I32); return u.i32_; } uint64_t i64() const { MOZ_ASSERT(type_ == ValType::I64); return u.i64_; } RawF32 f32() const { MOZ_ASSERT(type_ == ValType::F32); return u.f32_; } RawF64 f64() const { MOZ_ASSERT(type_ == ValType::F64); return u.f64_; } - const I8x16& i8x16() const { - MOZ_ASSERT(type_ == ValType::I8x16 || type_ == ValType::B8x16); - return u.i8x16_; - } - const I16x8& i16x8() const { - MOZ_ASSERT(type_ == ValType::I16x8 || type_ == ValType::B16x8); - return u.i16x8_; - } - const I32x4& i32x4() const { - MOZ_ASSERT(type_ == ValType::I32x4 || type_ == ValType::B32x4); - return u.i32x4_; - } - const F32x4& f32x4() const { - MOZ_ASSERT(type_ == ValType::F32x4); - return u.f32x4_; - } - void writePayload(uint8_t* dst) const; }; @@ -834,17 +681,13 @@ enum class Trap InvalidConversionToInteger, // Integer division by zero. IntegerDivideByZero, - // Out of bounds on wasm memory accesses and asm.js SIMD/atomic accesses. + // Out of bounds on wasm memory accesses and asm.js atomic accesses. OutOfBounds, // call_indirect to null. IndirectCallToNull, // call_indirect signature mismatch. IndirectCallBadSig, - // (asm.js only) SIMD float to int conversion failed because the input - // wasn't in bounds. - ImpreciseSimdConversion, - // The internal stack space was exhausted. For compatibility, this throws // the same over-recursed error as JS. StackOverflow, @@ -1388,7 +1231,7 @@ ComputeMappedSize(uint32_t maxSize); // Metadata for bounds check instructions that are patched at runtime with the // appropriate bounds check limit. On WASM_HUGE_MEMORY platforms for wasm (and -// SIMD/Atomic) bounds checks, no BoundsCheck is created: the signal handler +// Atomic) bounds checks, no BoundsCheck is created: the signal handler // catches everything. On !WASM_HUGE_MEMORY, a BoundsCheck is created for each // memory access (except when statically eliminated by optimizations) so that // the length can be patched in as an immediate. This requires that the bounds @@ -1413,7 +1256,7 @@ class BoundsCheck WASM_DECLARE_POD_VECTOR(BoundsCheck, BoundsCheckVector) // Metadata for memory accesses. On WASM_HUGE_MEMORY platforms, only -// (non-SIMD/Atomic) asm.js loads and stores create a MemoryAccess so that the +// (non-Atomic) asm.js loads and stores create a MemoryAccess so that the // signal handler can implement the semantically-correct wraparound logic; the // rest simply redirect to the out-of-bounds stub in the signal handler. On x86, // the base address of memory is baked into each memory access instruction so |