| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #pragma once
- // The representations below assume little-endian.
- #define SIMD_X 0
- #define SIMD_Y 1
- #define SIMD_Z 2
- #define SIMD_W 3
- #define FLOAT64_SIZE 8
- #define FLOAT32_SIZE 4
- #define INT32_SIZE 4
- #define INT16_SIZE 2
- #define INT8_SIZE 1
- #define SIMD_INDEX_VALUE_MAX 5
- #define SIMD_STRING_BUFFER_MAX 1024
- #define SIMD_DATA \
- Field(int32) i32[4];\
- Field(int16) i16[8];\
- Field(int8) i8[16];\
- Field(uint32) u32[4];\
- Field(uint16) u16[8];\
- Field(uint8) u8[16];\
- Field(float) f32[4];\
- Field(double) f64[2]; \
- Field(int64) i64[2];
- #define SIMD_TEMP_SIZE 3
- struct _SIMDValue
- {
- union{
- SIMD_DATA
- };
- void SetValue(_SIMDValue value)
- {
- i32[SIMD_X] = value.i32[SIMD_X];
- i32[SIMD_Y] = value.i32[SIMD_Y];
- i32[SIMD_Z] = value.i32[SIMD_Z];
- i32[SIMD_W] = value.i32[SIMD_W];
- }
- void Zero()
- {
- f64[SIMD_X] = f64[SIMD_Y] = 0;
- }
- bool operator==(const _SIMDValue& r)
- {
- // don't compare f64/f32 because NaN bit patterns will not be considered equal.
- return (this->i32[SIMD_X] == r.i32[SIMD_X] &&
- this->i32[SIMD_Y] == r.i32[SIMD_Y] &&
- this->i32[SIMD_Z] == r.i32[SIMD_Z] &&
- this->i32[SIMD_W] == r.i32[SIMD_W]);
- }
- bool IsZero()
- {
- return (i32[SIMD_X] == 0 && i32[SIMD_Y] == 0 && i32[SIMD_Z] == 0 && i32[SIMD_W] == 0);
- }
- };
- typedef _SIMDValue SIMDValue;
- // For dictionary use
- template <>
- struct DefaultComparer<_SIMDValue>
- {
- __forceinline static bool Equals(_SIMDValue x, _SIMDValue y)
- {
- return x == y;
- }
- __forceinline static hash_t GetHashCode(_SIMDValue d)
- {
- return (hash_t)(d.i32[SIMD_X] ^ d.i32[SIMD_Y] ^ d.i32[SIMD_Z] ^ d.i32[SIMD_W]);
- }
- };
- #if _M_IX86 || _M_AMD64
- struct _x86_SIMDValue
- {
- union{
- SIMD_DATA
- __m128 m128_value;
- __m128d m128d_value;
- __m128i m128i_value;
- };
- static _x86_SIMDValue ToX86SIMDValue(const SIMDValue& val)
- {
- _x86_SIMDValue result;
- result.m128_value = _mm_loadu_ps((float*) &val);
- return result;
- }
- static SIMDValue ToSIMDValue(const _x86_SIMDValue& val)
- {
- SIMDValue result;
- _mm_storeu_ps((float*) &result, val.m128_value);
- return result;
- }
- };
- #pragma warning(push)
- #pragma warning(disable:4838) // conversion from 'unsigned int' to 'int32' requires a narrowing conversion
- // These global values are 16-byte aligned.
- const _x86_SIMDValue X86_ABS_MASK_F4 = { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff };
- const _x86_SIMDValue X86_ABS_MASK_I4 = { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff };
- const _x86_SIMDValue X86_ABS_MASK_D2 = { 0xffffffff, 0x7fffffff, 0xffffffff, 0x7fffffff };
- const _x86_SIMDValue X86_NEG_MASK_F4 = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
- const _x86_SIMDValue X86_NEG_MASK_D2 = { 0x00000000, 0x80000000, 0x00000000, 0x80000000 };
- const _x86_SIMDValue X86_ALL_ONES_F4 = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 }; // {1.0, 1.0, 1.0, 1.0}
- const _x86_SIMDValue X86_ALL_ONES_I4 = { 0x00000001, 0x00000001, 0x00000001, 0x00000001 }; // {1, 1, 1, 1}
- const _x86_SIMDValue X86_ALL_ONES_D2 = { 0x00000000, 0x3ff00000, 0x00000000, 0x3ff00000 }; // {1.0, 1.0}
- const _x86_SIMDValue X86_ALL_NEG_ONES = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
- const _x86_SIMDValue X86_ALL_NEG_ONES_F4 = { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000 }; //-1.0, -1.0, -1.0, -1.0
- const _x86_SIMDValue X86_ALL_ONES_I8 = { 0x00010001, 0x00010001, 0x00010001, 0x00010001 }; // {1, 1, 1, 1, 1, 1, 1, 1}
- const _x86_SIMDValue X86_ALL_ZEROS = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
- const _x86_SIMDValue X86_ALL_ONES_I16 = { 0x01010101, 0x01010101, 0x01010101, 0x01010101 }; // {1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
- const _x86_SIMDValue X86_LANE0_ONES_I16 = { 0x000000ff, 0x00000000, 0x00000000, 0x00000000 };
- const _x86_SIMDValue X86_LOWBYTES_MASK = { 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff };
- const _x86_SIMDValue X86_HIGHBYTES_MASK = { 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00 };
- const _x86_SIMDValue X86_LANE_W_ZEROS = { 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000 };
- const _x86_SIMDValue X86_TWO_31_F4 = { 0x4f000000, 0x4f000000, 0x4f000000, 0x4f000000 }; // f32(2^31), ....
- const _x86_SIMDValue X86_NEG_TWO_31_F4 = { 0xcf000000, 0xcf000000, 0xcf000000, 0xcf000000 }; // f32(-2^31), ....
- const _x86_SIMDValue X86_TWO_32_F4 = { 0x4f800000, 0x4f800000, 0x4f800000, 0x4f800000 }; // f32(2^32), ....
- const _x86_SIMDValue X86_TWO_31_I4 = X86_NEG_MASK_F4; // 2^31, ....
- const _x86_SIMDValue X86_WORD_SIGNBITS = { 0x80008000, 0x80008000, 0x80008000, 0x80008000 };
- const _x86_SIMDValue X86_DWORD_SIGNBITS = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
- const _x86_SIMDValue X86_BYTE_SIGNBITS = { 0x80808080, 0x80808080, 0x80808080, 0x80808080 };
- const _x86_SIMDValue X86_4LANES_MASKS[] = {{ 0xffffffff, 0x00000000, 0x00000000, 0x00000000 },
- { 0x00000000, 0xffffffff, 0x00000000, 0x00000000 },
- { 0x00000000, 0x00000000, 0xffffffff, 0x00000000 },
- { 0x00000000, 0x00000000, 0x00000000, 0xffffffff }};
- #pragma warning(pop)
- #if ENABLE_NATIVE_CODEGEN && defined(ENABLE_WASM_SIMD)
- // auxiliary SIMD values in memory to help JIT'ed code. E.g. used for Int8x16 shuffle.
- extern _x86_SIMDValue X86_TEMP_SIMD[];
- #endif
- typedef _x86_SIMDValue X86SIMDValue;
- CompileAssert(sizeof(X86SIMDValue) == 16);
- #endif
- typedef SIMDValue AsmJsSIMDValue; // alias for asmjs
- CompileAssert(sizeof(SIMDValue) == 16);
- class ValueType;
- namespace Js {
- enum class OpCode : ushort;
- ///////////////////////////////////////////////////////////////
- //Class with static helper methods for manipulating SIMD Data.
- ///////////////////////////////////////////////////////////////
- class SIMDUtils
- {
- public:
- static uint32 inline SIMDGetShiftAmountMask(uint32 eleSizeInBytes) { return (eleSizeInBytes << 3) - 1; }
- ////////////////////////////////////////////
- //SIMD Extract Lane / Replace Lane Helpers
- ////////////////////////////////////////////
- static inline SIMDValue SIMD128InnerReplaceLaneF4(SIMDValue simdVal, const uint32 lane, const float value)
- {
- Assert(lane < 4);
- simdVal.f32[lane] = value;
- return simdVal;
- };
- static inline SIMDValue SIMD128InnerReplaceLaneD2(SIMDValue simdVal, const uint32 lane, const double value)
- {
- Assert(lane < 2);
- simdVal.f64[lane] = value;
- return simdVal;
- };
- static inline SIMDValue SIMD128InnerReplaceLaneI2(SIMDValue simdVal, const uint32 lane, const int64 value)
- {
- Assert(lane < 2);
- simdVal.i64[lane] = value;
- return simdVal;
- };
- static inline SIMDValue SIMD128InnerReplaceLaneI4(SIMDValue simdVal, const uint32 lane, const int32 value)
- {
- Assert(lane < 4);
- simdVal.i32[lane] = value;
- return simdVal;
- };
- static inline SIMDValue SIMD128InnerReplaceLaneI8(SIMDValue simdVal, const uint32 lane, const int16 value)
- {
- Assert(lane < 8);
- simdVal.i16[lane] = value;
- return simdVal;
- };
- static inline SIMDValue SIMD128InnerReplaceLaneI16(SIMDValue simdVal, const uint32 lane, const int8 value)
- {
- Assert(lane < 16);
- simdVal.i8[lane] = value;
- return simdVal;
- };
- static inline int32 SIMD128InnerExtractLaneB4(const SIMDValue src1, const uint32 lane)
- {
- Assert(lane < 4);
- int val = SIMD128InnerExtractLaneI4(src1, lane);
- return val ? 1 : 0;
- };
- static inline int16 SIMD128InnerExtractLaneB8(const SIMDValue src1, const uint32 lane)
- {
- Assert(lane < 8);
- int16 val = SIMD128InnerExtractLaneI8(src1, lane);
- return val ? 1 : 0;
- };
- static inline int8 SIMD128InnerExtractLaneB16(const SIMDValue src1, const uint32 lane)
- {
- Assert(lane < 16);
- int8 val = SIMD128InnerExtractLaneI16(src1, lane);
- return val ? 1 : 0;
- };
- static inline double SIMD128InnerExtractLaneD2(const SIMDValue src1, const uint32 lane) { Assert(lane < 2); return src1.f64[lane]; };
- static inline float SIMD128InnerExtractLaneF4(const SIMDValue src1, const uint32 lane) { Assert(lane < 4); return src1.f32[lane]; };
- static inline int64 SIMD128InnerExtractLaneI2(const SIMDValue src1, const uint32 lane) { Assert(lane < 2); return src1.i64[lane]; };
- static inline int32 SIMD128InnerExtractLaneI4(const SIMDValue src1, const uint32 lane) { Assert(lane < 4); return src1.i32[lane]; };
- static inline int16 SIMD128InnerExtractLaneI8(const SIMDValue src1, const uint32 lane) { Assert(lane < 8); return src1.i16[lane]; };
- static inline int8 SIMD128InnerExtractLaneI16(const SIMDValue src1, const uint32 lane) { Assert(lane < 16); return src1.i8[lane]; };
- static inline SIMDValue SIMD128BitSelect(const SIMDValue src1, const SIMDValue src2, const SIMDValue mask)
- {
- SIMDValue res{ 0 };
- res.i32[0] = (src1.i32[0] & mask.i32[0]) | (src2.i32[0] & ~mask.i32[0]);
- res.i32[1] = (src1.i32[1] & mask.i32[1]) | (src2.i32[1] & ~mask.i32[1]);
- res.i32[2] = (src1.i32[2] & mask.i32[2]) | (src2.i32[2] & ~mask.i32[2]);
- res.i32[3] = (src1.i32[3] & mask.i32[3]) | (src2.i32[3] & ~mask.i32[3]);
- return res;
- }
- ////////////////////////////////////////////
- // SIMD Shuffle Swizzle helpers
- ////////////////////////////////////////////
- static SIMDValue SIMD128InnerShuffle(const SIMDValue src1, const SIMDValue src2, uint32 laneCount, const uint32* lanes = nullptr);
- ///////////////////////////////////////////
- // SIMD Type conversion
- ///////////////////////////////////////////
- static SIMDValue FromSimdBits(const SIMDValue value);
- ///////////////////////////////////////////
- // SIMD Data load/store
- ///////////////////////////////////////////
- static SIMDValue SIMDLdData(const SIMDValue *data, uint8 dataWidth);
- static void SIMDStData(SIMDValue *data, const SIMDValue simdValue, uint8 dataWidth);
- template <typename T>
- static SIMDValue CanonicalizeToBools(SIMDValue val)
- {
- #ifdef ENABLE_WASM_SIMD
- CompileAssert(sizeof(T) <= sizeof(SIMDValue));
- CompileAssert(sizeof(SIMDValue) % sizeof(T) == 0);
- T* cursor = (T*)val.i8;
- const uint maxBytes = 16;
- uint size = maxBytes / sizeof(T);
- for (uint i = 0; i < size; i++)
- {
- cursor[i] = cursor[i] ? (T) -1 : 0;
- }
- return val;
- #else
- return val;
- #endif
- }
- static uint32 SimdOpcodeAsIndex(Js::OpCode op);
- };
- }
|