On Sun, 2024-04-28 at 23:15 +0800, Xu Kuohai wrote: [...] > diff --git a/kernel/bpf/tnum.c b/kernel/bpf/tnum.c > index 9dbc31b25e3d..9d4480a683ca 100644 > --- a/kernel/bpf/tnum.c > +++ b/kernel/bpf/tnum.c > @@ -150,6 +150,29 @@ struct tnum tnum_intersect(struct tnum a, struct tnum b) > return TNUM(v & ~mu, mu); > } > > +/* > + * Each bit has 3 states: unkown, known 0, known 1. If using x to represent > + * unknown state, the result of the union of two bits is as follows: > + * > + * | x 0 1 > + * -----+------------ > + * x | x x x > + * 0 | x 0 x > + * 1 | x x 1 > + * > + * For tnum a and b, only the bits that are both known 0 or known 1 in a > + * and b are known in the result of union a and b. > + */ > +struct tnum tnum_union(struct tnum a, struct tnum b) > +{ > + u64 v0, v1, mu; > + > + mu = a.mask | b.mask; // unkown bits either in a or b > + v1 = (a.value & b.value) & ~mu; // "known 1" bits in both a and b > + v0 = (~a.value & ~b.value) & ~mu; // "known 0" bits in both a and b > + return TNUM(v1, mu | ~(v0 | v1)); > +} > + Zero would be represented as {.value=0,.mask=0}, suppose 'b' is zero: 1. mu = a.mask | 0; 2. mu = a.mask; v1 = (a.value & 0) & ~mu; v1 = 0; v0 = (~a.value & ~0) & ~mu; v0 = ~a.value & ~mu; return TNUM(v1, mu | ~(v0 | v1)); return TNUM(v1, mu | ~(v0 | v1)); 3. v1 = 0; 4. v1 = 0; v0 = ~a.value & ~a.mask; v0 = ~a.value & ~a.mask; return TNUM(v1, a.mask | ~(v0 | v1)); return TNUM(0, a.mask | ~(~a.value & ~a.mask)); 5. return TNUM(0, a.mask | a.value) So ultimately this says that for 1's that we knew we no longer know if those are 1's. Which seems to make sense.