Coverage Report

Created: 2025-07-09 06:16

/src/wasm3/source/m3_math_utils.h
Line
Count
Source (jump to first uncovered line)
1
//
2
//  m3_math_utils.h
3
//
4
//  Created by Volodymyr Shymanksyy on 8/10/19.
5
//  Copyright © 2019 Volodymyr Shymanskyy. All rights reserved.
6
//
7
8
#ifndef m3_math_utils_h
9
#define m3_math_utils_h
10
11
#include "m3_core.h"
12
13
#include <limits.h>
14
15
#if defined(M3_COMPILER_MSVC)
16
17
#include <intrin.h>
18
19
#define __builtin_popcount    __popcnt
20
21
static inline
22
int __builtin_ctz(uint32_t x) {
23
    unsigned long ret;
24
    _BitScanForward(&ret, x);
25
    return (int)ret;
26
}
27
28
static inline
29
int __builtin_clz(uint32_t x) {
30
    unsigned long ret;
31
    _BitScanReverse(&ret, x);
32
    return (int)(31 ^ ret);
33
}
34
35
36
37
#ifdef _WIN64
38
39
#define __builtin_popcountll  __popcnt64
40
41
static inline
42
int __builtin_ctzll(uint64_t value) {
43
    unsigned long ret;
44
     _BitScanForward64(&ret, value);
45
    return (int)ret;
46
}
47
48
static inline
49
int __builtin_clzll(uint64_t value) {
50
    unsigned long ret;
51
    _BitScanReverse64(&ret, value);
52
    return (int)(63 ^ ret);
53
}
54
55
#else // _WIN64
56
57
#define __builtin_popcountll(x)  (__popcnt((x) & 0xFFFFFFFF) + __popcnt((x) >> 32))
58
59
static inline
60
int __builtin_ctzll(uint64_t value) {
61
    //if (value == 0) return 64; // Note: ctz(0) result is undefined anyway
62
    uint32_t msh = (uint32_t)(value >> 32);
63
    uint32_t lsh = (uint32_t)(value & 0xFFFFFFFF);
64
    if (lsh != 0) return __builtin_ctz(lsh);
65
    return 32 + __builtin_ctz(msh);
66
}
67
68
static inline
69
int __builtin_clzll(uint64_t value) {
70
    //if (value == 0) return 64; // Note: clz(0) result is undefined anyway
71
    uint32_t msh = (uint32_t)(value >> 32);
72
    uint32_t lsh = (uint32_t)(value & 0xFFFFFFFF);
73
    if (msh != 0) return __builtin_clz(msh);
74
    return 32 + __builtin_clz(lsh);
75
}
76
77
#endif // _WIN64
78
79
#endif // defined(M3_COMPILER_MSVC)
80
81
82
// TODO: not sure why, signbit is actually defined in math.h
83
#if (defined(ESP8266) || defined(ESP32)) && !defined(signbit)
84
    #define signbit(__x) \
85
            ((sizeof(__x) == sizeof(float))  ?  __signbitf(__x) : __signbitd(__x))
86
#endif
87
88
#if defined(__AVR__)
89
90
static inline
91
float rintf( float arg ) {
92
  union { float f; uint32_t i; } u;
93
  u.f = arg;
94
  uint32_t ux = u.i & 0x7FFFFFFF;
95
  if (M3_UNLIKELY(ux == 0 || ux > 0x5A000000)) {
96
    return arg;
97
  }
98
  return (float)lrint(arg);
99
}
100
101
static inline
102
double rint( double arg ) {
103
  union { double f; uint32_t i[2]; } u;
104
  u.f = arg;
105
  uint32_t ux = u.i[1] & 0x7FFFFFFF;
106
  if (M3_UNLIKELY((ux == 0 && u.i[0] == 0) || ux > 0x433FFFFF)) {
107
    return arg;
108
  }
109
  return (double)lrint(arg);
110
}
111
112
//TODO
113
static inline
114
uint64_t strtoull(const char* str, char** endptr, int base) {
115
  return 0;
116
}
117
118
#endif
119
120
/*
121
 * Rotr, Rotl
122
 */
