1 // SPDX-License-Identifier: GPL-2.0-only
2 /* tnum: tracked (or tristate) numbers
4 * A tnum tracks knowledge about the bits of a value. Each bit can be either
5 * known (0 or 1), or unknown (x). Arithmetic operations on tnums will
6 * propagate the unknown bits such that the tnum result represents all the
7 * possible results for possible values of the operands.
9 #include <linux/kernel.h>
10 #include <linux/tnum.h>
12 #define TNUM(_v, _m) (struct tnum){.value = _v, .mask = _m}
13 /* A completely unknown value */
14 const struct tnum tnum_unknown
= { .value
= 0, .mask
= -1 };
16 struct tnum
tnum_const(u64 value
)
18 return TNUM(value
, 0);
21 struct tnum
tnum_range(u64 min
, u64 max
)
23 u64 chi
= min
^ max
, delta
;
26 /* special case, needed because 1ULL << 64 is undefined */
29 /* e.g. if chi = 4, bits = 3, delta = (1<<3) - 1 = 7.
30 * if chi = 0, bits = 0, delta = (1<<0) - 1 = 0, so we return
31 * constant min (since min == max).
33 delta
= (1ULL << bits
) - 1;
34 return TNUM(min
& ~delta
, delta
);
37 struct tnum
tnum_lshift(struct tnum a
, u8 shift
)
39 return TNUM(a
.value
<< shift
, a
.mask
<< shift
);
42 struct tnum
tnum_rshift(struct tnum a
, u8 shift
)
44 return TNUM(a
.value
>> shift
, a
.mask
>> shift
);
47 struct tnum
tnum_arshift(struct tnum a
, u8 min_shift
)
49 /* if a.value is negative, arithmetic shifting by minimum shift
50 * will have larger negative offset compared to more shifting.
51 * If a.value is nonnegative, arithmetic shifting by minimum shift
52 * will have larger positive offset compare to more shifting.
54 return TNUM((s64
)a
.value
>> min_shift
, (s64
)a
.mask
>> min_shift
);
57 struct tnum
tnum_add(struct tnum a
, struct tnum b
)
59 u64 sm
, sv
, sigma
, chi
, mu
;
62 sv
= a
.value
+ b
.value
;
65 mu
= chi
| a
.mask
| b
.mask
;
66 return TNUM(sv
& ~mu
, mu
);
69 struct tnum
tnum_sub(struct tnum a
, struct tnum b
)
71 u64 dv
, alpha
, beta
, chi
, mu
;
73 dv
= a
.value
- b
.value
;
77 mu
= chi
| a
.mask
| b
.mask
;
78 return TNUM(dv
& ~mu
, mu
);
81 struct tnum
tnum_and(struct tnum a
, struct tnum b
)
85 alpha
= a
.value
| a
.mask
;
86 beta
= b
.value
| b
.mask
;
87 v
= a
.value
& b
.value
;
88 return TNUM(v
, alpha
& beta
& ~v
);
91 struct tnum
tnum_or(struct tnum a
, struct tnum b
)
95 v
= a
.value
| b
.value
;
97 return TNUM(v
, mu
& ~v
);
100 struct tnum
tnum_xor(struct tnum a
, struct tnum b
)
104 v
= a
.value
^ b
.value
;
105 mu
= a
.mask
| b
.mask
;
106 return TNUM(v
& ~mu
, mu
);
109 /* half-multiply add: acc += (unknown * mask * value).
110 * An intermediate step in the multiply algorithm.
112 static struct tnum
hma(struct tnum acc
, u64 value
, u64 mask
)
116 acc
= tnum_add(acc
, TNUM(0, value
));
123 struct tnum
tnum_mul(struct tnum a
, struct tnum b
)
128 pi
= a
.value
* b
.value
;
129 acc
= hma(TNUM(pi
, 0), a
.mask
, b
.mask
| b
.value
);
130 return hma(acc
, b
.mask
, a
.value
);
133 /* Note that if a and b disagree - i.e. one has a 'known 1' where the other has
134 * a 'known 0' - this will return a 'known 1' for that bit.
136 struct tnum
tnum_intersect(struct tnum a
, struct tnum b
)
140 v
= a
.value
| b
.value
;
141 mu
= a
.mask
& b
.mask
;
142 return TNUM(v
& ~mu
, mu
);
145 struct tnum
tnum_cast(struct tnum a
, u8 size
)
147 a
.value
&= (1ULL << (size
* 8)) - 1;
148 a
.mask
&= (1ULL << (size
* 8)) - 1;
152 bool tnum_is_aligned(struct tnum a
, u64 size
)
156 return !((a
.value
| a
.mask
) & (size
- 1));
159 bool tnum_in(struct tnum a
, struct tnum b
)
161 if (b
.mask
& ~a
.mask
)
164 return a
.value
== b
.value
;
167 int tnum_strn(char *str
, size_t size
, struct tnum a
)
169 return snprintf(str
, size
, "(%#llx; %#llx)", a
.value
, a
.mask
);
171 EXPORT_SYMBOL_GPL(tnum_strn
);
173 int tnum_sbin(char *str
, size_t size
, struct tnum a
)
177 for (n
= 64; n
; n
--) {
181 else if (a
.value
& 1)
189 str
[min(size
- 1, (size_t)64)] = 0;