From bc1b8bd1dc3ff0784b90fef7cfc9d068ff2fed59 Mon Sep 17 00:00:00 2001
From: Developer <dev@localhost>
Date: Tue, 14 Jul 2026 21:21:37 +0000
Subject: [PATCH 12/17] ppc: use wraparound (not saturating) add/sub/pack in
 IDCT4/IDCT8 math

Continuation of the AltiVec IDCT correctness work: the plain-C reference
this port must match bit-exact (vpx_dsp/inv_txfm.c) computes every
transform-stage addition, subtraction, and round-shift-then-narrow step
on wide (>=32-bit) intermediates and only narrows to 16 bits at specific
points via implicit C truncating conversion -- never via saturation.
This file's IDCT4 (idct4_vmx, vpx_idct4x4_16_add_altivec) and the shared
IDCT8 macro used saturating vec_adds/vec_subs for stage additions and
saturating vec_packs for the round-shift narrowing step, which silently
diverges from the reference the moment any intermediate would exceed the
int16 range -- exactly the kind of large-residual coefficient that shows
up in high-detail/high-motion content, matching the reported symptom
("moving objects look really bad, made of large pixels").

Switched the affected sites to plain (non-saturating) vec_add/vec_sub and
vec_pack, which truncate the same way the reference's implicit int16
narrowing does. Left every genuinely saturating operation alone: the
final pixel reconstruction (vec_packsu, clamping residual+prediction to
0..255) is correct as-is, and vec_msum's wide 32-bit accumulation was
already non-saturating and unaffected.

Verified against the QEMU/AltiVec cross-check harness: all four DC-only
functions plus the pure-DCT_DCT paths of vpx_idct4x4_16_add and
vp9_iht4x4_16_add now match vpx_dsp/inv_txfm.c's C reference exactly
(0 failures) at every coefficient magnitude tested, including full
int16 range extremes, where they previously diverged. IADST-involving
paths (tx_type 1-3) in this same file still fail the cross-check on
specific extreme-magnitude coefficient combinations and are not fixed by
this commit -- the existing iadst4/8/16_vmx routines use a hand-optimized
algebraic rearrangement that doesn't map cleanly onto either the SSE2 or
scalar-C reference for verification, and are being reworked separately.
8x8/16x16/32x32 IDCT (non-IADST) paths likely share this same class of
fix but are not yet done.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DLC53yuiz8taQDNndUp4rs
---
 vpx_dsp/ppc/vpx_idct_altivec.c | 48 +++++++++++++++++-----------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/vpx_dsp/ppc/vpx_idct_altivec.c b/vpx_dsp/ppc/vpx_idct_altivec.c