123
124
static inline
125
0
u32 rotl32(u32 n, unsigned c) {
126
0
    const unsigned mask = CHAR_BIT * sizeof(n) - 1;
127
0
    c &= mask & 31;
128
0
    return (n << c) | (n >> ((-c) & mask));
129
0
}
130
131
static inline
132
0
u32 rotr32(u32 n, unsigned c) {
133
0
    const unsigned mask = CHAR_BIT * sizeof(n) - 1;
134
0
    c &= mask & 31;
135
0
    return (n >> c) | (n << ((-c) & mask));
136
0
}
137
138
static inline
139
0
u64 rotl64(u64 n, unsigned c) {
140
0
    const unsigned mask = CHAR_BIT * sizeof(n) - 1;
141
0
    c &= mask & 63;
142
0
    return (n << c) | (n >> ((-c) & mask));
143
0
}
144
145
static inline
146
0
u64 rotr64(u64 n, unsigned c) {
147
0
    const unsigned mask = CHAR_BIT * sizeof(n) - 1;
148
0
    c &= mask & 63;
149
0
    return (n >> c) | (n << ((-c) & mask));
150
0
}
151
152
/*
153
 * Integer Div, Rem
154
 */
155
156
#define OP_DIV_U(RES, A, B)                                      \
157
0
    if (M3_UNLIKELY(B == 0)) newTrap (m3Err_trapDivisionByZero);    \
158
0
    RES = A / B;
159
160
#define OP_REM_U(RES, A, B)                                      \
161
0
    if (M3_UNLIKELY(B == 0)) newTrap (m3Err_trapDivisionByZero);    \
162
0
    RES = A % B;
163
164
// 2's complement detection
165
#if (INT_MIN != -INT_MAX)
166
167
    #define OP_DIV_S(RES, A, B, TYPE_MIN)                         \
168
0
        if (M3_UNLIKELY(B == 0)) newTrap (m3Err_trapDivisionByZero); \
169
0
        if (M3_UNLIKELY(B == -1 and A == TYPE_MIN)) {                \
170
0
            newTrap (m3Err_trapIntegerOverflow);                  \
171
0
        }                                                         \
172
0
        RES = A / B;
173
174
    #define OP_REM_S(RES, A, B, TYPE_MIN)                         \
175
0
        if (M3_UNLIKELY(B == 0)) newTrap (m3Err_trapDivisionByZero); \
176
0
        if (M3_UNLIKELY(B == -1 and A == TYPE_MIN)) RES = 0;         \
177
0
        else RES = A % B;
178
179
#else
180
181
    #define OP_DIV_S(RES, A, B, TYPE_MIN) OP_DIV_U(RES, A, B)
182
    #define OP_REM_S(RES, A, B, TYPE_MIN) OP_REM_U(RES, A, B)
183
184
#endif
185
186
/*
187
 * Trunc
188
 */
189
190
#define OP_TRUNC(RES, A, TYPE, RMIN, RMAX)                  \
191
0
    if (M3_UNLIKELY(isnan(A))) {                               \
192
0
        newTrap (m3Err_trapIntegerConversion);              \
193
0
    }                                                       \
194
0
    if (M3_UNLIKELY(A <= RMIN or A >= RMAX)) {                 \
195
0
        newTrap (m3Err_trapIntegerOverflow);                \
196
0
    }                                                       \
197
0
    RES = (TYPE)A;
198
199
200
0
#define OP_I32_TRUNC_F32(RES, A)    OP_TRUNC(RES, A, i32, -2147483904.0f, 2147483648.0f)
201
0
#define OP_U32_TRUNC_F32(RES, A)    OP_TRUNC(RES, A, u32,          -1.0f, 4294967296.0f)
202
0
#define OP_I32_TRUNC_F64(RES, A)    OP_TRUNC(RES, A, i32, -2147483649.0 , 2147483648.0 )
203
0
#define OP_U32_TRUNC_F64(RES, A)    OP_TRUNC(RES, A, u32,          -1.0 , 4294967296.0 )
204
205
0
#define OP_I64_TRUNC_F32(RES, A)    OP_TRUNC(RES, A, i64, -9223373136366403584.0f,  9223372036854775808.0f)
206
0
#define OP_U64_TRUNC_F32(RES, A)    OP_TRUNC(RES, A, u64,                   -1.0f, 18446744073709551616.0f)
207
0
#define OP_I64_TRUNC_F64(RES, A)    OP_TRUNC(RES, A, i64, -9223372036854777856.0 ,  9223372036854775808.0 )
208
0
#define OP_U64_TRUNC_F64(RES, A)    OP_TRUNC(RES, A, u64,                   -1.0 , 18446744073709551616.0 )
209
210
#define OP_TRUNC_SAT(RES, A, TYPE, RMIN, RMAX, IMIN, IMAX)  \
211
0
    if (M3_UNLIKELY(isnan(A))) {                               \
212
0
        RES = 0;                                            \
213
0
    } else if (M3_UNLIKELY(A <= RMIN)) {                       \
214
0
        RES = IMIN;                                         \
215
0
    } else if (M3_UNLIKELY(A >= RMAX)) {                       \
216
0
        RES = IMAX;                                         \
217
0
    } else {                                                \
218
0
        RES = (TYPE)A;                                      \
219
0
    }
