summaryrefslogtreecommitdiffstats
path: root/media/libjpeg/simd/arm/jchuff.h
blob: 2fbd252b9b86b3c7cf5049a400b06dc8bd5a763a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * jchuff.h
 *
 * This file was part of the Independent JPEG Group's software:
 * Copyright (C) 1991-1997, Thomas G. Lane.
 * libjpeg-turbo Modifications:
 * Copyright (C) 2009, 2018, 2021, D. R. Commander.
 * Copyright (C) 2018, Matthias Räncker.
 * Copyright (C) 2020-2021, Arm Limited.
 * For conditions of distribution and use, see the accompanying README.ijg
 * file.
 */

/* Expanded entropy encoder object for Huffman encoding.
 *
 * The savable_state subrecord contains fields that change within an MCU,
 * but must not be updated permanently until we complete the MCU.
 */

#if defined(__aarch64__) || defined(_M_ARM64)
#define BIT_BUF_SIZE  64
#else
#define BIT_BUF_SIZE  32
#endif

typedef struct {
  size_t put_buffer;                    /* current bit accumulation buffer */
  int free_bits;                        /* # of bits available in it */
  int last_dc_val[MAX_COMPS_IN_SCAN];   /* last DC coef for each component */
} savable_state;

typedef struct {
  JOCTET *next_output_byte;     /* => next byte to write in buffer */
  size_t free_in_buffer;        /* # of byte spaces remaining in buffer */
  savable_state cur;            /* Current bit buffer & DC state */
  j_compress_ptr cinfo;         /* dump_buffer needs access to this */
  int simd;
} working_state;

/* Outputting bits to the file */

/* Output byte b and, speculatively, an additional 0 byte. 0xFF must be encoded
 * as 0xFF 0x00, so the output buffer pointer is advanced by 2 if the byte is
 * 0xFF.  Otherwise, the output buffer pointer is advanced by 1, and the
 * speculative 0 byte will be overwritten by the next byte.
 */
#define EMIT_BYTE(b) { \
  buffer[0] = (JOCTET)(b); \
  buffer[1] = 0; \
  buffer -= -2 + ((JOCTET)(b) < 0xFF); \
}

/* Output the entire bit buffer.  If there are no 0xFF bytes in it, then write
 * directly to the output buffer.  Otherwise, use the EMIT_BYTE() macro to
 * encode 0xFF as 0xFF 0x00.
 */
#if defined(__aarch64__) || defined(_M_ARM64)

#define FLUSH() { \
  if (put_buffer & 0x8080808080808080 & ~(put_buffer + 0x0101010101010101)) { \
    EMIT_BYTE(put_buffer >> 56) \
    EMIT_BYTE(put_buffer >> 48) \
    EMIT_BYTE(put_buffer >> 40) \
    EMIT_BYTE(put_buffer >> 32) \
    EMIT_BYTE(put_buffer >> 24) \
    EMIT_BYTE(put_buffer >> 16) \
    EMIT_BYTE(put_buffer >>  8) \
    EMIT_BYTE(put_buffer      ) \
  } else { \
    *((uint64_t *)buffer) = BUILTIN_BSWAP64(put_buffer); \
    buffer += 8; \
  } \
}

#else

#if defined(_MSC_VER) && !defined(__clang__)
#define SPLAT() { \
  buffer[0] = (JOCTET)(put_buffer >> 24); \
  buffer[1] = (JOCTET)(put_buffer >> 16); \
  buffer[2] = (JOCTET)(put_buffer >>  8); \
  buffer[3] = (JOCTET)(put_buffer      ); \
  buffer += 4; \
}
#else
#define SPLAT() { \
  put_buffer = __builtin_bswap32(put_buffer); \
  __asm__("str %1, [%0], #4" : "+r" (buffer) : "r" (put_buffer)); \
}
#endif

#define FLUSH() { \
  if (put_buffer & 0x80808080 & ~(put_buffer + 0x01010101)) { \
    EMIT_BYTE(put_buffer >> 24) \
    EMIT_BYTE(put_buffer >> 16) \
    EMIT_BYTE(put_buffer >>  8) \
    EMIT_BYTE(put_buffer      ) \
  } else { \
    SPLAT(); \
  } \
}

#endif

/* Fill the bit buffer to capacity with the leading bits from code, then output
 * the bit buffer and put the remaining bits from code into the bit buffer.
 */
#define PUT_AND_FLUSH(code, size) { \
  put_buffer = (put_buffer << (size + free_bits)) | (code >> -free_bits); \
  FLUSH() \
  free_bits += BIT_BUF_SIZE; \
  put_buffer = code; \
}

/* Insert code into the bit buffer and output the bit buffer if needed.
 * NOTE: We can't flush with free_bits == 0, since the left shift in
 * PUT_AND_FLUSH() would have undefined behavior.
 */
#define PUT_BITS(code, size) { \
  free_bits -= size; \
  if (free_bits < 0) \
    PUT_AND_FLUSH(code, size) \
  else \
    put_buffer = (put_buffer << size) | code; \
}

#define PUT_CODE(code, size, diff) { \
  diff |= code << nbits; \
  nbits += size; \
  PUT_BITS(diff, nbits) \
}