FFmpeg
cabac.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #ifndef AVCODEC_X86_CABAC_H
22 #define AVCODEC_X86_CABAC_H
23 
24 #include <stddef.h>
25 
26 #include "libavcodec/cabac.h"
27 #include "libavutil/attributes.h"
28 #include "libavutil/macros.h"
29 #include "libavutil/x86/asm.h"
30 #include "config.h"
31 
32 #if (defined(__i386) && defined(__clang__) && (__clang_major__<2 || (__clang_major__==2 && __clang_minor__<10)))\
33  || ( !defined(__clang__) && defined(__llvm__) && __GNUC__==4 && __GNUC_MINOR__==2 && __GNUC_PATCHLEVEL__<=1)\
34  || (defined(__INTEL_COMPILER) && defined(_MSC_VER))
35 # define BROKEN_COMPILER 1
36 #else
37 # define BROKEN_COMPILER 0
38 #endif
39 
40 #if HAVE_INLINE_ASM
41 
42 #ifndef UNCHECKED_BITSTREAM_READER
43 #define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER
44 #endif
45 
46 #if UNCHECKED_BITSTREAM_READER
47 #define END_CHECK(end) ""
48 #else
49 #define END_CHECK(end) \
50  "cmp "end" , %%"FF_REG_c" \n\t"\
51  "jge 1f \n\t"
52 #endif
53 
54 #ifdef BROKEN_RELOCATIONS
55 #define TABLES_ARG , "r"(tables)
56 
57 #if HAVE_FAST_CMOV
58 #define BRANCHLESS_GET_CABAC_UPDATE(ret, retq, low, range, tmp) \
59  "cmp "low" , "tmp" \n\t"\
60  "cmova %%ecx , "range" \n\t"\
61  "sbb %%rcx , %%rcx \n\t"\
62  "and %%ecx , "tmp" \n\t"\
63  "xor %%rcx , "retq" \n\t"\
64  "sub "tmp" , "low" \n\t"
65 #else /* HAVE_FAST_CMOV */
66 #define BRANCHLESS_GET_CABAC_UPDATE(ret, retq, low, range, tmp) \
67 /* P4 Prescott has crappy cmov,sbb,64-bit shift so avoid them */ \
68  "sub "low" , "tmp" \n\t"\
69  "sar $31 , "tmp" \n\t"\
70  "sub %%ecx , "range" \n\t"\
71  "and "tmp" , "range" \n\t"\
72  "add %%ecx , "range" \n\t"\
73  "shl $17 , %%ecx \n\t"\
74  "and "tmp" , %%ecx \n\t"\
75  "sub %%ecx , "low" \n\t"\
76  "xor "tmp" , "ret" \n\t"\
77  "movslq "ret" , "retq" \n\t"
78 #endif /* HAVE_FAST_CMOV */
79 
80 #ifdef __LZCNT__
81 /* renormalisation shift = lzcnt(range) - 23, refill shift = tzcnt(low) - 16 */
82 #define BRANCHLESS_GET_CABAC_RENORM(range, rangeq, norm_off, tables) \
83  "lzcnt "range" , %%ecx \n\t"\
84  "sub $23 , %%ecx \n\t"
85 #define BRANCHLESS_GET_CABAC_REFILL(low, tmp, norm_off, tables) \
86  "movzwl (%%"FF_REG_c") , "tmp" \n\t"\
87  "tzcnt "low" , %%ecx \n\t"\
88  "bswap "tmp" \n\t"\
89  "shr $15 , "tmp" \n\t"\
90  "sub $16 , %%ecx \n\t"\
91  "sub $0xFFFF , "tmp" \n\t"\
92  "shl %%cl , "tmp" \n\t"\
93  "add "tmp" , "low" \n\t"
94 #else /* __LZCNT__ */
95 #define BRANCHLESS_GET_CABAC_RENORM(range, rangeq, norm_off, tables) \
96  "movzbl "norm_off"("tables", "rangeq"), %%ecx \n\t"
97 #define BRANCHLESS_GET_CABAC_REFILL(low, tmp, norm_off, tables) \
98  "movzwl (%%"FF_REG_c") , "tmp" \n\t"\
99  "lea -1("low") , %%ecx \n\t"\
100  "xor "low" , %%ecx \n\t"\
101  "shr $15 , %%ecx \n\t"\
102  "bswap "tmp" \n\t"\
103  "shr $15 , "tmp" \n\t"\
104  "movzbl "norm_off"("tables", %%rcx), %%ecx \n\t"\
105  "sub $0xFFFF , "tmp" \n\t"\
106  "neg %%ecx \n\t"\
107  "add $7 , %%ecx \n\t"\
108  "shl %%cl , "tmp" \n\t"\
109  "add "tmp" , "low" \n\t"
110 #endif /* __LZCNT__ */
111 
112 #define BRANCHLESS_GET_CABAC(ret, retq, statep, low, lowword, range, rangeq, tmp, tmpbyte, byte, end, norm_off, lps_off, mlps_off, tables) \
113  "movzbl "statep" , "ret" \n\t"\
114  "mov "range" , "tmp" \n\t"\
115  "and $0xC0 , "range" \n\t"\
116  "lea ("ret", "range", 2), %%ecx \n\t"\
117  "movzbl "lps_off"("tables", %%rcx), "range" \n\t"\
118  "sub "range" , "tmp" \n\t"\
119  "mov "tmp" , %%ecx \n\t"\
120  "shl $17 , "tmp" \n\t"\
121  BRANCHLESS_GET_CABAC_UPDATE(ret, retq, low, range, tmp) \
122  BRANCHLESS_GET_CABAC_RENORM(range, rangeq, norm_off, tables) \
123  "shl %%cl , "range" \n\t"\
124  "movzbl "mlps_off"+128("tables", "retq"), "tmp" \n\t"\
125  "shl %%cl , "low" \n\t"\
126  "mov "tmpbyte" , "statep" \n\t"\
127  "test "lowword" , "lowword" \n\t"\
128  "jnz 2f \n\t"\
129  "mov "byte" , %%"FF_REG_c" \n\t"\
130  END_CHECK(end)\
131  "add"FF_OPSIZE" $2 , "byte" \n\t"\
132  "1: \n\t"\
133  BRANCHLESS_GET_CABAC_REFILL(low, tmp, norm_off, tables) \
134  "2: \n\t"
135 
136 #else /* BROKEN_RELOCATIONS */
137 #define TABLES_ARG NAMED_CONSTRAINTS_ARRAY_ADD(ff_h264_cabac_tables)
138 #define RIP_ARG
139 
140 #if HAVE_FAST_CMOV
141 #define BRANCHLESS_GET_CABAC_UPDATE(ret, low, range, tmp)\
142  "mov "tmp" , %%ecx \n\t"\
143  "shl $17 , "tmp" \n\t"\
144  "cmp "low" , "tmp" \n\t"\
145  "cmova %%ecx , "range" \n\t"\
146  "sbb %%ecx , %%ecx \n\t"\
147  "and %%ecx , "tmp" \n\t"\
148  "xor %%ecx , "ret" \n\t"\
149  "sub "tmp" , "low" \n\t"
150 #else /* HAVE_FAST_CMOV */
151 #define BRANCHLESS_GET_CABAC_UPDATE(ret, low, range, tmp)\
152  "mov "tmp" , %%ecx \n\t"\
153  "shl $17 , "tmp" \n\t"\
154  "sub "low" , "tmp" \n\t"\
155  "sar $31 , "tmp" \n\t" /*lps_mask*/\
156  "sub %%ecx , "range" \n\t" /*RangeLPS - range*/\
157  "and "tmp" , "range" \n\t" /*(RangeLPS - range)&lps_mask*/\
158  "add %%ecx , "range" \n\t" /*new range*/\
159  "shl $17 , %%ecx \n\t"\
160  "and "tmp" , %%ecx \n\t"\
161  "sub %%ecx , "low" \n\t"\
162  "xor "tmp" , "ret" \n\t"
163 #endif /* HAVE_FAST_CMOV */
164 
165 #ifdef __LZCNT__
166 #define BRANCHLESS_GET_CABAC_RENORM(range, rangeq, norm_off, tables) \
167  "lzcnt "range" , %%ecx \n\t"\
168  "sub $23 , %%ecx \n\t"
169 #define BRANCHLESS_GET_CABAC_REFILL(low, tmp, norm_off, tables) \
170  "movzwl (%%"FF_REG_c") , "tmp" \n\t"\
171  "tzcnt "low" , %%ecx \n\t"\
172  "bswap "tmp" \n\t"\
173  "shr $15 , "tmp" \n\t"\
174  "sub $16 , %%ecx \n\t"\
175  "sub $0xFFFF , "tmp" \n\t"\
176  "shl %%cl , "tmp" \n\t"\
177  "add "tmp" , "low" \n\t"
178 #else /* __LZCNT__ */
179 #define BRANCHLESS_GET_CABAC_RENORM(range, rangeq, norm_off, tables) \
180  "movzbl "MANGLE(ff_h264_cabac_tables)"+"norm_off"("range"), %%ecx \n\t"
181 #define BRANCHLESS_GET_CABAC_REFILL(low, tmp, norm_off, tables) \
182  "movzwl (%%"FF_REG_c") , "tmp" \n\t"\
183  "lea -1("low") , %%ecx \n\t"\
184  "xor "low" , %%ecx \n\t"\
185  "shr $15 , %%ecx \n\t"\
186  "bswap "tmp" \n\t"\
187  "shr $15 , "tmp" \n\t"\
188  "movzbl "MANGLE(ff_h264_cabac_tables)"+"norm_off"(%%ecx), %%ecx \n\t"\
189  "sub $0xFFFF , "tmp" \n\t"\
190  "neg %%ecx \n\t"\
191  "add $7 , %%ecx \n\t"\
192  "shl %%cl , "tmp" \n\t"\
193  "add "tmp" , "low" \n\t"
194 #endif /* __LZCNT__ */
195 
196 #define BRANCHLESS_GET_CABAC(ret, retq, statep, low, lowword, range, rangeq, tmp, tmpbyte, byte, end, norm_off, lps_off, mlps_off, tables) \
197  "movzbl "statep" , "ret" \n\t"\
198  "mov "range" , "tmp" \n\t"\
199  "and $0xC0 , "range" \n\t"\
200  "movzbl "MANGLE(ff_h264_cabac_tables)"+"lps_off"("ret", "range", 2), "range" \n\t"\
201  "sub "range" , "tmp" \n\t"\
202  BRANCHLESS_GET_CABAC_UPDATE(ret, low, range, tmp) \
203  BRANCHLESS_GET_CABAC_RENORM(range, rangeq, norm_off, tables) \
204  "shl %%cl , "range" \n\t"\
205  "movzbl "MANGLE(ff_h264_cabac_tables)"+"mlps_off"+128("ret"), "tmp" \n\t"\
206  "shl %%cl , "low" \n\t"\
207  "mov "tmpbyte" , "statep" \n\t"\
208  "test "lowword" , "lowword" \n\t"\
209  " jnz 2f \n\t"\
210  "mov "byte" , %%"FF_REG_c" \n\t"\
211  END_CHECK(end)\
212  "add"FF_OPSIZE" $2 , "byte" \n\t"\
213  "1: \n\t"\
214  BRANCHLESS_GET_CABAC_REFILL(low, tmp, norm_off, tables) \
215  "2: \n\t"
216 
217 #endif /* BROKEN_RELOCATIONS */
218 
219 #if HAVE_7REGS && !BROKEN_COMPILER
220 #define get_cabac_inline get_cabac_inline_x86
221 static
222 #if ARCH_X86_32
224 #else
226 #endif
227 int get_cabac_inline_x86(CABACContext *c, uint8_t *const state)
228 {
229  int bit, tmp;
230 #ifdef BROKEN_RELOCATIONS
231  void *tables;
232 
233  __asm__ volatile(
234  "lea "MANGLE(ff_h264_cabac_tables)", %0 \n\t"
235  : "=&r"(tables)
237  );
238 #endif
239 
240  __asm__ volatile(
241  BRANCHLESS_GET_CABAC("%0", "%q0", "(%4)", "%1", "%w1",
242  "%2", "%q2", "%3", "%b3",
243  "%c6(%5)", "%c7(%5)",
247  "%8")
248  : "=&r"(bit), "=&r"(c->low), "=&r"(c->range), "=&q"(tmp)
249  : "r"(state), "r"(c),
250  "i"(offsetof(CABACContext, bytestream)),
251  "i"(offsetof(CABACContext, bytestream_end))
252  TABLES_ARG
253  ,"1"(c->low), "2"(c->range)
254  : "%"FF_REG_c, "memory"
255  );
256  return bit & 1;
257 }
258 #endif /* HAVE_7REGS && !BROKEN_COMPILER */
259 
260 #if !BROKEN_COMPILER
261 #define get_cabac_bypass_sign get_cabac_bypass_sign_x86
262 static av_always_inline int get_cabac_bypass_sign_x86(CABACContext *c, int val)
263 {
264  x86_reg tmp;
265  __asm__ volatile(
266  "movl %c6(%2), %k1 \n\t"
267  "movl %c3(%2), %%eax \n\t"
268  "shl $17, %k1 \n\t"
269  "add %%eax, %%eax \n\t"
270  "sub %k1, %%eax \n\t"
271  "cdq \n\t"
272  "and %%edx, %k1 \n\t"
273  "add %k1, %%eax \n\t"
274  "xor %%edx, %%ecx \n\t"
275  "sub %%edx, %%ecx \n\t"
276  "test %%ax, %%ax \n\t"
277  "jnz 1f \n\t"
278  "mov %c4(%2), %1 \n\t"
279  "subl $0xFFFF, %%eax \n\t"
280  "movzwl (%1), %%edx \n\t"
281  "bswap %%edx \n\t"
282  "shrl $15, %%edx \n\t"
283 #if UNCHECKED_BITSTREAM_READER
284  "add $2, %1 \n\t"
285  "addl %%edx, %%eax \n\t"
286  "mov %1, %c4(%2) \n\t"
287 #else
288  "addl %%edx, %%eax \n\t"
289  "cmp %c5(%2), %1 \n\t"
290  "jge 1f \n\t"
291  "add"FF_OPSIZE" $2, %c4(%2) \n\t"
292 #endif
293  "1: \n\t"
294  "movl %%eax, %c3(%2) \n\t"
295 
296  : "+c"(val), "=&r"(tmp)
297  : "r"(c),
298  "i"(offsetof(CABACContext, low)),
299  "i"(offsetof(CABACContext, bytestream)),
300  "i"(offsetof(CABACContext, bytestream_end)),
301  "i"(offsetof(CABACContext, range))
302  : "%eax", "%edx", "memory"
303  );
304  return val;
305 }
306 
307 #define get_cabac_bypass get_cabac_bypass_x86
308 static av_always_inline int get_cabac_bypass_x86(CABACContext *c)
309 {
310  x86_reg tmp;
311  int res;
312  __asm__ volatile(
313  "movl %c6(%2), %k1 \n\t"
314  "movl %c3(%2), %%eax \n\t"
315  "shl $17, %k1 \n\t"
316  "add %%eax, %%eax \n\t"
317  "sub %k1, %%eax \n\t"
318  "cdq \n\t"
319  "and %%edx, %k1 \n\t"
320  "add %k1, %%eax \n\t"
321  "inc %%edx \n\t"
322  "test %%ax, %%ax \n\t"
323  "jnz 1f \n\t"
324  "mov %c4(%2), %1 \n\t"
325  "subl $0xFFFF, %%eax \n\t"
326  "movzwl (%1), %%ecx \n\t"
327  "bswap %%ecx \n\t"
328  "shrl $15, %%ecx \n\t"
329  "addl %%ecx, %%eax \n\t"
330  "cmp %c5(%2), %1 \n\t"
331  "jge 1f \n\t"
332  "add"FF_OPSIZE" $2, %c4(%2) \n\t"
333  "1: \n\t"
334  "movl %%eax, %c3(%2) \n\t"
335 
336  : "=&d"(res), "=&r"(tmp)
337  : "r"(c),
338  "i"(offsetof(CABACContext, low)),
339  "i"(offsetof(CABACContext, bytestream)),
340  "i"(offsetof(CABACContext, bytestream_end)),
341  "i"(offsetof(CABACContext, range))
342  : "%eax", "%ecx", "memory"
343  );
344  return res;
345 }
346 #endif /* !BROKEN_COMPILER */
347 
348 #endif /* HAVE_INLINE_ASM */
349 #endif /* AVCODEC_X86_CABAC_H */
cabac.h
x86_reg
int x86_reg
Definition: asm.h:71
bit
#define bit(string, value)
Definition: cbs_mpeg2.c:56
av_always_inline
#define av_always_inline
Definition: attributes.h:76
macros.h
NAMED_CONSTRAINTS_ARRAY
#define NAMED_CONSTRAINTS_ARRAY(...)
Definition: asm.h:150
MANGLE
#define MANGLE(a)
Definition: asm.h:126
tables
Writing a table generator This documentation is preliminary Parts of the API are not good and should be changed Basic concepts A table generator consists of two *_tablegen c and *_tablegen h The h file will provide the variable declarations and initialization code for the tables
Definition: tablegen.txt:10
val
static double val(void *priv, double ch)
Definition: aeval.c:77
ff_h264_cabac_tables
const uint8_t ff_h264_cabac_tables[512+4 *2 *64+4 *64+63]
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
asm.h
attributes.h
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
H264_LPS_RANGE_OFFSET
#define H264_LPS_RANGE_OFFSET
Definition: cabac.h:34
range
enum AVColorRange range
Definition: mediacodec_wrapper.c:2594
AV_STRINGIFY
#define AV_STRINGIFY(s)
Definition: macros.h:66
H264_NORM_SHIFT_OFFSET
#define H264_NORM_SHIFT_OFFSET
Definition: cabac.h:33
state
static struct @600 state
__asm__
__asm__(".macro parse_r var r\n\t" "\\var = -1\n\t" _IFC_REG(0) _IFC_REG(1) _IFC_REG(2) _IFC_REG(3) _IFC_REG(4) _IFC_REG(5) _IFC_REG(6) _IFC_REG(7) _IFC_REG(8) _IFC_REG(9) _IFC_REG(10) _IFC_REG(11) _IFC_REG(12) _IFC_REG(13) _IFC_REG(14) _IFC_REG(15) _IFC_REG(16) _IFC_REG(17) _IFC_REG(18) _IFC_REG(19) _IFC_REG(20) _IFC_REG(21) _IFC_REG(22) _IFC_REG(23) _IFC_REG(24) _IFC_REG(25) _IFC_REG(26) _IFC_REG(27) _IFC_REG(28) _IFC_REG(29) _IFC_REG(30) _IFC_REG(31) ".iflt \\var\n\t" ".error \"Unable to parse register name \\r\"\n\t" ".endif\n\t" ".endm")
av_noinline
#define av_noinline
Definition: attributes.h:101
H264_MLPS_STATE_OFFSET
#define H264_MLPS_STATE_OFFSET
Definition: cabac.h:35
CABACContext
Definition: cabac.h:41