From a06d71c6d6ed943c7cc5d80884dea6be49315b81 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Sat, 15 Aug 2026 20:35:37 +0000 Subject: [PATCH 34/38] avcodec/cabac: PPC scalar CABAC optimizations, from PowerVLC Two ARCH_PPC-guarded changes to the shared CABAC reader, both from PowerVLC (github.com/Olsro/powervlc, contrib/src/ffmpeg, their patches 0001/0002), measured on a 1.42 GHz 7447A: 1. LPS renormalization via cntlzw: ff_h264_norm_shift[r] equals __builtin_clz(r) - 23 for the whole domain r in [2, 511] (verified exhaustively against the renormalization definition). One single-cycle ALU op replaces a table load on the critical renormalization path -- no load/store-unit slot, no potential cache miss. Guarded on ARCH_PPC && HAVE_FAST_CLZ (configure enables fast_clz for all PowerPC). 2. Force get_cabac() inline on PPC: every other architecture overrides get_cabac_inline() with assembly, so nobody noticed that GCC emits a real out-of-line get_cabac and calls it from all 73 bin sites in h264_cabac.o -- per bin a call/return, a full PIC prologue to re-find ff_h264_cabac_tables, and a reload+store of the low/range state that CABAC_ON_STACK exists precisely to keep in a local. Bit-exact by construction. PowerVLC measured +3.5% on a 720p High 4.8 Mbit/s H.264 decode (+0.6% at 1080p 1.8 Mbit/s; CABAC's share grows with bitrate). Also taken by the HEVC decoder, which reads bins through the same get_cabac(). No other architecture changes: both are dead #defines elsewhere. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01PRRFPPzH3qXUcq8Ask5LZh --- libavcodec/cabac_functions.h | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/libavcodec/cabac_functions.h b/libavcodec/cabac_functions.h index 6a2e9ce..567740e 100644 --- a/libavcodec/cabac_functions.h +++ b/libavcodec/cabac_functions.h @@ -128,7 +128,16 @@ static av_always_inline int get_cabac_inline(CABACContext *c, uint8_t * const st *state= (ff_h264_mlps_state+128)[s]; bit= s&1; +#if ARCH_PPC && HAVE_FAST_CLZ + /* ff_h264_norm_shift[r] == 31 - log2(r) - 23 for r in [2, 511]; + * cntlzw computes it in one instruction and, unlike the table lookup, + * does not occupy the single load/store unit of the G3/G4 nor risk a + * cache miss on the critical renormalization path. + * From PowerVLC (github.com/Olsro/powervlc, contrib/src/ffmpeg). */ + lps_mask= __builtin_clz(c->range) - 23; +#else lps_mask= ff_h264_norm_shift[c->range]; +#endif c->range<<= lps_mask; c->low <<= lps_mask; if(!(c->low & CABAC_MASK)) @@ -141,7 +150,23 @@ av_unused av_noinline static int get_cabac_noinline(CABACContext *c, uint8_t * c return get_cabac_inline(c,state); } -av_unused static int get_cabac(CABACContext *c, uint8_t * const state){ +#if ARCH_PPC +/* PowerPC has no asm CABAC reader, so get_cabac_inline() is the whole entropy + * decoder -- and GCC refuses to inline it here: it emits a real out-of-line + * get_cabac and calls it from every bin site in h264_cabac.o. Each bin then + * pays a call/return, a full PIC prologue to re-find ff_h264_cabac_tables, and + * a reload+store of the low/range state that CABAC_ON_STACK went out of its + * way to keep in a local. Forcing the inline is bit-exact by construction. + * From PowerVLC (github.com/Olsro/powervlc, contrib/src/ffmpeg): measured + * +3.5% on a 720p High 4.8 Mbit/s decode on a 1.42 GHz 7447A. */ +#define av_cabac_get_inline av_always_inline +#else +/* Elsewhere the compiler's own choice is either right or irrelevant (x86, + * ARM, AArch64 and MIPS override get_cabac_inline with asm). */ +#define av_cabac_get_inline +#endif + +av_unused static av_cabac_get_inline int get_cabac(CABACContext *c, uint8_t * const state){ return get_cabac_inline(c,state); } -- 2.43.0