diff --git a/include/FastSIMD/ToolSet/x86/512/f32x16.h b/include/FastSIMD/ToolSet/x86/512/f32x16.h index 09bc12a..0d3293a 100644 --- a/include/FastSIMD/ToolSet/x86/512/f32x16.h +++ b/include/FastSIMD/ToolSet/x86/512/f32x16.h @@ -18,6 +18,12 @@ namespace FS FS_FORCEINLINE Register() = default; FS_FORCEINLINE Register( NativeType v ) : native( v ) { } FS_FORCEINLINE Register( float v ) : native( _mm512_set1_ps( v ) ) { } +#if defined( _MSC_VER ) && !defined( __clang__ ) + // MSVC copies trivially copyable 64 byte structs as two 32 byte halves, reloading those as a 512 bit register + // stalls store forwarding. Copying the native vector keeps register copies in zmm registers + FS_FORCEINLINE Register( const Register& v ) : native( v.native ) { } + FS_FORCEINLINE Register& operator =( const Register& v ) { native = v.native; return *this; } +#endif FS_FORCEINLINE NativeType GetNative() const { diff --git a/include/FastSIMD/ToolSet/x86/512/i32x16.h b/include/FastSIMD/ToolSet/x86/512/i32x16.h index 00c07d3..4cd504b 100644 --- a/include/FastSIMD/ToolSet/x86/512/i32x16.h +++ b/include/FastSIMD/ToolSet/x86/512/i32x16.h @@ -18,6 +18,12 @@ namespace FS FS_FORCEINLINE Register() = default; FS_FORCEINLINE Register( NativeType v ) : native( v ) { } FS_FORCEINLINE Register( std::int32_t v ) : native( _mm512_set1_epi32( v ) ) { } +#if defined( _MSC_VER ) && !defined( __clang__ ) + // MSVC copies trivially copyable 64 byte structs as two 32 byte halves, reloading those as a 512 bit register + // stalls store forwarding. Copying the native vector keeps register copies in zmm registers + FS_FORCEINLINE Register( const Register& v ) : native( v.native ) { } + FS_FORCEINLINE Register& operator =( const Register& v ) { native = v.native; return *this; } +#endif FS_FORCEINLINE NativeType GetNative() const { diff --git a/include/FastSIMD/ToolSet/x86/512/mNx16.h b/include/FastSIMD/ToolSet/x86/512/mNx16.h index 70b2af9..0785204 100644 --- a/include/FastSIMD/ToolSet/x86/512/mNx16.h +++ b/include/FastSIMD/ToolSet/x86/512/mNx16.h @@ -26,6 +26,12 @@ namespace FS FS_FORCEINLINE Register() = default; FS_FORCEINLINE Register( NativeType v ) { this->native = v; } +#if defined( _MSC_VER ) && !defined( __clang__ ) + // MSVC writes copies of a 32 lane composite mask with two 16 bit stores and reads them back with one 32 bit load, + // which can't be store forwarded. Copying the native mask keeps the halves in registers + FS_FORCEINLINE Register( const Register& v ) { this->native = v.native; } + FS_FORCEINLINE Register& operator =( const Register& v ) { this->native = v.native; return *this; } +#endif FS_FORCEINLINE NativeType GetNative() const { @@ -67,4 +73,13 @@ namespace FS { return static_cast>( a.native ); } + +#if defined( _MSC_VER ) && !defined( __clang__ ) + // MSVC moves both mask halves to general purpose registers to OR them + template, 16, SIMD>>> + FS_FORCEINLINE bool AnyMask( const Register, 32, SIMD>& a ) + { + return !_mm512_kortestz( a.v0.native, a.v1.native ); + } +#endif } \ No newline at end of file