index 3fcb01f08..3268222fd 100644
--- a/vpx_dsp/ppc/vpx_idct_altivec.c
+++ b/vpx_dsp/ppc/vpx_idct_altivec.c
@@ -214,8 +214,8 @@ void vpx_idct4x4_16_add_altivec(const tran_low_t *input, uint8_t *dest, int stri
 	wnput3 = vec_sra(wnput3, dct_bitshift_vec);
 
 	// Stage 2. Pack back to short.
-	input0 = vec_packs(wnput0, wnput1);
-	input1 = vec_packs(wnput2, wnput3);
+	input0 = vec_pack(wnput0, wnput1);
+	input1 = vec_pack(wnput2, wnput3);
 
 	// Transpose.
 	input2 = vec_mergeh(input0, input1);
@@ -253,8 +253,8 @@ void vpx_idct4x4_16_add_altivec(const tran_low_t *input, uint8_t *dest, int stri
 	wnput3 = vec_sra(wnput3, dct_bitshift_vec);
 
 	// Stage 2 again. Pack back to short.
-	input0 = vec_packs(wnput0, wnput2);
-	input1 = vec_packs(wnput1, wnput3);
+	input0 = vec_pack(wnput0, wnput2);
+	input1 = vec_pack(wnput1, wnput3);
 
 	// Transpose again.
 	input2 = vec_mergeh(input0, input1);
@@ -535,8 +535,8 @@ static void idct4_vmx(vector signed short *in) {
 	w[2] = vec_sra(w[2], dct_bitshift_vec);
 	w[3] = vec_sra(w[3], dct_bitshift_vec);
 
-	u[0] = vec_packs(w[0], w[1]);
-	u[1] = vec_packs(w[3], w[2]);
+	u[0] = vec_pack(w[0], w[1]);
+	u[1] = vec_pack(w[3], w[2]);
 
 	// Stage 2.
 	in[0] = vec_add(u[0], u[1]);
@@ -601,8 +601,8 @@ static void iadst4_vmx(vector signed short *in) {
 	w[2] = vec_sra(v[2], dct_bitshift_vec);
 	w[3] = vec_sra(v[3], dct_bitshift_vec);
 
-	in[0] = vec_packs(w[0], w[1]);
-	in[1] = vec_packs(w[2], w[3]);
+	in[0] = vec_pack(w[0], w[1]);
+	in[1] = vec_pack(w[2], w[3]);
 }
 
 void vp9_iht4x4_16_add_altivec(const tran_low_t *input, uint8_t *dest, int stride, int tx_type) {
@@ -760,10 +760,10 @@ void vp9_iht4x4_16_add_altivec(const tran_low_t *input, uint8_t *dest, int strid
                            stg2_1, stg2_2, stg2_3, stp2_0,     \
                            stp2_1, stp2_2, stp2_3)             \
     \
-	stp2_4 = vec_adds(stp1_4, stp1_5); \
-	stp2_5 = vec_subs(stp1_4, stp1_5); \
-	stp2_6 = vec_subs(stp1_7, stp1_6); \
-	stp2_7 = vec_adds(stp1_7, stp1_6); \
+	stp2_4 = vec_add(stp1_4, stp1_5); \
+	stp2_5 = vec_sub(stp1_4, stp1_5); \
+	stp2_6 = vec_sub(stp1_7, stp1_6); \
+	stp2_7 = vec_add(stp1_7, stp1_6); \
   } \
     \
   /* Stage 3. */ \
@@ -771,10 +771,10 @@ void vp9_iht4x4_16_add_altivec(const tran_low_t *input, uint8_t *dest, int strid
 	vector signed short lo_56 = vec_mergeh(stp2_6, stp2_5); \
 	vector signed short hi_56 = vec_mergel(stp2_6, stp2_5); \
     \
-	stp1_0 = vec_adds(stp2_0, stp2_3); \
-	stp1_1 = vec_adds(stp2_1, stp2_2); \
-	stp1_2 = vec_subs(stp2_1, stp2_2); \
-	stp1_3 = vec_subs(stp2_0, stp2_3); \
+	stp1_0 = vec_add(stp2_0, stp2_3); \
+	stp1_1 = vec_add(stp2_1, stp2_2); \
+	stp1_2 = vec_sub(stp2_1, stp2_2); \
+	stp1_3 = vec_sub(stp2_0, stp2_3); \
     \
 	tmp0 = vec_msum(lo_56, stg2_1, dct_rounding_vec); \
 	tmp1 = vec_msum(hi_56, stg2_1, dct_rounding_vec); \
@@ -791,14 +791,14 @@ void vp9_iht4x4_16_add_altivec(const tran_low_t *input, uint8_t *dest, int strid
   } \
   \
   /* Stage 4.  */ \
-	out0 = vec_adds(stp1_0, stp2_7); \
-	out1 = vec_adds(stp1_1, stp1_6); \
-	out2 = vec_adds(stp1_2, stp1_5); \
-	out3 = vec_adds(stp1_3, stp2_4); \
-	out4 = vec_subs(stp1_3, stp2_4); \
-	out5 = vec_subs(stp1_2, stp1_5); \
-	out6 = vec_subs(stp1_1, stp1_6); \
-	out7 = vec_subs(stp1_0, stp2_7); \
+	out0 = vec_add(stp1_0, stp2_7); \
+	out1 = vec_add(stp1_1, stp1_6); \
+	out2 = vec_add(stp1_2, stp1_5); \
+	out3 = vec_add(stp1_3, stp2_4); \
+	out4 = vec_sub(stp1_3, stp2_4); \
+	out5 = vec_sub(stp1_2, stp1_5); \
+	out6 = vec_sub(stp1_1, stp1_6); \
+	out7 = vec_sub(stp1_0, stp2_7); \
   }
 
 void vpx_idct8x8_64_add_altivec(const tran_low_t *input, uint8_t *dest, int stride) {
-- 
2.43.0

