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