diff --git a/ps2xRecomp/src/lib/code_generator.cpp b/ps2xRecomp/src/lib/code_generator.cpp index 272e45d..3a24521 100644 --- a/ps2xRecomp/src/lib/code_generator.cpp +++ b/ps2xRecomp/src/lib/code_generator.cpp @@ -2057,15 +2057,10 @@ namespace ps2recomp return fmt::format("SET_GPR_VEC(ctx, {}, PS2_PSUBB(GPR_VEC(ctx, {}), GPR_VEC(ctx, {})));", rd, rs, rt); case MMI0_PCGTB: return fmt::format("SET_GPR_VEC(ctx, {}, PS2_PCGTB(GPR_VEC(ctx, {}), GPR_VEC(ctx, {})));", rd, rs, rt); - // thouse 2 require SSE4.1 now TODO implement on SSE2 case MMI0_PADDSW: - return fmt::format("SET_GPR_VEC(ctx, {}, _mm_min_epi32(_mm_max_epi32(_mm_add_epi32(GPR_VEC(ctx, {}), GPR_VEC(ctx, {})), " - "_mm_set1_epi32(INT32_MIN)), _mm_set1_epi32(INT32_MAX)));", - rd, rs, rt); + return fmt::format("SET_GPR_VEC(ctx, {}, PS2_PADDSW(GPR_VEC(ctx, {}), GPR_VEC(ctx, {})));", rd, rs, rt); case MMI0_PSUBSW: - return fmt::format("SET_GPR_VEC(ctx, {}, _mm_min_epi32(_mm_max_epi32(_mm_sub_epi32(GPR_VEC(ctx, {}), GPR_VEC(ctx, {})), " - "_mm_set1_epi32(INT32_MIN)), _mm_set1_epi32(INT32_MAX)));", - rd, rs, rt); + return fmt::format("SET_GPR_VEC(ctx, {}, PS2_PSUBSW(GPR_VEC(ctx, {}), GPR_VEC(ctx, {})));", rd, rs, rt); case MMI0_PEXTLW: return fmt::format("SET_GPR_VEC(ctx, {}, PS2_PEXTLW(GPR_VEC(ctx, {}), GPR_VEC(ctx, {})));", rd, rs, rt); case MMI0_PPACW: diff --git a/ps2xRuntime/include/ps2_runtime_macros.h b/ps2xRuntime/include/ps2_runtime_macros.h index 6413333..f7b3316 100644 --- a/ps2xRuntime/include/ps2_runtime_macros.h +++ b/ps2xRuntime/include/ps2_runtime_macros.h @@ -426,6 +426,60 @@ static inline void Ps2FastWrite128(uint8_t *rdram, uint32_t addr, __m128i value) #define PS2_PCGTH(a, b) _mm_cmpgt_epi16((__m128i)(a), (__m128i)(b)) #define PS2_PCGTB(a, b) _mm_cmpgt_epi8((__m128i)(a), (__m128i)(b)) +// Packed Add with Signed Saturation Word (PADDSW) +inline __m128i ps2_paddsw(__m128i a, __m128i b) +{ + + __m128i sum = _mm_add_epi32(a, b); + // Check for over/underflow. Clamp to either INT32_MIN/INT32_MAX. + __m128i overflow = _mm_and_si128(_mm_xor_si128(a, sum), + _mm_xor_si128(b, sum)); + // Extract input sign. + overflow = _mm_srai_epi32(overflow, 31); + __m128i input_sign = _mm_srai_epi32(a, 31); + // Select saturation value based on overflow sign. + #if defined(__SSE4_1__) + __m128i sat = _mm_blendv_epi8( + _mm_set1_epi32(INT32_MAX), + _mm_set1_epi32(INT32_MIN), + input_sign); + return _mm_blendv_epi8(sum, sat, overflow); + #else + __m128i sat = _mm_or_si128(_mm_and_si128(input_sign, _mm_set1_epi32(INT32_MIN)), + _mm_andnot_si128(input_sign, _mm_set1_epi32(INT32_MAX))); + return _mm_or_si128(_mm_and_si128(overflow, sat), + _mm_andnot_si128(overflow, sum)); + #endif +} +#define PS2_PADDSW(a, b) ps2_paddsw((__m128i)(a), (__m128i)(b)) + +// Packed Subtract with Signed Saturation Word (PSUBSW) +inline __m128i ps2_psubsw(__m128i a, __m128i b) +{ + __m128i diff = _mm_sub_epi32(a, b); + // Check for over/underflow. Clamp to either INT32_MIN/INT32_MAX. + __m128i overflow = _mm_and_si128(_mm_xor_si128(a, b), + _mm_xor_si128(a, diff)); + // Extract input sign. + overflow = _mm_srai_epi32(overflow, 31); + __m128i input_sign = _mm_srai_epi32(a, 31); + // Select saturation value based on overflow sign. + #if defined(__SSE4_1__) + __m128i sat = _mm_blendv_epi8( + _mm_set1_epi32(INT32_MAX), + _mm_set1_epi32(INT32_MIN), + input_sign); + return _mm_blendv_epi8(diff, sat, overflow); + #else + __m128i sat = _mm_or_si128(_mm_and_si128(input_sign, _mm_set1_epi32(INT32_MIN)), + _mm_andnot_si128(input_sign, _mm_set1_epi32(INT32_MAX))); + return _mm_or_si128(_mm_and_si128(overflow, sat), + _mm_andnot_si128(overflow, diff)); + #endif + +} +#define PS2_PSUBSW(a, b) ps2_psubsw((__m128i)(a), (__m128i)(b)) + // Packed Compare Equal (PCEQ) #define PS2_PCEQW(a, b) _mm_cmpeq_epi32((__m128i)(a), (__m128i)(b)) #define PS2_PCEQH(a, b) _mm_cmpeq_epi16((__m128i)(a), (__m128i)(b))