Commit 9e0ec794 authored by Evan Nemerson's avatar Evan Nemerson

sse, sse2: add range checks to several conversion functions

For value outside of (INT32_MIN, INT32_MAX), as well as NaNs, x86
returns INT32_MIN.

I added a SIMDE_FAST_CONVERSION_RANGE macro (which is defined by
default if SIMDE_FAST_MATH is defined) to opt-out of the more accurate
behavior since it's also substantially slower on many platforms.

Fixes #685
parent 16dfb46c
...@@ -112,6 +112,16 @@ ...@@ -112,6 +112,16 @@
#define SIMDE_FAST_ROUND_TIES #define SIMDE_FAST_ROUND_TIES
#endif #endif
/* For functions which convert from one type to another (mostly from
* floating point to integer types), sometimes we need to do a range
* check and potentially return a different result if the value
* falls outside that range. Skipping this check can provide a
* performance boost, at the expense of faithfulness to the API we're
* emulating. */
#if !defined(SIMDE_FAST_CONVERSION_RANGE) && !defined(SIMDE_NO_FAST_CONVERSION_RANGE) && defined(SIMDE_FAST_MATH)
#define SIMDE_FAST_CONVERSION_RANGE
#endif
#if \ #if \
HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \
HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
......
...@@ -1948,12 +1948,18 @@ simde_mm_cvtps_pi32 (simde__m128 a) { ...@@ -1948,12 +1948,18 @@ simde_mm_cvtps_pi32 (simde__m128 a) {
simde__m64_private r_; simde__m64_private r_;
simde__m128_private a_ = simde__m128_to_private(a); simde__m128_private a_ = simde__m128_to_private(a);
#if defined(SIMDE_ARM_NEON_A32V8_NATIVE) && !defined(SIMDE_BUG_GCC_95399) #if defined(SIMDE_ARM_NEON_A32V8_NATIVE) && defined(SIMDE_FAST_CONVERSION_RANGE) && !defined(SIMDE_BUG_GCC_95399)
r_.neon_i32 = vcvt_s32_f32(vget_low_f32(vrndiq_f32(a_.neon_f32))); r_.neon_i32 = vcvt_s32_f32(vget_low_f32(vrndiq_f32(a_.neon_f32)));
#else #else
SIMDE_VECTORIZE SIMDE_VECTORIZE
for (size_t i = 0 ; i < (sizeof(r_.i32) / sizeof(r_.i32[0])) ; i++) { for (size_t i = 0 ; i < (sizeof(r_.i32) / sizeof(r_.i32[0])) ; i++) {
r_.i32[i] = SIMDE_CONVERT_FTOI(int32_t, simde_math_roundf(a_.f32[i])); simde_float32 v = simde_math_roundf(a_.f32[i]);
#if !defined(SIMDE_FAST_CONVERSION_RANGE)
r_.i32[i] = ((v > HEDLEY_STATIC_CAST(simde_float32, INT32_MIN)) && (v < HEDLEY_STATIC_CAST(simde_float32, INT32_MAX))) ?
SIMDE_CONVERT_FTOI(int32_t, v) : INT32_MIN;
#else
r_.i32[i] = SIMDE_CONVERT_FTOI(int32_t, v);
#endif
} }
#endif #endif
...@@ -2161,14 +2167,18 @@ simde_mm_cvtt_ps2pi (simde__m128 a) { ...@@ -2161,14 +2167,18 @@ simde_mm_cvtt_ps2pi (simde__m128 a) {
simde__m64_private r_; simde__m64_private r_;
simde__m128_private a_ = simde__m128_to_private(a); simde__m128_private a_ = simde__m128_to_private(a);
#if defined(SIMDE_ARM_NEON_A32V7_NATIVE) #if defined(SIMDE_ARM_NEON_A32V7_NATIVE) && defined(SIMDE_FAST_CONVERSION_RANGE)
r_.neon_i32 = vcvt_s32_f32(vget_low_f32(a_.neon_f32)); r_.neon_i32 = vcvt_s32_f32(vget_low_f32(a_.neon_f32));
#elif defined(SIMDE_CONVERT_VECTOR_)
SIMDE_CONVERT_VECTOR_(r_.i32, a_.m64_private[0].f32);
#else #else
SIMDE_VECTORIZE SIMDE_VECTORIZE
for (size_t i = 0 ; i < (sizeof(r_.f32) / sizeof(r_.f32[0])) ; i++) { for (size_t i = 0 ; i < (sizeof(r_.f32) / sizeof(r_.f32[0])) ; i++) {
r_.i32[i] = SIMDE_CONVERT_FTOI(int32_t, a_.f32[i]); simde_float32 v = a_.f32[i];
#if !defined(SIMDE_FAST_CONVERSION_RANGE)
r_.i32[i] = ((v > HEDLEY_STATIC_CAST(simde_float32, INT32_MIN)) && (v < HEDLEY_STATIC_CAST(simde_float32, INT32_MAX))) ?
SIMDE_CONVERT_FTOI(int32_t, v) : INT32_MIN;
#else
r_.i32[i] = SIMDE_CONVERT_FTOI(int32_t, v);
#endif
} }
#endif #endif
...@@ -2189,10 +2199,16 @@ simde_mm_cvtt_ss2si (simde__m128 a) { ...@@ -2189,10 +2199,16 @@ simde_mm_cvtt_ss2si (simde__m128 a) {
#else #else
simde__m128_private a_ = simde__m128_to_private(a); simde__m128_private a_ = simde__m128_to_private(a);
#if defined(SIMDE_ARM_NEON_A32V7_NATIVE) #if defined(SIMDE_ARM_NEON_A32V7_NATIVE) && defined(SIMDE_FAST_CONVERSION_RANGE)
return SIMDE_CONVERT_FTOI(int32_t, vgetq_lane_f32(a_.neon_f32, 0)); return SIMDE_CONVERT_FTOI(int32_t, vgetq_lane_f32(a_.neon_f32, 0));
#else #else
return SIMDE_CONVERT_FTOI(int32_t, a_.f32[0]); simde_float32 v = a_.f32[0];
#if !defined(SIMDE_FAST_CONVERSION_RANGE)
return ((v > HEDLEY_STATIC_CAST(simde_float32, INT32_MIN)) && (v < HEDLEY_STATIC_CAST(simde_float32, INT32_MAX))) ?
SIMDE_CONVERT_FTOI(int32_t, v) : INT32_MIN;
#else
return SIMDE_CONVERT_FTOI(int32_t, v);
#endif
#endif #endif
#endif #endif
} }
......
...@@ -2515,46 +2515,48 @@ simde_mm_cvtepi32_ps (simde__m128i a) { ...@@ -2515,46 +2515,48 @@ simde_mm_cvtepi32_ps (simde__m128i a) {
#endif #endif
SIMDE_FUNCTION_ATTRIBUTES SIMDE_FUNCTION_ATTRIBUTES
simde__m128i simde__m64
simde_mm_cvtpd_epi32 (simde__m128d a) { simde_mm_cvtpd_pi32 (simde__m128d a) {
#if defined(SIMDE_X86_SSE2_NATIVE) #if defined(SIMDE_X86_SSE2_NATIVE) && defined(SIMDE_X86_MMX_NATIVE)
return _mm_cvtpd_epi32(a); return _mm_cvtpd_pi32(a);
#else #else
simde__m128i_private r_; simde__m64_private r_;
simde__m128d_private a_ = simde__m128d_to_private(a); simde__m128d_private a_ = simde__m128d_to_private(a);
SIMDE_VECTORIZE SIMDE_VECTORIZE
for (size_t i = 0 ; i < (sizeof(a_.f64) / sizeof(a_.f64[0])) ; i++) { for (size_t i = 0 ; i < (sizeof(r_.i32) / sizeof(r_.i32[0])) ; i++) {
r_.i32[i] = SIMDE_CONVERT_FTOI(int32_t, simde_math_nearbyint(a_.f64[i])); simde_float64 v = simde_math_round(a_.f64[i]);
#if defined(SIMDE_FAST_CONVERSION_RANGE)
r_.i32[i] = SIMDE_CONVERT_FTOI(int32_t, v);
#else
r_.i32[i] = ((v > HEDLEY_STATIC_CAST(simde_float64, INT32_MIN)) && (v < HEDLEY_STATIC_CAST(simde_float64, INT32_MAX))) ?
SIMDE_CONVERT_FTOI(int32_t, v) : INT32_MIN;
#endif
} }
simde_memset(&(r_.m64_private[1]), 0, sizeof(r_.m64_private[1]));
return simde__m128i_from_private(r_); return simde__m64_from_private(r_);
#endif #endif
} }
#if defined(SIMDE_X86_SSE2_ENABLE_NATIVE_ALIASES) #if defined(SIMDE_X86_SSE2_ENABLE_NATIVE_ALIASES)
#define _mm_cvtpd_epi32(a) simde_mm_cvtpd_epi32(a) #define _mm_cvtpd_pi32(a) simde_mm_cvtpd_pi32(a)
#endif #endif
SIMDE_FUNCTION_ATTRIBUTES SIMDE_FUNCTION_ATTRIBUTES
simde__m64 simde__m128i
simde_mm_cvtpd_pi32 (simde__m128d a) { simde_mm_cvtpd_epi32 (simde__m128d a) {
#if defined(SIMDE_X86_SSE2_NATIVE) && defined(SIMDE_X86_MMX_NATIVE) #if defined(SIMDE_X86_SSE2_NATIVE)
return _mm_cvtpd_pi32(a); return _mm_cvtpd_epi32(a);
#else #else
simde__m64_private r_; simde__m128i_private r_;
simde__m128d_private a_ = simde__m128d_to_private(a);
SIMDE_VECTORIZE r_.m64[0] = simde_mm_cvtpd_pi32(a);
for (size_t i = 0 ; i < (sizeof(r_.i32) / sizeof(r_.i32[0])) ; i++) { r_.m64[1] = simde_mm_setzero_si64();
r_.i32[i] = HEDLEY_STATIC_CAST(int32_t, simde_math_nearbyint(a_.f64[i]));
}
return simde__m64_from_private(r_); return simde__m128i_from_private(r_);
#endif #endif
} }
#if defined(SIMDE_X86_SSE2_ENABLE_NATIVE_ALIASES) #if defined(SIMDE_X86_SSE2_ENABLE_NATIVE_ALIASES)
#define _mm_cvtpd_pi32(a) simde_mm_cvtpd_pi32(a) #define _mm_cvtpd_epi32(a) simde_mm_cvtpd_epi32(a)
#endif #endif
SIMDE_FUNCTION_ATTRIBUTES SIMDE_FUNCTION_ATTRIBUTES
...@@ -2620,11 +2622,11 @@ simde_mm_cvtps_epi32 (simde__m128 a) { ...@@ -2620,11 +2622,11 @@ simde_mm_cvtps_epi32 (simde__m128 a) {
simde__m128i_private r_; simde__m128i_private r_;
simde__m128_private a_ = simde__m128_to_private(a); simde__m128_private a_ = simde__m128_to_private(a);
#if defined(SIMDE_ARM_NEON_A64V8_NATIVE) #if defined(SIMDE_ARM_NEON_A64V8_NATIVE) && defined(SIMDE_FAST_CONVERSION_RANGE)
r_.neon_i32 = vcvtnq_s32_f32(a_.neon_f32); r_.neon_i32 = vcvtnq_s32_f32(a_.neon_f32);
#elif defined(SIMDE_ARM_NEON_A32V7_NATIVE) && defined(SIMDE_FAST_ROUND_TIES) #elif defined(SIMDE_ARM_NEON_A32V7_NATIVE) && defined(SIMDE_FAST_CONVERSION_RANGE) && defined(SIMDE_FAST_ROUND_TIES)
r_.neon_i32 = vcvtnq_s32_f32(a_.neon_f32); r_.neon_i32 = vcvtnq_s32_f32(a_.neon_f32);
#elif defined(SIMDE_POWER_ALTIVEC_P6_NATIVE) && defined(SIMDE_FAST_ROUND_TIES) #elif defined(SIMDE_POWER_ALTIVEC_P6_NATIVE) && defined(SIMDE_FAST_CONVERSION_RANGE) && defined(SIMDE_FAST_ROUND_TIES)
HEDLEY_DIAGNOSTIC_PUSH HEDLEY_DIAGNOSTIC_PUSH
SIMDE_DIAGNOSTIC_DISABLE_C11_EXTENSIONS_ SIMDE_DIAGNOSTIC_DISABLE_C11_EXTENSIONS_
SIMDE_DIAGNOSTIC_DISABLE_VECTOR_CONVERSION_ SIMDE_DIAGNOSTIC_DISABLE_VECTOR_CONVERSION_
...@@ -2634,7 +2636,13 @@ simde_mm_cvtps_epi32 (simde__m128 a) { ...@@ -2634,7 +2636,13 @@ simde_mm_cvtps_epi32 (simde__m128 a) {
a_ = simde__m128_to_private(simde_x_mm_round_ps(a, SIMDE_MM_FROUND_TO_NEAREST_INT, 1)); a_ = simde__m128_to_private(simde_x_mm_round_ps(a, SIMDE_MM_FROUND_TO_NEAREST_INT, 1));
SIMDE_VECTORIZE SIMDE_VECTORIZE
for (size_t i = 0 ; i < (sizeof(r_.i32) / sizeof(r_.i32[0])) ; i++) { for (size_t i = 0 ; i < (sizeof(r_.i32) / sizeof(r_.i32[0])) ; i++) {
r_.i32[i] = HEDLEY_STATIC_CAST(int32_t, a_.f32[i]); simde_float32 v = simde_math_roundf(a_.f32[i]);
#if defined(SIMDE_FAST_CONVERSION_RANGE)
r_.i32[i] = SIMDE_CONVERT_FTOI(int32_t, v);
#else
r_.i32[i] = ((v > HEDLEY_STATIC_CAST(simde_float32, INT32_MIN)) && (v < HEDLEY_STATIC_CAST(simde_float32, INT32_MAX))) ?
SIMDE_CONVERT_FTOI(int32_t, v) : INT32_MIN;
#endif
} }
#endif #endif
...@@ -2679,7 +2687,14 @@ simde_mm_cvtsd_si32 (simde__m128d a) { ...@@ -2679,7 +2687,14 @@ simde_mm_cvtsd_si32 (simde__m128d a) {
return _mm_cvtsd_si32(a); return _mm_cvtsd_si32(a);
#else #else
simde__m128d_private a_ = simde__m128d_to_private(a); simde__m128d_private a_ = simde__m128d_to_private(a);
return SIMDE_CONVERT_FTOI(int32_t, simde_math_round(a_.f64[0]));
simde_float64 v = simde_math_round(a_.f64[0]);
#if defined(SIMDE_FAST_CONVERSION_RANGE)
return SIMDE_CONVERT_FTOI(int32_t, v);
#else
return ((v > HEDLEY_STATIC_CAST(simde_float64, INT32_MIN)) && (v < HEDLEY_STATIC_CAST(simde_float64, INT32_MAX))) ?
SIMDE_CONVERT_FTOI(int32_t, v) : INT32_MIN;
#endif
#endif #endif
} }
#if defined(SIMDE_X86_SSE2_ENABLE_NATIVE_ALIASES) #if defined(SIMDE_X86_SSE2_ENABLE_NATIVE_ALIASES)
...@@ -2962,27 +2977,6 @@ simde_mm_cvtss_sd (simde__m128d a, simde__m128 b) { ...@@ -2962,27 +2977,6 @@ simde_mm_cvtss_sd (simde__m128d a, simde__m128 b) {
#define _mm_cvtss_sd(a, b) simde_mm_cvtss_sd(a, b) #define _mm_cvtss_sd(a, b) simde_mm_cvtss_sd(a, b)
#endif #endif
SIMDE_FUNCTION_ATTRIBUTES
simde__m128i
simde_mm_cvttpd_epi32 (simde__m128d a) {
#if defined(SIMDE_X86_SSE2_NATIVE)
return _mm_cvttpd_epi32(a);
#else
simde__m128i_private r_;
simde__m128d_private a_ = simde__m128d_to_private(a);
for (size_t i = 0 ; i < (sizeof(a_.f64) / sizeof(a_.f64[0])) ; i++) {
r_.i32[i] = SIMDE_CONVERT_FTOI(int32_t, a_.f64[i]);
}
simde_memset(&(r_.m64_private[1]), 0, sizeof(r_.m64_private[1]));
return simde__m128i_from_private(r_);
#endif
}
#if defined(SIMDE_X86_SSE2_ENABLE_NATIVE_ALIASES)
#define _mm_cvttpd_epi32(a) simde_mm_cvttpd_epi32(a)
#endif
SIMDE_FUNCTION_ATTRIBUTES SIMDE_FUNCTION_ATTRIBUTES
simde__m64 simde__m64
simde_mm_cvttpd_pi32 (simde__m128d a) { simde_mm_cvttpd_pi32 (simde__m128d a) {
...@@ -2992,11 +2986,17 @@ simde_mm_cvttpd_pi32 (simde__m128d a) { ...@@ -2992,11 +2986,17 @@ simde_mm_cvttpd_pi32 (simde__m128d a) {
simde__m64_private r_; simde__m64_private r_;
simde__m128d_private a_ = simde__m128d_to_private(a); simde__m128d_private a_ = simde__m128d_to_private(a);
#if defined(SIMDE_CONVERT_VECTOR_) #if defined(SIMDE_CONVERT_VECTOR_) && defined(SIMDE_FAST_CONVERSION_RANGE)
SIMDE_CONVERT_VECTOR_(r_.i32, a_.f64); SIMDE_CONVERT_VECTOR_(r_.i32, a_.f64);
#else #else
for (size_t i = 0 ; i < (sizeof(r_.i32) / sizeof(r_.i32[0])) ; i++) { for (size_t i = 0 ; i < (sizeof(r_.i32) / sizeof(r_.i32[0])) ; i++) {
r_.i32[i] = SIMDE_CONVERT_FTOI(int32_t, a_.f64[i]); simde_float64 v = a_.f64[i];
#if defined(SIMDE_FAST_CONVERSION_RANGE)
r_.i32[i] = SIMDE_CONVERT_FTOI(int32_t, v);
#else
r_.i32[i] = ((v > HEDLEY_STATIC_CAST(simde_float64, INT32_MIN)) && (v < HEDLEY_STATIC_CAST(simde_float64, INT32_MAX))) ?
SIMDE_CONVERT_FTOI(int32_t, v) : INT32_MIN;
#endif
} }
#endif #endif
...@@ -3007,6 +3007,24 @@ simde_mm_cvttpd_pi32 (simde__m128d a) { ...@@ -3007,6 +3007,24 @@ simde_mm_cvttpd_pi32 (simde__m128d a) {
#define _mm_cvttpd_pi32(a) simde_mm_cvttpd_pi32(a) #define _mm_cvttpd_pi32(a) simde_mm_cvttpd_pi32(a)
#endif #endif
SIMDE_FUNCTION_ATTRIBUTES
simde__m128i
simde_mm_cvttpd_epi32 (simde__m128d a) {
#if defined(SIMDE_X86_SSE2_NATIVE)
return _mm_cvttpd_epi32(a);
#else
simde__m128i_private r_;
r_.m64[0] = simde_mm_cvttpd_pi32(a);
r_.m64[1] = simde_mm_setzero_si64();
return simde__m128i_from_private(r_);
#endif
}
#if defined(SIMDE_X86_SSE2_ENABLE_NATIVE_ALIASES)
#define _mm_cvttpd_epi32(a) simde_mm_cvttpd_epi32(a)
#endif
SIMDE_FUNCTION_ATTRIBUTES SIMDE_FUNCTION_ATTRIBUTES
simde__m128i simde__m128i
simde_mm_cvttps_epi32 (simde__m128 a) { simde_mm_cvttps_epi32 (simde__m128 a) {
...@@ -3016,13 +3034,19 @@ simde_mm_cvttps_epi32 (simde__m128 a) { ...@@ -3016,13 +3034,19 @@ simde_mm_cvttps_epi32 (simde__m128 a) {
simde__m128i_private r_; simde__m128i_private r_;
simde__m128_private a_ = simde__m128_to_private(a); simde__m128_private a_ = simde__m128_to_private(a);
#if defined(SIMDE_ARM_NEON_A32V7_NATIVE) #if defined(SIMDE_ARM_NEON_A32V7_NATIVE) && defined(SIMDE_FAST_CONVERSION_RANGE)
r_.neon_i32 = vcvtq_s32_f32(a_.neon_f32); r_.neon_i32 = vcvtq_s32_f32(a_.neon_f32);
#elif defined(SIMDE_CONVERT_VECTOR_) #elif defined(SIMDE_CONVERT_VECTOR_) && defined(SIMDE_FAST_CONVERSION_RANGE)
SIMDE_CONVERT_VECTOR_(r_.i32, a_.f32); SIMDE_CONVERT_VECTOR_(r_.i32, a_.f32);
#else #else
for (size_t i = 0 ; i < (sizeof(r_.i32) / sizeof(r_.i32[0])) ; i++) { for (size_t i = 0 ; i < (sizeof(r_.i32) / sizeof(r_.i32[0])) ; i++) {
r_.i32[i] = SIMDE_CONVERT_FTOI(int32_t, a_.f32[i]); simde_float32 v = a_.f32[i];
#if defined(SIMDE_FAST_CONVERSION_RANGE)
r_.i32[i] = SIMDE_CONVERT_FTOI(int32_t, v);
#else
r_.i32[i] = ((v > HEDLEY_STATIC_CAST(simde_float32, INT32_MIN)) && (v < HEDLEY_STATIC_CAST(simde_float32, INT32_MAX))) ?
SIMDE_CONVERT_FTOI(int32_t, v) : INT32_MIN;
#endif
} }
#endif #endif
...@@ -3040,7 +3064,13 @@ simde_mm_cvttsd_si32 (simde__m128d a) { ...@@ -3040,7 +3064,13 @@ simde_mm_cvttsd_si32 (simde__m128d a) {
return _mm_cvttsd_si32(a); return _mm_cvttsd_si32(a);
#else #else
simde__m128d_private a_ = simde__m128d_to_private(a); simde__m128d_private a_ = simde__m128d_to_private(a);
return SIMDE_CONVERT_FTOI(int32_t, a_.f64[0]); simde_float64 v = a_.f64[0];
#if defined(SIMDE_FAST_CONVERSION_RANGE)
return SIMDE_CONVERT_FTOI(int32_t, v);
#else
return ((v > HEDLEY_STATIC_CAST(simde_float64, INT32_MIN)) && (v < HEDLEY_STATIC_CAST(simde_float64, INT32_MAX))) ?
SIMDE_CONVERT_FTOI(int32_t, v) : INT32_MIN;
#endif
#endif #endif
} }
#if defined(SIMDE_X86_SSE2_ENABLE_NATIVE_ALIASES) #if defined(SIMDE_X86_SSE2_ENABLE_NATIVE_ALIASES)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment