1;; Rewrites for `band`, `bnot`, `bor`, `bxor` 2 3;; x | 0 == x | x == x. 4(rule (simplify (bor ty 5 x 6 (iconst_u ty 0))) 7 (subsume x)) 8(rule (simplify (bor ty x x)) 9 (subsume x)) 10 11;; x ^ 0 == x. 12(rule (simplify (bxor ty 13 x 14 (iconst_u ty 0))) 15 (subsume x)) 16 17;; x ^ x == 0. 18(rule (simplify (bxor (ty_int ty) x x)) 19 (subsume (iconst_u ty 0))) 20 21;; x ^ not(x) == not(x) ^ x == x | not(x) == not(x) | x == -1. 22;; This identity also holds for non-integer types, vectors, and wider types. 23(rule (simplify (bxor (ty_int ty) x (bnot ty x))) (subsume (iconst_s ty -1))) 24(rule (simplify (bxor (ty_int ty) (bnot ty x) x)) (subsume (iconst_s ty -1))) 25(rule (simplify (bor (ty_int ty) x (bnot ty x))) (subsume (iconst_s ty -1))) 26(rule (simplify (bor (ty_int ty) (bnot ty x) x)) (subsume (iconst_s ty -1))) 27 28;; x & x == x & -1 == x. 29(rule (simplify (band ty x x)) (subsume x)) 30(rule (simplify (band ty x (iconst_s ty -1))) 31 (subsume x)) 32 33;; x & 0 == x & not(x) == not(x) & x == 0. 34(rule (simplify (band ty _ zero @ (iconst_u ty 0))) (subsume zero)) 35(rule (simplify (band (ty_int ty) x (bnot ty x))) (subsume (iconst_u ty 0))) 36(rule (simplify (band (ty_int ty) (bnot ty x) x)) (subsume (iconst_u ty 0))) 37 38;; not(not(x)) == x. 39(rule (simplify (bnot ty (bnot ty x))) (subsume x)) 40 41;; DeMorgan's rule (two versions): 42;; bnot(bor(x, y)) == band(bnot(x), bnot(y)) 43(rule (simplify (bnot ty (bor ty x y))) 44 (band ty (bnot ty x) (bnot ty y))) 45;; bnot(band(x, y)) == bor(bnot(x), bnot(y)) 46(rule (simplify (bnot ty (band t x y))) 47 (bor ty (bnot ty x) (bnot ty y))) 48 49;; `or(and(x, y), not(y)) == or(x, not(y))` 50(rule (simplify (bor ty 51 (band ty x y) 52 z @ (bnot ty y))) 53 (bor ty x z)) 54;; Duplicate the rule but swap the `bor` operands because `bor` is 55;; commutative. We could, of course, add a `simplify` rule to do the commutative 56;; swap for all `bor`s but this will bloat the e-graph with many e-nodes. It is 57;; cheaper to have additional rules, rather than additional e-nodes, because we 58;; amortize their cost via ISLE's smart codegen. 59(rule (simplify (bor ty 60 z @ (bnot ty y) 61 (band ty x y))) 62 (bor ty x z)) 63 64;; `or(and(x, y), not(y)) == or(x, not(y))` specialized for constants, since 65;; otherwise we may not know that `z == not(y)` since we don't generally expand 66;; constants in the e-graph. 67;; 68;; (No need to duplicate for commutative `bor` for this constant version because 69;; we move constants to the right.) 70(rule (simplify (bor ty 71 (band ty x (iconst_u ty y)) 72 z @ (iconst_u ty zk))) 73 (if-let true (u64_eq (u64_and (ty_mask ty) zk) 74 (u64_and (ty_mask ty) (u64_not y)))) 75 (bor ty x z)) 76 77;; (x ^ -1) can be replaced with the `bnot` instruction 78(rule (simplify (bxor ty x (iconst_s ty -1))) 79 (bnot ty x)) 80 81;; sshr((x | -x), N) == bmask(x) where N = ty_bits(ty) - 1. 82;; 83;; (x | -x) sets the sign bit to 1 if x is nonzero, and 0 if x is zero. sshr propagates 84;; the sign bit to the rest of the value. 85(rule (simplify (sshr ty (bor ty x (ineg ty x)) (iconst_u ty shift_amt))) 86 (if-let true (u64_eq shift_amt (ty_shift_mask ty))) 87 (bmask ty x)) 88 89(rule (simplify (sshr ty (bor ty (ineg ty x) x) (iconst_u ty shift_amt))) 90 (if-let true (u64_eq shift_amt (ty_shift_mask ty))) 91 (bmask ty x)) 92 93;; Since icmp is always 0 or 1, bmask is just a negation. 94;; TODO: Explore whether this makes sense for things needing extension too. 95(rule (simplify (bmask $I8 cmp@(icmp $I8 _ _ _))) 96 (ineg $I8 cmp)) 97 98;; Matches any expressions that preserve "truthiness". 99;; i.e. If the input is zero it remains zero, and if it is nonzero it can have 100;; a different value as long as it is still nonzero. 101(decl pure multi truthy (Value) Value) 102(rule (truthy (sextend _ x)) x) 103(rule (truthy (uextend _ x)) x) 104(rule (truthy (bmask _ x)) x) 105(rule (truthy (ineg _ x)) x) 106(rule (truthy (bswap _ x)) x) 107(rule (truthy (bitrev _ x)) x) 108(rule (truthy (popcnt _ x)) x) 109(rule (truthy (rotl _ x _)) x) 110(rule (truthy (rotr _ x _)) x) 111(rule (truthy (select _ x (iconst_u _ (u64_nonzero _)) (iconst_u _ 0))) x) 112;; (ne ty (iconst 0) v) is also canonicalized into this form via another rule 113(rule (truthy (ne _ x (iconst_u _ 0))) x) 114 115;; All of these expressions don't care about their input as long as it is truthy. 116;; so we can remove expressions that preserve that property from the input. 117(rule (simplify (bmask ty v)) (if-let x (truthy v)) (bmask ty x)) 118(rule (simplify (select ty v t f)) (if-let c (truthy v)) (select ty c t f)) 119;; (ne ty (iconst 0) v) is also canonicalized into this form via another rule 120(rule (simplify (ne cty v (iconst_u _ 0))) 121 (if-let c (truthy v)) 122 (if-let (value_type (ty_int_ref_scalar_64 ty)) c) 123 (ne cty c (iconst_u ty 0))) 124 125 126 127;; (sextend (bmask x)) can be replaced with (bmask x) since bmask 128;; supports any size of output type, regardless of input. 129;; Same with `ireduce` 130(rule (simplify (sextend ty (bmask _ x))) (bmask ty x)) 131(rule (simplify (ireduce ty (bmask _ x))) (bmask ty x)) 132 133;; (bswap (bswap x)) == x 134(rule (simplify (bswap ty (bswap ty x))) (subsume x)) 135 136;; (bitrev (bitrev x)) == x 137(rule (simplify (bitrev ty (bitrev ty x))) (subsume x)) 138 139;; WebAssembly doesn't have a native byte-swapping instruction at this time so 140;; languages which have a byte-swapping operation will compile it down to bit 141;; shifting and twiddling. This attempts to pattern match what LLVM currently 142;; generates today for the Rust code `a.swap_bytes()`. This might be a bit 143;; brittle over time and/or with other possible LLVM backend optimizations, but 144;; it's at least one way to generate a byte swap. 145;; 146;; Technically this could be permuted quite a few ways and currently there's no 147;; easy way to match all of them, so only one is matched here. 148(rule (simplify (bor ty @ $I32 149 (bor ty 150 (ishl ty x (iconst_u ty 24)) 151 (ishl ty 152 (band ty x (iconst_u ty 0xff00)) 153 (iconst_u ty 8))) 154 (bor ty 155 (band ty 156 (ushr ty x (iconst_u ty 8)) 157 (iconst_u ty 0xff00)) 158 (ushr ty x (iconst_u ty 24))))) 159 (bswap ty x)) 160 161(rule (simplify (bor ty @ $I64 162 (bor ty 163 (bor ty 164 (ishl ty x (iconst_u ty 56)) 165 (ishl ty 166 (band ty x (iconst_u ty 0xff00)) 167 (iconst_u ty 40))) 168 (bor ty 169 (ishl ty 170 (band ty x (iconst_u ty 0xff_0000)) 171 (iconst_u ty 24)) 172 (ishl ty 173 (band ty x (iconst_u ty 0xff00_0000)) 174 (iconst_u ty 8)))) 175 (bor ty 176 (bor ty 177 (band ty 178 (ushr ty x (iconst_u ty 8)) 179 (iconst_u ty 0xff00_0000)) 180 (band ty 181 (ushr ty x (iconst_u ty 24)) 182 (iconst_u ty 0xff_0000))) 183 (bor ty 184 (band ty 185 (ushr ty x (iconst_u ty 40)) 186 (iconst_u ty 0xff00)) 187 (ushr ty x (iconst_u ty 56)))))) 188 (bswap ty x)) 189