FFmpeg
intmath.h
Go to the documentation of this file.
1 /*
2  * Copyright © 2022-2024 Rémi Denis-Courmont.
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 AVUTIL_RISCV_INTMATH_H
22 #define AVUTIL_RISCV_INTMATH_H
23 
24 #include <stdint.h>
25 #include <math.h>
26 
27 #include "config.h"
28 #include "libavutil/attributes.h"
29 #include "libavutil/riscv/cpu.h"
30 
31 /*
32  * The compiler is forced to sign-extend the result anyhow, so it is faster to
33  * compute it explicitly and use it.
34  */
35 #define av_clip_int8 av_clip_int8_rvi
37 {
38  union { uint8_t u; int8_t s; } u = { .u = a };
39 
40  if (a != u.s)
41  a = ((a >> 31) ^ 0x7F);
42  return a;
43 }
44 
45 #define av_clip_int16 av_clip_int16_rvi
47 {
48  union { uint16_t u; int16_t s; } u = { .u = a };
49 
50  if (a != u.s)
51  a = ((a >> 31) ^ 0x7FFF);
52  return a;
53 }
54 
55 #define av_clipl_int32 av_clipl_int32_rvi
57 {
58  union { uint32_t u; int32_t s; } u = { .u = a };
59 
60  if (a != u.s)
61  a = ((a >> 63) ^ 0x7FFFFFFF);
62  return a;
63 }
64 
65 #define av_clip_intp2 av_clip_intp2_rvi
67 {
68  const int shift = 31 - p;
69  int b = ((int)(((unsigned)a) << shift)) >> shift;
70 
71  if (a != b)
72  b = (a >> 31) ^ ((1 << p) - 1);
73  return b;
74 }
75 
76 #if defined (__riscv_f) || defined (__riscv_zfinx)
77 #define av_clipf av_clipf_rvf
78 static av_always_inline av_const float av_clipf_rvf(float a, float min,
79  float max)
80 {
81  return fminf(fmaxf(a, min), max);
82 }
83 #endif
84 
85 #if defined (__riscv_d) || defined (__riscv_zdinx)
86 #define av_clipd av_clipd_rvd
87 static av_always_inline av_const double av_clipd_rvd(double a, double min,
88  double max)
89 {
90  return fmin(fmax(a, min), max);
91 }
92 #endif
93 
94 #if defined (__GNUC__) || defined (__clang__)
95 static inline av_const int ff_ctz_rv(int x)
96 {
97 #if HAVE_RV && !defined(__riscv_zbb)
98  if (!__builtin_constant_p(x) &&
99  __builtin_expect(ff_rv_zbb_support(), true)) {
100  int y;
101 
102  __asm__ (
103  ".option push\n"
104  ".option arch, +zbb\n"
105 #if __riscv_xlen >= 64
106  "ctzw %0, %1\n"
107 #else
108  "ctz %0, %1\n"
109 #endif
110  ".option pop" : "=r" (y) : "r" (x));
111  if (y > 32)
112  __builtin_unreachable();
113  return y;
114  }
115 #endif
116  return __builtin_ctz(x);
117 }
118 #define ff_ctz ff_ctz_rv
119 
120 static inline av_const int ff_ctzll_rv(long long x)
121 {
122 #if HAVE_RV && !defined(__riscv_zbb) && __riscv_xlen == 64
123  if (!__builtin_constant_p(x) &&
124  __builtin_expect(ff_rv_zbb_support(), true)) {
125  int y;
126 
127  __asm__ (
128  ".option push\n"
129  ".option arch, +zbb\n"
130  "ctz %0, %1\n"
131  ".option pop" : "=r" (y) : "r" (x));
132  if (y > 64)
133  __builtin_unreachable();
134  return y;
135  }
136 #endif
137  return __builtin_ctzll(x);
138 }
139 #define ff_ctzll ff_ctzll_rv
140 
141 static inline av_const int ff_clz_rv(int x)
142 {
143 #if HAVE_RV && !defined(__riscv_zbb)
144  if (!__builtin_constant_p(x) &&
145  __builtin_expect(ff_rv_zbb_support(), true)) {
146  int y;
147 
148  __asm__ (
149  ".option push\n"
150  ".option arch, +zbb\n"
151 #if __riscv_xlen >= 64
152  "clzw %0, %1\n"
153 #else
154  "clz %0, %1\n"
155 #endif
156  ".option pop" : "=r" (y) : "r" (x));
157  if (y > 32)
158  __builtin_unreachable();
159  return y;
160  }
161 #endif
162  return __builtin_clz(x);
163 }
164 #define ff_clz ff_clz_rv
165 
166 #if __riscv_xlen == 64
167 static inline av_const int ff_clzll_rv(long long x)
168 {
169 #if HAVE_RV && !defined(__riscv_zbb)
170  if (!__builtin_constant_p(x) &&
171  __builtin_expect(ff_rv_zbb_support(), true)) {
172  int y;
173 
174  __asm__ (
175  ".option push\n"
176  ".option arch, +zbb\n"
177  "clz %0, %1\n"
178  ".option pop" : "=r" (y) : "r" (x));
179  if (y > 64)
180  __builtin_unreachable();
181  return y;
182  }
183 #endif
184  return __builtin_clzll(x);
185 }
186 #define ff_clz ff_clz_rv
187 #endif
188 
189 static inline av_const int ff_log2_rv(unsigned int x)
190 {
191  return 31 - ff_clz_rv(x | 1);
192 }
193 #define ff_log2 ff_log2_rv
194 #define ff_log2_16bit ff_log2_rv
195 
196 static inline av_const int av_popcount_rv(unsigned int x)
197 {
198 #if HAVE_RV && !defined(__riscv_zbb)
199  if (!__builtin_constant_p(x) &&
200  __builtin_expect(ff_rv_zbb_support(), true)) {
201  int y;
202 
203  __asm__ (
204  ".option push\n"
205  ".option arch, +zbb\n"
206 #if __riscv_xlen >= 64
207  "cpopw %0, %1\n"
208 #else
209  "cpop %0, %1\n"
210 #endif
211  ".option pop" : "=r" (y) : "r" (x));
212  if (y > 32)
213  __builtin_unreachable();
214  return y;
215  }
216 #endif
217  return __builtin_popcount(x);
218 }
219 #define av_popcount av_popcount_rv
220 
221 static inline av_const int av_popcount64_rv(uint64_t x)
222 {
223 #if HAVE_RV && !defined(__riscv_zbb) && __riscv_xlen >= 64
224  if (!__builtin_constant_p(x) &&
225  __builtin_expect(ff_rv_zbb_support(), true)) {
226  int y;
227 
228  __asm__ (
229  ".option push\n"
230  ".option arch, +zbb\n"
231  "cpop %0, %1\n"
232  ".option pop" : "=r" (y) : "r" (x));
233  if (y > 64)
234  __builtin_unreachable();
235  return y;
236  }
237 #endif
238  return __builtin_popcountl(x);
239 }
240 #define av_popcount64 av_popcount64_rv
241 
242 static inline av_const int av_parity_rv(unsigned int x)
243 {
244 #if HAVE_RV && !defined(__riscv_zbb)
245  if (!__builtin_constant_p(x) &&
246  __builtin_expect(ff_rv_zbb_support(), true)) {
247  int y;
248 
249  __asm__ (
250  ".option push\n"
251  ".option arch, +zbb\n"
252 #if __riscv_xlen >= 64
253  "cpopw %0, %1\n"
254 #else
255  "cpop %0, %1\n"
256 #endif
257  ".option pop" : "=r" (y) : "r" (x));
258  return y & 1;
259  }
260 #endif
261  return __builtin_parity(x);
262 }
263 #define av_parity av_parity_rv
264 #endif
265 
266 #endif /* AVUTIL_RISCV_INTMATH_H */
u
#define u(width, name, range_min, range_max)
Definition: cbs_h2645.c:251
int64_t
long long int64_t
Definition: coverity.c:34
av_const
#define av_const
Definition: attributes.h:84
b
#define b
Definition: input.c:41
max
#define max(a, b)
Definition: cuda_runtime.h:33
av_clipl_int32_rvi
static av_always_inline av_const int32_t av_clipl_int32_rvi(int64_t a)
Definition: intmath.h:56
av_clip_int8_rvi
static av_always_inline av_const int8_t av_clip_int8_rvi(int a)
Definition: intmath.h:36
ff_clz_rv
static av_const int ff_clz_rv(int x)
Definition: intmath.h:141
s
#define s(width, name)
Definition: cbs_vp9.c:198
ff_rv_zbb_support
static av_const bool ff_rv_zbb_support(void)
Definition: cpu.h:34
cpu.h
fminf
float fminf(float, float)
ff_ctzll_rv
static av_const int ff_ctzll_rv(long long x)
Definition: intmath.h:120
av_popcount_rv
static av_const int av_popcount_rv(unsigned int x)
Definition: intmath.h:196
ff_ctz_rv
static av_const int ff_ctz_rv(int x)
Definition: intmath.h:95
shift
static int shift(int a, int b)
Definition: bonk.c:261
ff_log2_rv
static av_const int ff_log2_rv(unsigned int x)
Definition: intmath.h:189
fmaxf
float fmaxf(float, float)
fmin
double fmin(double, double)
av_clip_intp2_rvi
static av_always_inline av_const int av_clip_intp2_rvi(int a, int p)
Definition: intmath.h:66
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
attributes.h
av_always_inline
#define av_always_inline
Definition: attributes.h:49
av_parity_rv
static av_const int av_parity_rv(unsigned int x)
Definition: intmath.h:242
__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")
fmax
double fmax(double, double)
av_clip_int16_rvi
static av_always_inline av_const int16_t av_clip_int16_rvi(int a)
Definition: intmath.h:46
av_popcount64_rv
static av_const int av_popcount64_rv(uint64_t x)
Definition: intmath.h:221
int32_t
int32_t
Definition: audioconvert.c:56
min
float min
Definition: vorbis_enc_data.h:429