220
221
0
#define OP_I32_TRUNC_SAT_F32(RES, A)    OP_TRUNC_SAT(RES, A, i32, -2147483904.0f, 2147483648.0f,   INT32_MIN,  INT32_MAX)
222
0
#define OP_U32_TRUNC_SAT_F32(RES, A)    OP_TRUNC_SAT(RES, A, u32,          -1.0f, 4294967296.0f,         0UL, UINT32_MAX)
223
0
#define OP_I32_TRUNC_SAT_F64(RES, A)    OP_TRUNC_SAT(RES, A, i32, -2147483649.0 , 2147483648.0,    INT32_MIN,  INT32_MAX)
224
0
#define OP_U32_TRUNC_SAT_F64(RES, A)    OP_TRUNC_SAT(RES, A, u32,          -1.0 , 4294967296.0,          0UL, UINT32_MAX)
225
226
0
#define OP_I64_TRUNC_SAT_F32(RES, A)    OP_TRUNC_SAT(RES, A, i64, -9223373136366403584.0f,  9223372036854775808.0f, INT64_MIN,  INT64_MAX)
227
0
#define OP_U64_TRUNC_SAT_F32(RES, A)    OP_TRUNC_SAT(RES, A, u64,                   -1.0f, 18446744073709551616.0f,      0ULL, UINT64_MAX)
228
0
#define OP_I64_TRUNC_SAT_F64(RES, A)    OP_TRUNC_SAT(RES, A, i64, -9223372036854777856.0 ,  9223372036854775808.0,  INT64_MIN,  INT64_MAX)
229
0
#define OP_U64_TRUNC_SAT_F64(RES, A)    OP_TRUNC_SAT(RES, A, u64,                   -1.0 , 18446744073709551616.0,       0ULL, UINT64_MAX)
230
231
/*
232
 * Min, Max
233
 */
234
235
#if d_m3HasFloat
236
237
#include <math.h>
238
239
static inline
240
0
f32 min_f32(f32 a, f32 b) {
241
0
    if (M3_UNLIKELY(isnan(a) or isnan(b))) return NAN;
242
0
    if (M3_UNLIKELY(a == 0 and a == b)) return signbit(a) ? a : b;
243
0
    return a > b ? b : a;
244
0
}
245
246
static inline
247
0
f32 max_f32(f32 a, f32 b) {
248
0
    if (M3_UNLIKELY(isnan(a) or isnan(b))) return NAN;
249
0
    if (M3_UNLIKELY(a == 0 and a == b)) return signbit(a) ? b : a;
250
0
    return a > b ? a : b;
251
0
}
252
253
static inline
254
0
f64 min_f64(f64 a, f64 b) {
255
0
    if (M3_UNLIKELY(isnan(a) or isnan(b))) return NAN;
256
0
    if (M3_UNLIKELY(a == 0 and a == b)) return signbit(a) ? a : b;
257
0
    return a > b ? b : a;
258
0
}
259
260
static inline
261
0
f64 max_f64(f64 a, f64 b) {
262
0
    if (M3_UNLIKELY(isnan(a) or isnan(b))) return NAN;
263
0
    if (M3_UNLIKELY(a == 0 and a == b)) return signbit(a) ? b : a;
264
0
    return a > b ? a : b;
265
0
}
266
#endif
267
268
#endif // m3_math_utils_h