| 1 | /* @title: Type-Generic Compiler Wrappers */ |
| 2 | #pragma once |
| 3 | #include <compiler/core.h> |
| 4 | #include <compiler/intrinsic.h> |
| 5 | |
| 6 | #define cw_alloc_0() cc_malloc_like cc_warn_unused_result |
| 7 | #define cw_alloc_1(sz) cw_alloc_0() cc_alloc_size(sz) |
| 8 | #define cw_alloc_2(sz, align) cw_alloc_1(sz) cc_alloc_align(align) |
| 9 | |
| 10 | #define cw_alloc(...) PP_CALL2(cw_alloc, __VA_ARGS__) |
| 11 | |
| 12 | #define cw_popcount(x) \ |
| 13 | cc_generic((x), unsigned char : ci_popcount((unsigned int) (x)), \ |
| 14 | signed char : ci_popcount((unsigned int) (unsigned char) (x)), \ |
| 15 | char : ci_popcount((unsigned int) (unsigned char) (x)), \ |
| 16 | unsigned short : ci_popcount((unsigned int) (x)), \ |
| 17 | short : ci_popcount((unsigned int) (unsigned short) (x)), \ |
| 18 | unsigned int : ci_popcount(x), \ |
| 19 | int : ci_popcount((unsigned int) (x)), \ |
| 20 | unsigned long : ci_popcountl(x), \ |
| 21 | long : ci_popcountl((unsigned long) (x)), \ |
| 22 | unsigned long long : ci_popcountll(x), \ |
| 23 | long long : ci_popcountll((unsigned long long) (x)), \ |
| 24 | default : ci_popcountll((unsigned long long) (x))) |
| 25 | |
| 26 | #define cw_bswap16(x) ci_bswap16(x) |
| 27 | #define cw_bswap32(x) ci_bswap32(x) |
| 28 | #define cw_bswap64(x) ci_bswap64(x) |
| 29 | |
| 30 | #define cw_bswap(x) \ |
| 31 | cc_generic((x), uint16_t : ci_bswap16(x), \ |
| 32 | int16_t : (int16_t) ci_bswap16((uint16_t) (x)), \ |
| 33 | uint32_t : ci_bswap32(x), \ |
| 34 | int32_t : (int32_t) ci_bswap32((uint32_t) (x)), \ |
| 35 | uint64_t : ci_bswap64(x), \ |
| 36 | int64_t : (int64_t) ci_bswap64((uint64_t) (x)), \ |
| 37 | default : (sizeof(x) == 2 ? ci_bswap16((uint16_t) (x)) \ |
| 38 | : sizeof(x) == 4 ? ci_bswap32((uint32_t) (x)) \ |
| 39 | : sizeof(x) == 8 ? ci_bswap64((uint64_t) (x)) \ |
| 40 | : (x))) |
| 41 | |
| 42 | /* |
| 43 | * Count Leading Zeros |
| 44 | */ |
| 45 | #define cw_clz(x) \ |
| 46 | ({ \ |
| 47 | __auto_type __cw_clz_x = (x); \ |
| 48 | ct_typecheck_unsigned_as(__cw_clz_x, x); \ |
| 49 | __cw_clz_x == 0 ? (unsigned int) ct_bitsizeof(__cw_clz_x) \ |
| 50 | : sizeof(__cw_clz_x) <= sizeof(unsigned int) \ |
| 51 | ? (unsigned int) (ci_clz((unsigned int) __cw_clz_x) - \ |
| 52 | (ct_bitsizeof(unsigned int) - \ |
| 53 | ct_bitsizeof(__cw_clz_x))) \ |
| 54 | : sizeof(__cw_clz_x) <= sizeof(unsigned long) \ |
| 55 | ? (unsigned int) (ci_clzl((unsigned long) __cw_clz_x) - \ |
| 56 | (ct_bitsizeof(unsigned long) - \ |
| 57 | ct_bitsizeof(__cw_clz_x))) \ |
| 58 | : (unsigned int) ci_clzll((unsigned long long) __cw_clz_x); \ |
| 59 | }) |
| 60 | |
| 61 | /* |
| 62 | * Count Leading Zeros |
| 63 | */ |
| 64 | #define cw_clz_nonzero(x) \ |
| 65 | ({ \ |
| 66 | __auto_type __cw_clzn_x = (x); \ |
| 67 | ct_typecheck_unsigned_as(__cw_clzn_x, x); \ |
| 68 | sizeof(__cw_clzn_x) <= sizeof(unsigned int) \ |
| 69 | ? (unsigned int) (ci_clz((unsigned int) __cw_clzn_x) - \ |
| 70 | (ct_bitsizeof(unsigned int) - \ |
| 71 | ct_bitsizeof(__cw_clzn_x))) \ |
| 72 | : sizeof(__cw_clzn_x) <= sizeof(unsigned long) \ |
| 73 | ? (unsigned int) (ci_clzl((unsigned long) __cw_clzn_x) - \ |
| 74 | (ct_bitsizeof(unsigned long) - \ |
| 75 | ct_bitsizeof(__cw_clzn_x))) \ |
| 76 | : (unsigned int) ci_clzll((unsigned long long) __cw_clzn_x); \ |
| 77 | }) |
| 78 | |
| 79 | /* |
| 80 | * Count Trailing Zeros |
| 81 | */ |
| 82 | #define cw_ctz(x) \ |
| 83 | ({ \ |
| 84 | __auto_type __cw_ctz_x = (x); \ |
| 85 | ct_typecheck_unsigned_as(__cw_ctz_x, x); \ |
| 86 | __cw_ctz_x == 0 \ |
| 87 | ? (unsigned int) ct_bitsizeof(__cw_ctz_x) \ |
| 88 | : (sizeof(__cw_ctz_x) <= sizeof(unsigned int) \ |
| 89 | ? (unsigned int) ci_ctz((unsigned int) __cw_ctz_x) \ |
| 90 | : sizeof(__cw_ctz_x) <= sizeof(unsigned long) \ |
| 91 | ? (unsigned int) ci_ctzl((unsigned long) __cw_ctz_x) \ |
| 92 | : (unsigned int) ci_ctzll( \ |
| 93 | (unsigned long long) __cw_ctz_x)); \ |
| 94 | }) |
| 95 | |
| 96 | /* Fast Count Trailing Zeros: requires x != 0 */ |
| 97 | #define cw_ctz_nonzero(x) \ |
| 98 | ({ \ |
| 99 | __auto_type __cw_ctzn_x = (x); \ |
| 100 | ct_typecheck_unsigned_as(__cw_ctzn_x, x); \ |
| 101 | sizeof(__cw_ctzn_x) <= sizeof(unsigned int) \ |
| 102 | ? (unsigned int) ci_ctz((unsigned int) __cw_ctzn_x) \ |
| 103 | : sizeof(__cw_ctzn_x) <= sizeof(unsigned long) \ |
| 104 | ? (unsigned int) ci_ctzl((unsigned long) __cw_ctzn_x) \ |
| 105 | : (unsigned int) ci_ctzll((unsigned long long) __cw_ctzn_x); \ |
| 106 | }) |
| 107 | |
| 108 | /* Find First Set (1-based index, 0 if none) */ |
| 109 | #define cw_ffs(x) \ |
| 110 | ({ \ |
| 111 | __auto_type __cw_ffs_x = (x); \ |
| 112 | ct_typecheck_integer_as(__cw_ffs_x, x); \ |
| 113 | sizeof(__cw_ffs_x) <= sizeof(unsigned int) \ |
| 114 | ? (unsigned int) ci_ffs((int) __cw_ffs_x) \ |
| 115 | : sizeof(__cw_ffs_x) <= sizeof(unsigned long) \ |
| 116 | ? (unsigned int) ci_ffsl((long) __cw_ffs_x) \ |
| 117 | : (unsigned int) ci_ffsll((long long) __cw_ffs_x); \ |
| 118 | }) |
| 119 | |
| 120 | /* Find Last Set (1-based index, 0 if none) */ |
| 121 | #define cw_fls(x) \ |
| 122 | ({ \ |
| 123 | __auto_type __cw_fls_x = (x); \ |
| 124 | ct_typecheck_unsigned_as(__cw_fls_x, x); \ |
| 125 | __cw_fls_x == 0 ? 0u \ |
| 126 | : (unsigned int) (ct_bitsizeof(__cw_fls_x) - \ |
| 127 | cw_clz_nonzero(__cw_fls_x)); \ |
| 128 | }) |
| 129 | |
| 130 | #define cw_parity(x) \ |
| 131 | cc_generic( \ |
| 132 | (x), unsigned char : ci_parity((unsigned int) (x)), \ |
| 133 | signed char : ci_parity((unsigned int) (unsigned char) (x)), \ |
| 134 | char : ci_parity((unsigned int) (unsigned char) (x)), \ |
| 135 | unsigned short : ci_parity((unsigned int) (x)), \ |
| 136 | short : ci_parity((unsigned int) (unsigned short) (x)), \ |
| 137 | unsigned int : ci_parity(x), int : ci_parity((unsigned int) (x)), \ |
| 138 | unsigned long : ci_parityl(x), long : ci_parityl((unsigned long) (x)), \ |
| 139 | unsigned long long : ci_parityll(x), \ |
| 140 | long long : ci_parityll((unsigned long long) (x)), \ |
| 141 | default : ci_parityll((unsigned long long) (x))) |
| 142 | |
| 143 | #define cw_rol(x, n) \ |
| 144 | ({ \ |
| 145 | __auto_type __cw_rol_x = (x); \ |
| 146 | __auto_type __cw_rol_n = (n); \ |
| 147 | ct_typecheck_unsigned_as(__cw_rol_x, x); \ |
| 148 | ct_typecheck_integer_as(__cw_rol_n, n); \ |
| 149 | unsigned int __cw_rol_shift = (unsigned int) __cw_rol_n; \ |
| 150 | unsigned int __cw_rol_w = (unsigned int) ct_bitsizeof(__cw_rol_x); \ |
| 151 | __cw_rol_shift &= (__cw_rol_w - 1u); \ |
| 152 | (typeof(__cw_rol_x)) ((__cw_rol_x << __cw_rol_shift) | \ |
| 153 | (__cw_rol_x >> ((__cw_rol_w - __cw_rol_shift) & \ |
| 154 | (__cw_rol_w - 1u)))); \ |
| 155 | }) |
| 156 | |
| 157 | #define cw_ror(x, n) \ |
| 158 | ({ \ |
| 159 | __auto_type __cw_ror_x = (x); \ |
| 160 | __auto_type __cw_ror_n = (n); \ |
| 161 | ct_typecheck_unsigned_as(__cw_ror_x, x); \ |
| 162 | ct_typecheck_integer_as(__cw_ror_n, n); \ |
| 163 | unsigned int __cw_ror_shift = (unsigned int) __cw_ror_n; \ |
| 164 | unsigned int __cw_ror_w = (unsigned int) ct_bitsizeof(__cw_ror_x); \ |
| 165 | __cw_ror_shift &= (__cw_ror_w - 1u); \ |
| 166 | (typeof(__cw_ror_x)) ((__cw_ror_x >> __cw_ror_shift) | \ |
| 167 | (__cw_ror_x << ((__cw_ror_w - __cw_ror_shift) & \ |
| 168 | (__cw_ror_w - 1u)))); \ |
| 169 | }) |
| 170 | |
| 171 | #define cw_sat_add(a, b) \ |
| 172 | ({ \ |
| 173 | __auto_type __cw_sa_a = (a); \ |
| 174 | __auto_type __cw_sa_b = (b); \ |
| 175 | typeof(__cw_sa_a) __cw_sa_res; \ |
| 176 | if (ci_add_overflow(__cw_sa_a, __cw_sa_b, &__cw_sa_res)) { \ |
| 177 | __cw_sa_res = (__cw_sa_b > 0) ? ct_max_val(typeof(__cw_sa_a)) \ |
| 178 | : ct_min_val(typeof(__cw_sa_a)); \ |
| 179 | } \ |
| 180 | __cw_sa_res; \ |
| 181 | }) |
| 182 | |
| 183 | #define cw_sat_sub(a, b) \ |
| 184 | ({ \ |
| 185 | __auto_type __cw_ss_a = (a); \ |
| 186 | __auto_type __cw_ss_b = (b); \ |
| 187 | typeof(__cw_ss_a) __cw_ss_res; \ |
| 188 | if (ci_sub_overflow(__cw_ss_a, __cw_ss_b, &__cw_ss_res)) { \ |
| 189 | __cw_ss_res = (__cw_ss_b > 0) ? ct_min_val(typeof(__cw_ss_a)) \ |
| 190 | : ct_max_val(typeof(__cw_ss_a)); \ |
| 191 | } \ |
| 192 | __cw_ss_res; \ |
| 193 | }) |
| 194 | |