* Context Adaptive Binary Arithmetic Coder.
*/
+#ifndef CABAC_H
+#define CABAC_H
+
+#include "bitstream.h"
//#undef NDEBUG
#include <assert.h>
+#ifdef ARCH_X86
+#include "x86_cpu.h"
+#endif
#define CABAC_BITS 16
#define CABAC_MASK ((1<<CABAC_BITS)-1)
#define BRANCHLESS_CABAC_DECODER 1
-#define CMOV_IS_FAST 1
+//#define ARCH_X86_DISABLED 1
typedef struct CABACContext{
int low;
}CABACContext;
extern uint8_t ff_h264_mlps_state[4*64];
-extern uint8_t ff_h264_lps_range[4][2*64]; ///< rangeTabLPS
+extern uint8_t ff_h264_lps_range[4*2*64]; ///< rangeTabLPS
extern uint8_t ff_h264_mps_state[2*64]; ///< transIdxMPS
extern uint8_t ff_h264_lps_state[2*64]; ///< transIdxLPS
extern const uint8_t ff_h264_norm_shift[512];
refill(c);
}
-static int always_inline get_cabac_inline(CABACContext *c, uint8_t * const state){
+static av_always_inline int get_cabac_inline(CABACContext *c, uint8_t * const state){
//FIXME gcc generates duplicate load/stores for c->low and c->range
-#if defined(ARCH_X86) && !defined(PIC)
- int bit;
-
#define LOW "0"
#define RANGE "4"
+#ifdef ARCH_X86_64
+#define BYTESTART "16"
+#define BYTE "24"
+#define BYTEEND "32"
+#else
#define BYTESTART "12"
#define BYTE "16"
#define BYTEEND "20"
+#endif
+#if defined(ARCH_X86) && defined(CONFIG_7REGS) && defined(HAVE_EBX_AVAILABLE) && !defined(BROKEN_RELOCATIONS)
+ int bit;
+
#ifndef BRANCHLESS_CABAC_DECODER
asm volatile(
- "movzbl (%1), %%eax \n\t"
+ "movzbl (%1), %0 \n\t"
"movl "RANGE "(%2), %%ebx \n\t"
"movl "RANGE "(%2), %%edx \n\t"
"andl $0xC0, %%ebx \n\t"
- "movzbl "MANGLE(ff_h264_lps_range)"(%%eax, %%ebx, 2), %%esi\n\t"
+ "movzbl "MANGLE(ff_h264_lps_range)"(%0, %%ebx, 2), %%esi\n\t"
"movl "LOW "(%2), %%ebx \n\t"
//eax:state ebx:low, edx:range, esi:RangeLPS
"subl %%esi, %%edx \n\t"
"shl %%cl, %%edx \n\t"
"shl %%cl, %%ebx \n\t"
#endif
- "movzbl "MANGLE(ff_h264_mps_state)"(%%eax), %%ecx \n\t"
+ "movzbl "MANGLE(ff_h264_mps_state)"(%0), %%ecx \n\t"
"movb %%cl, (%1) \n\t"
//eax:state ebx:low, edx:range, esi:RangeLPS
"test %%bx, %%bx \n\t"
" jnz 2f \n\t"
- "movl "BYTE "(%2), %%esi \n\t"
+ "mov "BYTE "(%2), %%"REG_S" \n\t"
"subl $0xFFFF, %%ebx \n\t"
- "movzwl (%%esi), %%ecx \n\t"
+ "movzwl (%%"REG_S"), %%ecx \n\t"
"bswap %%ecx \n\t"
"shrl $15, %%ecx \n\t"
- "addl $2, %%esi \n\t"
+ "add $2, %%"REG_S" \n\t"
"addl %%ecx, %%ebx \n\t"
- "movl %%esi, "BYTE "(%2) \n\t"
+ "mov %%"REG_S", "BYTE "(%2) \n\t"
"jmp 2f \n\t"
"1: \n\t"
//eax:state ebx:low, edx:range, esi:RangeLPS
"movzbl " MANGLE(ff_h264_norm_shift) "(%%esi), %%ecx \n\t"
"shll %%cl, %%ebx \n\t"
"shll %%cl, %%edx \n\t"
- "movzbl "MANGLE(ff_h264_lps_state)"(%%eax), %%ecx \n\t"
+ "movzbl "MANGLE(ff_h264_lps_state)"(%0), %%ecx \n\t"
"movb %%cl, (%1) \n\t"
- "addl $1, %%eax \n\t"
+ "add $1, %0 \n\t"
"test %%bx, %%bx \n\t"
" jnz 2f \n\t"
- "movl "BYTE "(%2), %%ecx \n\t"
- "movzwl (%%ecx), %%esi \n\t"
+ "mov "BYTE "(%2), %%"REG_c" \n\t"
+ "movzwl (%%"REG_c"), %%esi \n\t"
"bswap %%esi \n\t"
"shrl $15, %%esi \n\t"
"subl $0xFFFF, %%esi \n\t"
- "addl $2, %%ecx \n\t"
- "movl %%ecx, "BYTE "(%2) \n\t"
+ "add $2, %%"REG_c" \n\t"
+ "mov %%"REG_c", "BYTE "(%2) \n\t"
"leal -1(%%ebx), %%ecx \n\t"
"xorl %%ebx, %%ecx \n\t"
"movl %%ebx, "LOW "(%2) \n\t"
:"=&a"(bit) //FIXME this is fragile gcc either runs out of registers or misscompiles it (for example if "+a"(bit) or "+m"(*state) is used
:"r"(state), "r"(c)
- : "%ecx", "%ebx", "%edx", "%esi", "memory"
+ : "%"REG_c, "%ebx", "%edx", "%"REG_S, "memory"
);
bit&=1;
#else /* BRANCHLESS_CABAC_DECODER */
- asm volatile(
- "movzbl (%1), %%eax \n\t"
- "movl "RANGE "(%2), %%ebx \n\t"
- "movl "RANGE "(%2), %%edx \n\t"
- "andl $0xC0, %%ebx \n\t"
- "movzbl "MANGLE(ff_h264_lps_range)"(%%eax, %%ebx, 2), %%esi\n\t"
- "movl "LOW "(%2), %%ebx \n\t"
-//eax:state ebx:low, edx:range, esi:RangeLPS
- "subl %%esi, %%edx \n\t"
-#ifdef CMOV_IS_FAST
- "movl %%edx, %%ecx \n\t"
- "shl $17, %%edx \n\t"
- "cmpl %%ebx, %%edx \n\t"
- "cmova %%ecx, %%esi \n\t"
- "sbbl %%ecx, %%ecx \n\t"
- "andl %%ecx, %%edx \n\t"
- "subl %%edx, %%ebx \n\t"
- "xorl %%ecx, %%eax \n\t"
-#else /* CMOV_IS_FAST */
-FIXTHIS
- "movl %%edx, %%ecx \n\t"
- "subl %%ebx, %%edx \n\t"
- "sarl $31, %%edx \n\t" //lps_mask
- "subl %%ecx, %%esi \n\t" //RangeLPS - range
- "andl %%edx, %%esi \n\t" //(RangeLPS - range)&lps_mask
- "addl %%ecx, %%esi \n\t" //new range
- "andl %%edx, %%ecx \n\t"
- "subl %%ecx, %%ebx \n\t"
- "xorl %%edx, %%eax \n\t"
-#endif /* CMOV_IS_FAST */
-//eax:state ebx:low edx:mask esi:range
-//eax:bit ebx:low esi:range
+#if defined HAVE_FAST_CMOV
+#define BRANCHLESS_GET_CABAC_UPDATE(ret, cabac, statep, low, lowword, range, tmp, tmpbyte)\
+ "mov "tmp" , %%ecx \n\t"\
+ "shl $17 , "tmp" \n\t"\
+ "cmp "low" , "tmp" \n\t"\
+ "cmova %%ecx , "range" \n\t"\
+ "sbb %%ecx , %%ecx \n\t"\
+ "and %%ecx , "tmp" \n\t"\
+ "sub "tmp" , "low" \n\t"\
+ "xor %%ecx , "ret" \n\t"
+#else /* HAVE_FAST_CMOV */
+#define BRANCHLESS_GET_CABAC_UPDATE(ret, cabac, statep, low, lowword, range, tmp, tmpbyte)\
+ "mov "tmp" , %%ecx \n\t"\
+ "shl $17 , "tmp" \n\t"\
+ "sub "low" , "tmp" \n\t"\
+ "sar $31 , "tmp" \n\t" /*lps_mask*/\
+ "sub %%ecx , "range" \n\t" /*RangeLPS - range*/\
+ "and "tmp" , "range" \n\t" /*(RangeLPS - range)&lps_mask*/\
+ "add %%ecx , "range" \n\t" /*new range*/\
+ "shl $17 , %%ecx \n\t"\
+ "and "tmp" , %%ecx \n\t"\
+ "sub %%ecx , "low" \n\t"\
+ "xor "tmp" , "ret" \n\t"
+#endif /* HAVE_FAST_CMOV */
+
+
+#define BRANCHLESS_GET_CABAC(ret, cabac, statep, low, lowword, range, tmp, tmpbyte)\
+ "movzbl "statep" , "ret" \n\t"\
+ "mov "range" , "tmp" \n\t"\
+ "and $0xC0 , "range" \n\t"\
+ "movzbl "MANGLE(ff_h264_lps_range)"("ret", "range", 2), "range" \n\t"\
+ "sub "range" , "tmp" \n\t"\
+ BRANCHLESS_GET_CABAC_UPDATE(ret, cabac, statep, low, lowword, range, tmp, tmpbyte)\
+ "movzbl " MANGLE(ff_h264_norm_shift) "("range"), %%ecx \n\t"\
+ "shl %%cl , "range" \n\t"\
+ "movzbl "MANGLE(ff_h264_mlps_state)"+128("ret"), "tmp" \n\t"\
+ "mov "tmpbyte" , "statep" \n\t"\
+ "shl %%cl , "low" \n\t"\
+ "test "lowword" , "lowword" \n\t"\
+ " jnz 1f \n\t"\
+ "mov "BYTE"("cabac"), %%"REG_c" \n\t"\
+ "movzwl (%%"REG_c") , "tmp" \n\t"\
+ "bswap "tmp" \n\t"\
+ "shr $15 , "tmp" \n\t"\
+ "sub $0xFFFF , "tmp" \n\t"\
+ "add $2 , %%"REG_c" \n\t"\
+ "mov %%"REG_c" , "BYTE "("cabac") \n\t"\
+ "lea -1("low") , %%ecx \n\t"\
+ "xor "low" , %%ecx \n\t"\
+ "shr $15 , %%ecx \n\t"\
+ "movzbl " MANGLE(ff_h264_norm_shift) "(%%ecx), %%ecx \n\t"\
+ "neg %%ecx \n\t"\
+ "add $7 , %%ecx \n\t"\
+ "shl %%cl , "tmp" \n\t"\
+ "add "tmp" , "low" \n\t"\
+ "1: \n\t"
- "movzbl " MANGLE(ff_h264_norm_shift) "(%%esi), %%ecx \n\t"
- "shll %%cl, %%esi \n\t"
- "movzbl "MANGLE(ff_h264_mlps_state)"+128(%%eax), %%edx \n\t"
- "movb %%dl, (%1) \n\t"
+ asm volatile(
+ "movl "RANGE "(%2), %%esi \n\t"
+ "movl "LOW "(%2), %%ebx \n\t"
+ BRANCHLESS_GET_CABAC("%0", "%2", "(%1)", "%%ebx", "%%bx", "%%esi", "%%edx", "%%dl")
"movl %%esi, "RANGE "(%2) \n\t"
- "shll %%cl, %%ebx \n\t"
"movl %%ebx, "LOW "(%2) \n\t"
- "test %%bx, %%bx \n\t"
- " jnz 1f \n\t"
-
- "movl "BYTE "(%2), %%ecx \n\t"
- "movzwl (%%ecx), %%esi \n\t"
- "bswap %%esi \n\t"
- "shrl $15, %%esi \n\t"
- "subl $0xFFFF, %%esi \n\t"
- "addl $2, %%ecx \n\t"
- "movl %%ecx, "BYTE "(%2) \n\t"
-
- "leal -1(%%ebx), %%ecx \n\t"
- "xorl %%ebx, %%ecx \n\t"
- "shrl $15, %%ecx \n\t"
- "movzbl " MANGLE(ff_h264_norm_shift) "(%%ecx), %%ecx \n\t"
- "neg %%ecx \n\t"
- "add $7, %%ecx \n\t"
- "shll %%cl , %%esi \n\t"
- "addl %%esi, %%ebx \n\t"
- "movl %%ebx, "LOW "(%2) \n\t"
- "1: \n\t"
:"=&a"(bit)
:"r"(state), "r"(c)
- : "%ecx", "%ebx", "%edx", "%esi", "memory"
+ : "%"REG_c, "%ebx", "%edx", "%esi", "memory"
);
bit&=1;
#endif /* BRANCHLESS_CABAC_DECODER */
-#else /* ARCH_X86 */
+#else /* defined(ARCH_X86) && defined(CONFIG_7REGS) && defined(HAVE_EBX_AVAILABLE) && !defined(BROKEN_RELOCATIONS) */
int s = *state;
- int RangeLPS= ff_h264_lps_range[0][2*(c->range&0xC0) + s];
- int bit, lps_mask attribute_unused;
+ int RangeLPS= ff_h264_lps_range[2*(c->range&0xC0) + s];
+ int bit, lps_mask av_unused;
c->range -= RangeLPS;
#ifndef BRANCHLESS_CABAC_DECODER
- if(c->low < (c->range<<17)){
+ if(c->low < (c->range<<(CABAC_BITS+1))){
bit= s&1;
*state= ff_h264_mps_state[s];
renorm_cabac_decoder_once(c);
}else{
bit= ff_h264_norm_shift[RangeLPS];
- c->low -= (c->range<<17);
+ c->low -= (c->range<<(CABAC_BITS+1));
*state= ff_h264_lps_state[s];
c->range = RangeLPS<<bit;
c->low <<= bit;
bit= (s&1)^1;
- if(!(c->low & 0xFFFF)){
+ if(!(c->low & CABAC_MASK)){
refill2(c);
}
}
#else /* BRANCHLESS_CABAC_DECODER */
- lps_mask= ((c->range<<17) - c->low)>>31;
+ lps_mask= ((c->range<<(CABAC_BITS+1)) - c->low)>>31;
- c->low -= (c->range<<17) & lps_mask;
+ c->low -= (c->range<<(CABAC_BITS+1)) & lps_mask;
c->range += (RangeLPS - c->range) & lps_mask;
s^=lps_mask;
if(!(c->low & CABAC_MASK))
refill2(c);
#endif /* BRANCHLESS_CABAC_DECODER */
-#endif /* ARCH_X86 */
+#endif /* defined(ARCH_X86) && defined(CONFIG_7REGS) && defined(HAVE_EBX_AVAILABLE) && !defined(BROKEN_RELOCATIONS) */
return bit;
}
-static int __attribute((noinline)) get_cabac_noinline(CABACContext *c, uint8_t * const state){
+static int av_noinline get_cabac_noinline(CABACContext *c, uint8_t * const state){
return get_cabac_inline(c,state);
}
}
static int get_cabac_bypass(CABACContext *c){
+#if 0 //not faster
+ int bit;
+ asm volatile(
+ "movl "RANGE "(%1), %%ebx \n\t"
+ "movl "LOW "(%1), %%eax \n\t"
+ "shl $17, %%ebx \n\t"
+ "add %%eax, %%eax \n\t"
+ "sub %%ebx, %%eax \n\t"
+ "cdq \n\t"
+ "and %%edx, %%ebx \n\t"
+ "add %%ebx, %%eax \n\t"
+ "test %%ax, %%ax \n\t"
+ " jnz 1f \n\t"
+ "movl "BYTE "(%1), %%"REG_b" \n\t"
+ "subl $0xFFFF, %%eax \n\t"
+ "movzwl (%%"REG_b"), %%ecx \n\t"
+ "bswap %%ecx \n\t"
+ "shrl $15, %%ecx \n\t"
+ "addl $2, %%"REG_b" \n\t"
+ "addl %%ecx, %%eax \n\t"
+ "movl %%"REG_b", "BYTE "(%1) \n\t"
+ "1: \n\t"
+ "movl %%eax, "LOW "(%1) \n\t"
+
+ :"=&d"(bit)
+ :"r"(c)
+ : "%eax", "%"REG_b, "%ecx", "memory"
+ );
+ return bit+1;
+#else
int range;
c->low += c->low;
if(!(c->low & CABAC_MASK))
refill(c);
- range= c->range<<17;
+ range= c->range<<(CABAC_BITS+1);
if(c->low < range){
return 0;
}else{
c->low -= range;
return 1;
}
+#endif
+}
+
+
+static av_always_inline int get_cabac_bypass_sign(CABACContext *c, int val){
+#if defined(ARCH_X86) && !(defined(PIC) && defined(__GNUC__))
+ asm volatile(
+ "movl "RANGE "(%1), %%ebx \n\t"
+ "movl "LOW "(%1), %%eax \n\t"
+ "shl $17, %%ebx \n\t"
+ "add %%eax, %%eax \n\t"
+ "sub %%ebx, %%eax \n\t"
+ "cdq \n\t"
+ "and %%edx, %%ebx \n\t"
+ "add %%ebx, %%eax \n\t"
+ "xor %%edx, %%ecx \n\t"
+ "sub %%edx, %%ecx \n\t"
+ "test %%ax, %%ax \n\t"
+ " jnz 1f \n\t"
+ "mov "BYTE "(%1), %%"REG_b" \n\t"
+ "subl $0xFFFF, %%eax \n\t"
+ "movzwl (%%"REG_b"), %%edx \n\t"
+ "bswap %%edx \n\t"
+ "shrl $15, %%edx \n\t"
+ "add $2, %%"REG_b" \n\t"
+ "addl %%edx, %%eax \n\t"
+ "mov %%"REG_b", "BYTE "(%1) \n\t"
+ "1: \n\t"
+ "movl %%eax, "LOW "(%1) \n\t"
+
+ :"+c"(val)
+ :"r"(c)
+ : "%eax", "%"REG_b, "%edx", "memory"
+ );
+ return val;
+#else
+ int range, mask;
+ c->low += c->low;
+
+ if(!(c->low & CABAC_MASK))
+ refill(c);
+
+ range= c->range<<(CABAC_BITS+1);
+ c->low -= range;
+ mask= c->low >> 31;
+ range &= mask;
+ c->low += range;
+ return (val^mask)-mask;
+#endif
+}
+
+//FIXME the x86 code from this file should be moved into i386/h264 or cabac something.c/h (note ill kill you if you move my code away from under my fingers before iam finished with it!)
+//FIXME use some macros to avoid duplicatin get_cabac (cant be done yet as that would make optimization work hard)
+#if defined(ARCH_X86) && defined(CONFIG_7REGS) && defined(HAVE_EBX_AVAILABLE) && !defined(BROKEN_RELOCATIONS)
+static int decode_significance_x86(CABACContext *c, int max_coeff, uint8_t *significant_coeff_ctx_base, int *index){
+ void *end= significant_coeff_ctx_base + max_coeff - 1;
+ int minusstart= -(int)significant_coeff_ctx_base;
+ int minusindex= 4-(int)index;
+ int coeff_count;
+ asm volatile(
+ "movl "RANGE "(%3), %%esi \n\t"
+ "movl "LOW "(%3), %%ebx \n\t"
+
+ "2: \n\t"
+
+ BRANCHLESS_GET_CABAC("%%edx", "%3", "(%1)", "%%ebx", "%%bx", "%%esi", "%%eax", "%%al")
+
+ "test $1, %%edx \n\t"
+ " jz 3f \n\t"
+
+ BRANCHLESS_GET_CABAC("%%edx", "%3", "61(%1)", "%%ebx", "%%bx", "%%esi", "%%eax", "%%al")
+
+ "mov %2, %%"REG_a" \n\t"
+ "movl %4, %%ecx \n\t"
+ "add %1, %%"REG_c" \n\t"
+ "movl %%ecx, (%%"REG_a") \n\t"
+
+ "test $1, %%edx \n\t"
+ " jnz 4f \n\t"
+
+ "add $4, %%"REG_a" \n\t"
+ "mov %%"REG_a", %2 \n\t"
+
+ "3: \n\t"
+ "add $1, %1 \n\t"
+ "cmp %5, %1 \n\t"
+ " jb 2b \n\t"
+ "mov %2, %%"REG_a" \n\t"
+ "movl %4, %%ecx \n\t"
+ "add %1, %%"REG_c" \n\t"
+ "movl %%ecx, (%%"REG_a") \n\t"
+ "4: \n\t"
+ "add %6, %%eax \n\t"
+ "shr $2, %%eax \n\t"
+
+ "movl %%esi, "RANGE "(%3) \n\t"
+ "movl %%ebx, "LOW "(%3) \n\t"
+ :"=&a"(coeff_count), "+r"(significant_coeff_ctx_base), "+m"(index)\
+ :"r"(c), "m"(minusstart), "m"(end), "m"(minusindex)\
+ : "%"REG_c, "%ebx", "%edx", "%esi", "memory"\
+ );
+ return coeff_count;
+}
+
+static int decode_significance_8x8_x86(CABACContext *c, uint8_t *significant_coeff_ctx_base, int *index, uint8_t *sig_off){
+ int minusindex= 4-(int)index;
+ int coeff_count;
+ long last=0;
+ asm volatile(
+ "movl "RANGE "(%3), %%esi \n\t"
+ "movl "LOW "(%3), %%ebx \n\t"
+
+ "mov %1, %%"REG_D" \n\t"
+ "2: \n\t"
+
+ "mov %6, %%"REG_a" \n\t"
+ "movzbl (%%"REG_a", %%"REG_D"), %%edi \n\t"
+ "add %5, %%"REG_D" \n\t"
+
+ BRANCHLESS_GET_CABAC("%%edx", "%3", "(%%"REG_D")", "%%ebx", "%%bx", "%%esi", "%%eax", "%%al")
+
+ "mov %1, %%edi \n\t"
+ "test $1, %%edx \n\t"
+ " jz 3f \n\t"
+
+ "movzbl "MANGLE(last_coeff_flag_offset_8x8)"(%%edi), %%edi\n\t"
+ "add %5, %%"REG_D" \n\t"
+
+ BRANCHLESS_GET_CABAC("%%edx", "%3", "15(%%"REG_D")", "%%ebx", "%%bx", "%%esi", "%%eax", "%%al")
+
+ "mov %2, %%"REG_a" \n\t"
+ "mov %1, %%edi \n\t"
+ "movl %%edi, (%%"REG_a") \n\t"
+
+ "test $1, %%edx \n\t"
+ " jnz 4f \n\t"
+
+ "add $4, %%"REG_a" \n\t"
+ "mov %%"REG_a", %2 \n\t"
+
+ "3: \n\t"
+ "addl $1, %%edi \n\t"
+ "mov %%edi, %1 \n\t"
+ "cmpl $63, %%edi \n\t"
+ " jb 2b \n\t"
+ "mov %2, %%"REG_a" \n\t"
+ "movl %%edi, (%%"REG_a") \n\t"
+ "4: \n\t"
+ "addl %4, %%eax \n\t"
+ "shr $2, %%eax \n\t"
+
+ "movl %%esi, "RANGE "(%3) \n\t"
+ "movl %%ebx, "LOW "(%3) \n\t"
+ :"=&a"(coeff_count),"+m"(last), "+m"(index)\
+ :"r"(c), "m"(minusindex), "m"(significant_coeff_ctx_base), "m"(sig_off)\
+ : "%"REG_c, "%ebx", "%edx", "%esi", "%"REG_D, "memory"\
+ );
+ return coeff_count;
}
+#endif /* defined(ARCH_X86) && && defined(CONFIG_7REGS) && defined(HAVE_EBX_AVAILABLE) && !defined(BROKEN_RELOCATIONS) */
/**
*
*/
static int get_cabac_terminate(CABACContext *c){
c->range -= 2;
- if(c->low < c->range<<17){
+ if(c->low < c->range<<(CABAC_BITS+1)){
renorm_cabac_decoder_once(c);
return 0;
}else{
}else
return i;
}
+
+#endif /* CABAC_H */