1848b8605Smrg/**************************************************************************
2848b8605Smrg *
3848b8605Smrg * Copyright 2011 Christian König.
4848b8605Smrg * All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the
8848b8605Smrg * "Software"), to deal in the Software without restriction, including
9848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish,
10848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to
11848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to
12848b8605Smrg * the following conditions:
13848b8605Smrg *
14848b8605Smrg * The above copyright notice and this permission notice (including the
15848b8605Smrg * next paragraph) shall be included in all copies or substantial portions
16848b8605Smrg * of the Software.
17848b8605Smrg *
18848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21848b8605Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25848b8605Smrg *
26848b8605Smrg **************************************************************************/
27848b8605Smrg
28848b8605Smrg/*
29848b8605Smrg * Functions for fast bitwise access to multiple probably unaligned input buffers
30848b8605Smrg */
31848b8605Smrg
32848b8605Smrg#ifndef vl_vlc_h
33848b8605Smrg#define vl_vlc_h
34848b8605Smrg
35848b8605Smrg#include "pipe/p_compiler.h"
36848b8605Smrg
37848b8605Smrg#include "util/u_math.h"
38848b8605Smrg#include "util/u_pointer.h"
39848b8605Smrg#include "util/u_debug.h"
40848b8605Smrg
41848b8605Smrgstruct vl_vlc
42848b8605Smrg{
43848b8605Smrg   uint64_t buffer;
44848b8605Smrg   signed invalid_bits;
45848b8605Smrg   const uint8_t *data;
46848b8605Smrg   const uint8_t *end;
47848b8605Smrg
48848b8605Smrg   const void *const *inputs;
49848b8605Smrg   const unsigned    *sizes;
50848b8605Smrg   unsigned          bytes_left;
51848b8605Smrg};
52848b8605Smrg
53848b8605Smrgstruct vl_vlc_entry
54848b8605Smrg{
55848b8605Smrg   int8_t length;
56848b8605Smrg   int8_t value;
57848b8605Smrg};
58848b8605Smrg
59848b8605Smrgstruct vl_vlc_compressed
60848b8605Smrg{
61848b8605Smrg   uint16_t bitcode;
62848b8605Smrg   struct vl_vlc_entry entry;
63848b8605Smrg};
64848b8605Smrg
65848b8605Smrg/**
66848b8605Smrg * initalize and decompress a lookup table
67848b8605Smrg */
68b8e80941Smrgstatic inline void
69848b8605Smrgvl_vlc_init_table(struct vl_vlc_entry *dst, unsigned dst_size, const struct vl_vlc_compressed *src, unsigned src_size)
70848b8605Smrg{
71848b8605Smrg   unsigned i, bits = util_logbase2(dst_size);
72848b8605Smrg
73848b8605Smrg   assert(dst && dst_size);
74848b8605Smrg   assert(src && src_size);
75848b8605Smrg
76848b8605Smrg   for (i=0;i<dst_size;++i) {
77848b8605Smrg      dst[i].length = 0;
78848b8605Smrg      dst[i].value = 0;
79848b8605Smrg   }
80848b8605Smrg
81848b8605Smrg   for(; src_size > 0; --src_size, ++src) {
82b8e80941Smrg      for(i = 0; i < (1u << (bits - src->entry.length)); ++i)
83848b8605Smrg         dst[src->bitcode >> (16 - bits) | i] = src->entry;
84848b8605Smrg   }
85848b8605Smrg}
86848b8605Smrg
87848b8605Smrg/**
88848b8605Smrg * switch over to next input buffer
89848b8605Smrg */
90b8e80941Smrgstatic inline void
91848b8605Smrgvl_vlc_next_input(struct vl_vlc *vlc)
92848b8605Smrg{
93848b8605Smrg   unsigned len = vlc->sizes[0];
94848b8605Smrg
95848b8605Smrg   assert(vlc);
96848b8605Smrg   assert(vlc->bytes_left);
97848b8605Smrg
98848b8605Smrg   if (len < vlc->bytes_left)
99848b8605Smrg      vlc->bytes_left -= len;
100848b8605Smrg   else {
101848b8605Smrg      len = vlc->bytes_left;
102848b8605Smrg      vlc->bytes_left = 0;
103848b8605Smrg   }
104848b8605Smrg
105848b8605Smrg   vlc->data = vlc->inputs[0];
106848b8605Smrg   vlc->end = vlc->data + len;
107848b8605Smrg
108848b8605Smrg   ++vlc->inputs;
109848b8605Smrg   ++vlc->sizes;
110848b8605Smrg}
111848b8605Smrg
112848b8605Smrg/**
113848b8605Smrg * align the data pointer to the next dword
114848b8605Smrg */
115b8e80941Smrgstatic inline void
116848b8605Smrgvl_vlc_align_data_ptr(struct vl_vlc *vlc)
117848b8605Smrg{
118848b8605Smrg   /* align the data pointer */
119848b8605Smrg   while (vlc->data != vlc->end && pointer_to_uintptr(vlc->data) & 3) {
120848b8605Smrg      vlc->buffer |= (uint64_t)*vlc->data << (24 + vlc->invalid_bits);
121848b8605Smrg      ++vlc->data;
122848b8605Smrg      vlc->invalid_bits -= 8;
123848b8605Smrg   }
124848b8605Smrg}
125848b8605Smrg
126848b8605Smrg/**
127848b8605Smrg * fill the bit buffer, so that at least 32 bits are valid
128848b8605Smrg */
129b8e80941Smrgstatic inline void
130848b8605Smrgvl_vlc_fillbits(struct vl_vlc *vlc)
131848b8605Smrg{
132848b8605Smrg   assert(vlc);
133848b8605Smrg
134848b8605Smrg   /* as long as the buffer needs to be filled */
135848b8605Smrg   while (vlc->invalid_bits > 0) {
136848b8605Smrg      unsigned bytes_left = vlc->end - vlc->data;
137848b8605Smrg
138848b8605Smrg      /* if this input is depleted */
139848b8605Smrg      if (bytes_left == 0) {
140848b8605Smrg
141848b8605Smrg         if (vlc->bytes_left) {
142848b8605Smrg            /* go on to next input */
143848b8605Smrg            vl_vlc_next_input(vlc);
144848b8605Smrg            vl_vlc_align_data_ptr(vlc);
145848b8605Smrg         } else
146848b8605Smrg            /* or give up since we don't have anymore inputs */
147848b8605Smrg            return;
148848b8605Smrg
149848b8605Smrg      } else if (bytes_left >= 4) {
150848b8605Smrg
151848b8605Smrg         /* enough bytes in buffer, read in a whole dword */
152848b8605Smrg         uint64_t value = *(const uint32_t*)vlc->data;
153848b8605Smrg
154848b8605Smrg#ifndef PIPE_ARCH_BIG_ENDIAN
155848b8605Smrg         value = util_bswap32(value);
156848b8605Smrg#endif
157848b8605Smrg
158848b8605Smrg         vlc->buffer |= value << vlc->invalid_bits;
159848b8605Smrg         vlc->data += 4;
160848b8605Smrg         vlc->invalid_bits -= 32;
161848b8605Smrg
162848b8605Smrg         /* buffer is now definitely filled up avoid the loop test */
163848b8605Smrg         break;
164848b8605Smrg
165848b8605Smrg      } else while (vlc->data < vlc->end) {
166848b8605Smrg
167848b8605Smrg         /* not enough bytes left in buffer, read single bytes */
168848b8605Smrg         vlc->buffer |= (uint64_t)*vlc->data << (24 + vlc->invalid_bits);
169848b8605Smrg         ++vlc->data;
170848b8605Smrg         vlc->invalid_bits -= 8;
171848b8605Smrg      }
172848b8605Smrg   }
173848b8605Smrg}
174848b8605Smrg
175848b8605Smrg/**
176848b8605Smrg * initialize vlc structure and start reading from first input buffer
177848b8605Smrg */
178b8e80941Smrgstatic inline void
179848b8605Smrgvl_vlc_init(struct vl_vlc *vlc, unsigned num_inputs,
180848b8605Smrg            const void *const *inputs, const unsigned *sizes)
181848b8605Smrg{
182848b8605Smrg   unsigned i;
183848b8605Smrg
184848b8605Smrg   assert(vlc);
185848b8605Smrg   assert(num_inputs);
186848b8605Smrg
187848b8605Smrg   vlc->buffer = 0;
188848b8605Smrg   vlc->invalid_bits = 32;
189848b8605Smrg   vlc->inputs = inputs;
190848b8605Smrg   vlc->sizes = sizes;
191848b8605Smrg   vlc->bytes_left = 0;
192848b8605Smrg
193848b8605Smrg   for (i = 0; i < num_inputs; ++i)
194848b8605Smrg      vlc->bytes_left += sizes[i];
195848b8605Smrg
196848b8605Smrg   if (vlc->bytes_left) {
197848b8605Smrg      vl_vlc_next_input(vlc);
198848b8605Smrg      vl_vlc_align_data_ptr(vlc);
199848b8605Smrg      vl_vlc_fillbits(vlc);
200848b8605Smrg   }
201848b8605Smrg}
202848b8605Smrg
203848b8605Smrg/**
204848b8605Smrg * number of bits still valid in bit buffer
205848b8605Smrg */
206b8e80941Smrgstatic inline unsigned
207848b8605Smrgvl_vlc_valid_bits(struct vl_vlc *vlc)
208848b8605Smrg{
209848b8605Smrg   return 32 - vlc->invalid_bits;
210848b8605Smrg}
211848b8605Smrg
212848b8605Smrg/**
213848b8605Smrg * number of bits left over all inbut buffers
214848b8605Smrg */
215b8e80941Smrgstatic inline unsigned
216848b8605Smrgvl_vlc_bits_left(struct vl_vlc *vlc)
217848b8605Smrg{
218848b8605Smrg   signed bytes_left = vlc->end - vlc->data;
219848b8605Smrg   bytes_left += vlc->bytes_left;
220848b8605Smrg   return bytes_left * 8 + vl_vlc_valid_bits(vlc);
221848b8605Smrg}
222848b8605Smrg
223848b8605Smrg/**
224848b8605Smrg * get num_bits from bit buffer without removing them
225848b8605Smrg */
226b8e80941Smrgstatic inline unsigned
227848b8605Smrgvl_vlc_peekbits(struct vl_vlc *vlc, unsigned num_bits)
228848b8605Smrg{
229848b8605Smrg   assert(vl_vlc_valid_bits(vlc) >= num_bits || vlc->data >= vlc->end);
230848b8605Smrg   return vlc->buffer >> (64 - num_bits);
231848b8605Smrg}
232848b8605Smrg
233848b8605Smrg/**
234848b8605Smrg * remove num_bits from bit buffer
235848b8605Smrg */
236b8e80941Smrgstatic inline void
237848b8605Smrgvl_vlc_eatbits(struct vl_vlc *vlc, unsigned num_bits)
238848b8605Smrg{
239848b8605Smrg   assert(vl_vlc_valid_bits(vlc) >= num_bits);
240848b8605Smrg
241848b8605Smrg   vlc->buffer <<= num_bits;
242848b8605Smrg   vlc->invalid_bits += num_bits;
243848b8605Smrg}
244848b8605Smrg
245848b8605Smrg/**
246848b8605Smrg * get num_bits from bit buffer with removing them
247848b8605Smrg */
248b8e80941Smrgstatic inline unsigned
249848b8605Smrgvl_vlc_get_uimsbf(struct vl_vlc *vlc, unsigned num_bits)
250848b8605Smrg{
251848b8605Smrg   unsigned value;
252848b8605Smrg
253848b8605Smrg   assert(vl_vlc_valid_bits(vlc) >= num_bits);
254848b8605Smrg
255848b8605Smrg   value = vlc->buffer >> (64 - num_bits);
256848b8605Smrg   vl_vlc_eatbits(vlc, num_bits);
257848b8605Smrg
258848b8605Smrg   return value;
259848b8605Smrg}
260848b8605Smrg
261848b8605Smrg/**
262848b8605Smrg * treat num_bits as signed value and remove them from bit buffer
263848b8605Smrg */
264b8e80941Smrgstatic inline signed
265848b8605Smrgvl_vlc_get_simsbf(struct vl_vlc *vlc, unsigned num_bits)
266848b8605Smrg{
267848b8605Smrg   signed value;
268848b8605Smrg
269848b8605Smrg   assert(vl_vlc_valid_bits(vlc) >= num_bits);
270848b8605Smrg
271848b8605Smrg   value = ((int64_t)vlc->buffer) >> (64 - num_bits);
272848b8605Smrg   vl_vlc_eatbits(vlc, num_bits);
273848b8605Smrg
274848b8605Smrg   return value;
275848b8605Smrg}
276848b8605Smrg
277848b8605Smrg/**
278848b8605Smrg * lookup a value and length in a decompressed table
279848b8605Smrg */
280b8e80941Smrgstatic inline int8_t
281848b8605Smrgvl_vlc_get_vlclbf(struct vl_vlc *vlc, const struct vl_vlc_entry *tbl, unsigned num_bits)
282848b8605Smrg{
283848b8605Smrg   tbl += vl_vlc_peekbits(vlc, num_bits);
284848b8605Smrg   vl_vlc_eatbits(vlc, tbl->length);
285848b8605Smrg   return tbl->value;
286848b8605Smrg}
287848b8605Smrg
288848b8605Smrg/**
289848b8605Smrg * fast forward search for a specific byte value
290848b8605Smrg */
291b8e80941Smrgstatic inline boolean
292848b8605Smrgvl_vlc_search_byte(struct vl_vlc *vlc, unsigned num_bits, uint8_t value)
293848b8605Smrg{
294848b8605Smrg   /* make sure we are on a byte boundary */
295848b8605Smrg   assert((vl_vlc_valid_bits(vlc) % 8) == 0);
296b8e80941Smrg   assert(num_bits == ~0u || (num_bits % 8) == 0);
297848b8605Smrg
298848b8605Smrg   /* deplete the bit buffer */
299848b8605Smrg   while (vl_vlc_valid_bits(vlc) > 0) {
300848b8605Smrg
301848b8605Smrg      if (vl_vlc_peekbits(vlc, 8) == value) {
302848b8605Smrg         vl_vlc_fillbits(vlc);
303848b8605Smrg         return TRUE;
304848b8605Smrg      }
305848b8605Smrg
306848b8605Smrg      vl_vlc_eatbits(vlc, 8);
307848b8605Smrg
308b8e80941Smrg      if (num_bits != ~0u) {
309848b8605Smrg         num_bits -= 8;
310848b8605Smrg         if (num_bits == 0)
311848b8605Smrg            return FALSE;
312848b8605Smrg      }
313848b8605Smrg   }
314848b8605Smrg
315848b8605Smrg   /* deplete the byte buffers */
316848b8605Smrg   while (1) {
317848b8605Smrg
318848b8605Smrg      /* if this input is depleted */
319848b8605Smrg      if (vlc->data == vlc->end) {
320848b8605Smrg         if (vlc->bytes_left)
321848b8605Smrg            /* go on to next input */
322848b8605Smrg            vl_vlc_next_input(vlc);
323848b8605Smrg         else
324848b8605Smrg            /* or give up since we don't have anymore inputs */
325848b8605Smrg            return FALSE;
326848b8605Smrg      }
327848b8605Smrg
328848b8605Smrg      if (*vlc->data == value) {
329848b8605Smrg         vl_vlc_align_data_ptr(vlc);
330848b8605Smrg         vl_vlc_fillbits(vlc);
331848b8605Smrg         return TRUE;
332848b8605Smrg      }
333848b8605Smrg
334848b8605Smrg      ++vlc->data;
335b8e80941Smrg      if (num_bits != ~0u) {
336848b8605Smrg         num_bits -= 8;
337848b8605Smrg         if (num_bits == 0) {
338848b8605Smrg            vl_vlc_align_data_ptr(vlc);
339848b8605Smrg            return FALSE;
340848b8605Smrg         }
341848b8605Smrg      }
342848b8605Smrg   }
343848b8605Smrg}
344848b8605Smrg
345848b8605Smrg/**
346848b8605Smrg * remove num_bits bits starting at pos from the bitbuffer
347848b8605Smrg */
348b8e80941Smrgstatic inline void
349848b8605Smrgvl_vlc_removebits(struct vl_vlc *vlc, unsigned pos, unsigned num_bits)
350848b8605Smrg{
351848b8605Smrg   uint64_t lo = (vlc->buffer & (~0UL >> (pos + num_bits))) << num_bits;
352848b8605Smrg   uint64_t hi = (vlc->buffer & (~0UL << (64 - pos)));
353848b8605Smrg   vlc->buffer = lo | hi;
354848b8605Smrg   vlc->invalid_bits += num_bits;
355848b8605Smrg}
356848b8605Smrg
357848b8605Smrg/**
358848b8605Smrg * limit the number of bits left for fetching
359848b8605Smrg */
360b8e80941Smrgstatic inline void
361848b8605Smrgvl_vlc_limit(struct vl_vlc *vlc, unsigned bits_left)
362848b8605Smrg{
363848b8605Smrg   assert(bits_left <= vl_vlc_bits_left(vlc));
364848b8605Smrg
365848b8605Smrg   vl_vlc_fillbits(vlc);
366848b8605Smrg   if (bits_left < vl_vlc_valid_bits(vlc)) {
367848b8605Smrg      vlc->invalid_bits = 32 - bits_left;
368848b8605Smrg      vlc->buffer &= ~0L << (vlc->invalid_bits + 32);
369848b8605Smrg      vlc->end = vlc->data;
370848b8605Smrg      vlc->bytes_left = 0;
371848b8605Smrg   } else {
372848b8605Smrg      assert((bits_left - vl_vlc_valid_bits(vlc)) % 8 == 0);
373848b8605Smrg      vlc->bytes_left = (bits_left - vl_vlc_valid_bits(vlc)) / 8;
374848b8605Smrg      if (vlc->bytes_left < (vlc->end - vlc->data)) {
375848b8605Smrg         vlc->end = vlc->data + vlc->bytes_left;
376848b8605Smrg         vlc->bytes_left = 0;
377848b8605Smrg      } else
378848b8605Smrg         vlc->bytes_left -= vlc->end - vlc->data;
379848b8605Smrg   }
380848b8605Smrg}
381848b8605Smrg
382848b8605Smrg#endif /* vl_vlc_h */
383