1*457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2f1174f77SEdward Cree /* tnum: tracked (or tristate) numbers 3f1174f77SEdward Cree * 4f1174f77SEdward Cree * A tnum tracks knowledge about the bits of a value. Each bit can be either 5f1174f77SEdward Cree * known (0 or 1), or unknown (x). Arithmetic operations on tnums will 6f1174f77SEdward Cree * propagate the unknown bits such that the tnum result represents all the 7f1174f77SEdward Cree * possible results for possible values of the operands. 8f1174f77SEdward Cree */ 9f1174f77SEdward Cree #include <linux/kernel.h> 10f1174f77SEdward Cree #include <linux/tnum.h> 11f1174f77SEdward Cree 12f1174f77SEdward Cree #define TNUM(_v, _m) (struct tnum){.value = _v, .mask = _m} 13f1174f77SEdward Cree /* A completely unknown value */ 14f1174f77SEdward Cree const struct tnum tnum_unknown = { .value = 0, .mask = -1 }; 15f1174f77SEdward Cree 16f1174f77SEdward Cree struct tnum tnum_const(u64 value) 17f1174f77SEdward Cree { 18f1174f77SEdward Cree return TNUM(value, 0); 19f1174f77SEdward Cree } 20f1174f77SEdward Cree 21b03c9f9fSEdward Cree struct tnum tnum_range(u64 min, u64 max) 22b03c9f9fSEdward Cree { 23b03c9f9fSEdward Cree u64 chi = min ^ max, delta; 24b03c9f9fSEdward Cree u8 bits = fls64(chi); 25b03c9f9fSEdward Cree 26b03c9f9fSEdward Cree /* special case, needed because 1ULL << 64 is undefined */ 27b03c9f9fSEdward Cree if (bits > 63) 28b03c9f9fSEdward Cree return tnum_unknown; 29b03c9f9fSEdward Cree /* e.g. if chi = 4, bits = 3, delta = (1<<3) - 1 = 7. 30b03c9f9fSEdward Cree * if chi = 0, bits = 0, delta = (1<<0) - 1 = 0, so we return 31b03c9f9fSEdward Cree * constant min (since min == max). 32b03c9f9fSEdward Cree */ 33b03c9f9fSEdward Cree delta = (1ULL << bits) - 1; 34b03c9f9fSEdward Cree return TNUM(min & ~delta, delta); 35b03c9f9fSEdward Cree } 36b03c9f9fSEdward Cree 37f1174f77SEdward Cree struct tnum tnum_lshift(struct tnum a, u8 shift) 38f1174f77SEdward Cree { 39f1174f77SEdward Cree return TNUM(a.value << shift, a.mask << shift); 40f1174f77SEdward Cree } 41f1174f77SEdward Cree 42f1174f77SEdward Cree struct tnum tnum_rshift(struct tnum a, u8 shift) 43f1174f77SEdward Cree { 44f1174f77SEdward Cree return TNUM(a.value >> shift, a.mask >> shift); 45f1174f77SEdward Cree } 46f1174f77SEdward Cree 479cbe1f5aSYonghong Song struct tnum tnum_arshift(struct tnum a, u8 min_shift) 489cbe1f5aSYonghong Song { 499cbe1f5aSYonghong Song /* if a.value is negative, arithmetic shifting by minimum shift 509cbe1f5aSYonghong Song * will have larger negative offset compared to more shifting. 519cbe1f5aSYonghong Song * If a.value is nonnegative, arithmetic shifting by minimum shift 529cbe1f5aSYonghong Song * will have larger positive offset compare to more shifting. 539cbe1f5aSYonghong Song */ 549cbe1f5aSYonghong Song return TNUM((s64)a.value >> min_shift, (s64)a.mask >> min_shift); 559cbe1f5aSYonghong Song } 569cbe1f5aSYonghong Song 57f1174f77SEdward Cree struct tnum tnum_add(struct tnum a, struct tnum b) 58f1174f77SEdward Cree { 59f1174f77SEdward Cree u64 sm, sv, sigma, chi, mu; 60f1174f77SEdward Cree 61f1174f77SEdward Cree sm = a.mask + b.mask; 62f1174f77SEdward Cree sv = a.value + b.value; 63f1174f77SEdward Cree sigma = sm + sv; 64f1174f77SEdward Cree chi = sigma ^ sv; 65f1174f77SEdward Cree mu = chi | a.mask | b.mask; 66f1174f77SEdward Cree return TNUM(sv & ~mu, mu); 67f1174f77SEdward Cree } 68f1174f77SEdward Cree 69f1174f77SEdward Cree struct tnum tnum_sub(struct tnum a, struct tnum b) 70f1174f77SEdward Cree { 71f1174f77SEdward Cree u64 dv, alpha, beta, chi, mu; 72f1174f77SEdward Cree 73f1174f77SEdward Cree dv = a.value - b.value; 74f1174f77SEdward Cree alpha = dv + a.mask; 75f1174f77SEdward Cree beta = dv - b.mask; 76f1174f77SEdward Cree chi = alpha ^ beta; 77f1174f77SEdward Cree mu = chi | a.mask | b.mask; 78f1174f77SEdward Cree return TNUM(dv & ~mu, mu); 79f1174f77SEdward Cree } 80f1174f77SEdward Cree 81f1174f77SEdward Cree struct tnum tnum_and(struct tnum a, struct tnum b) 82f1174f77SEdward Cree { 83f1174f77SEdward Cree u64 alpha, beta, v; 84f1174f77SEdward Cree 85f1174f77SEdward Cree alpha = a.value | a.mask; 86f1174f77SEdward Cree beta = b.value | b.mask; 87f1174f77SEdward Cree v = a.value & b.value; 88f1174f77SEdward Cree return TNUM(v, alpha & beta & ~v); 89f1174f77SEdward Cree } 90f1174f77SEdward Cree 91f1174f77SEdward Cree struct tnum tnum_or(struct tnum a, struct tnum b) 92f1174f77SEdward Cree { 93f1174f77SEdward Cree u64 v, mu; 94f1174f77SEdward Cree 95f1174f77SEdward Cree v = a.value | b.value; 96f1174f77SEdward Cree mu = a.mask | b.mask; 97f1174f77SEdward Cree return TNUM(v, mu & ~v); 98f1174f77SEdward Cree } 99f1174f77SEdward Cree 100f1174f77SEdward Cree struct tnum tnum_xor(struct tnum a, struct tnum b) 101f1174f77SEdward Cree { 102f1174f77SEdward Cree u64 v, mu; 103f1174f77SEdward Cree 104f1174f77SEdward Cree v = a.value ^ b.value; 105f1174f77SEdward Cree mu = a.mask | b.mask; 106f1174f77SEdward Cree return TNUM(v & ~mu, mu); 107f1174f77SEdward Cree } 108f1174f77SEdward Cree 109f1174f77SEdward Cree /* half-multiply add: acc += (unknown * mask * value). 110f1174f77SEdward Cree * An intermediate step in the multiply algorithm. 111f1174f77SEdward Cree */ 112f1174f77SEdward Cree static struct tnum hma(struct tnum acc, u64 value, u64 mask) 113f1174f77SEdward Cree { 114f1174f77SEdward Cree while (mask) { 115f1174f77SEdward Cree if (mask & 1) 116f1174f77SEdward Cree acc = tnum_add(acc, TNUM(0, value)); 117f1174f77SEdward Cree mask >>= 1; 118f1174f77SEdward Cree value <<= 1; 119f1174f77SEdward Cree } 120f1174f77SEdward Cree return acc; 121f1174f77SEdward Cree } 122f1174f77SEdward Cree 123f1174f77SEdward Cree struct tnum tnum_mul(struct tnum a, struct tnum b) 124f1174f77SEdward Cree { 125f1174f77SEdward Cree struct tnum acc; 126f1174f77SEdward Cree u64 pi; 127f1174f77SEdward Cree 128f1174f77SEdward Cree pi = a.value * b.value; 129f1174f77SEdward Cree acc = hma(TNUM(pi, 0), a.mask, b.mask | b.value); 130f1174f77SEdward Cree return hma(acc, b.mask, a.value); 131f1174f77SEdward Cree } 132f1174f77SEdward Cree 133f1174f77SEdward Cree /* Note that if a and b disagree - i.e. one has a 'known 1' where the other has 134f1174f77SEdward Cree * a 'known 0' - this will return a 'known 1' for that bit. 135f1174f77SEdward Cree */ 136f1174f77SEdward Cree struct tnum tnum_intersect(struct tnum a, struct tnum b) 137f1174f77SEdward Cree { 138f1174f77SEdward Cree u64 v, mu; 139f1174f77SEdward Cree 140f1174f77SEdward Cree v = a.value | b.value; 141f1174f77SEdward Cree mu = a.mask & b.mask; 142f1174f77SEdward Cree return TNUM(v & ~mu, mu); 143f1174f77SEdward Cree } 144f1174f77SEdward Cree 145f1174f77SEdward Cree struct tnum tnum_cast(struct tnum a, u8 size) 146f1174f77SEdward Cree { 147f1174f77SEdward Cree a.value &= (1ULL << (size * 8)) - 1; 148f1174f77SEdward Cree a.mask &= (1ULL << (size * 8)) - 1; 149f1174f77SEdward Cree return a; 150f1174f77SEdward Cree } 151f1174f77SEdward Cree 152f1174f77SEdward Cree bool tnum_is_aligned(struct tnum a, u64 size) 153f1174f77SEdward Cree { 154f1174f77SEdward Cree if (!size) 155f1174f77SEdward Cree return true; 156f1174f77SEdward Cree return !((a.value | a.mask) & (size - 1)); 157f1174f77SEdward Cree } 158f1174f77SEdward Cree 159f1174f77SEdward Cree bool tnum_in(struct tnum a, struct tnum b) 160f1174f77SEdward Cree { 161f1174f77SEdward Cree if (b.mask & ~a.mask) 162f1174f77SEdward Cree return false; 163f1174f77SEdward Cree b.value &= ~a.mask; 164f1174f77SEdward Cree return a.value == b.value; 165f1174f77SEdward Cree } 166f1174f77SEdward Cree 167f1174f77SEdward Cree int tnum_strn(char *str, size_t size, struct tnum a) 168f1174f77SEdward Cree { 169f1174f77SEdward Cree return snprintf(str, size, "(%#llx; %#llx)", a.value, a.mask); 170f1174f77SEdward Cree } 171f1174f77SEdward Cree EXPORT_SYMBOL_GPL(tnum_strn); 172f1174f77SEdward Cree 173f1174f77SEdward Cree int tnum_sbin(char *str, size_t size, struct tnum a) 174f1174f77SEdward Cree { 175f1174f77SEdward Cree size_t n; 176f1174f77SEdward Cree 177f1174f77SEdward Cree for (n = 64; n; n--) { 178f1174f77SEdward Cree if (n < size) { 179f1174f77SEdward Cree if (a.mask & 1) 180f1174f77SEdward Cree str[n - 1] = 'x'; 181f1174f77SEdward Cree else if (a.value & 1) 182f1174f77SEdward Cree str[n - 1] = '1'; 183f1174f77SEdward Cree else 184f1174f77SEdward Cree str[n - 1] = '0'; 185f1174f77SEdward Cree } 186f1174f77SEdward Cree a.mask >>= 1; 187f1174f77SEdward Cree a.value >>= 1; 188f1174f77SEdward Cree } 189f1174f77SEdward Cree str[min(size - 1, (size_t)64)] = 0; 190f1174f77SEdward Cree return 64; 191f1174f77SEdward Cree } 192