Skip to content

Commit 8c9eb99

Browse files
fitzgenitsrainy
andauthored
Cranelift: Rewrite or(and(x, y), not(y)) => or(x, not(y)) (#5676)
Co-authored-by: Rainy Sinclair <844493+itsrainy@users.noreply.github.com>
1 parent e82995f commit 8c9eb99

5 files changed

Lines changed: 112 additions & 1 deletion

File tree

cranelift/codegen/src/isle_prelude.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ macro_rules! isle_common_prelude_methods {
109109
!x
110110
}
111111

112+
#[inline]
113+
fn u64_eq(&mut self, x: u64, y: u64) -> u64 {
114+
u64::from(x == y)
115+
}
116+
112117
#[inline]
113118
fn u64_is_zero(&mut self, value: u64) -> bool {
114119
0 == value

cranelift/codegen/src/opts/algebraic.isle

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,33 @@
138138
(rule (simplify (bnot ty (band t x y)))
139139
(bor ty (bnot ty x) (bnot ty y)))
140140

141+
;; `or(and(x, y), not(y)) == or(x, not(y))`
142+
(rule (simplify (bor ty
143+
(band ty x y)
144+
z @ (bnot ty y)))
145+
(bor ty x z))
146+
;; Duplicate the rule but swap the `bor` operands because `bor` is
147+
;; commutative. We could, of course, add a `simplify` rule to do the commutative
148+
;; swap for all `bor`s but this will bloat the e-graph with many e-nodes. It is
149+
;; cheaper to have additional rules, rather than additional e-nodes, because we
150+
;; amortize their cost via ISLE's smart codegen.
151+
(rule (simplify (bor ty
152+
z @ (bnot ty y)
153+
(band ty x y)))
154+
(bor ty x z))
155+
156+
;; `or(and(x, y), not(y)) == or(x, not(y))` specialized for constants, since
157+
;; otherwise we may not know that `z == not(y)` since we don't generally expand
158+
;; constants in the e-graph.
159+
;;
160+
;; (No need to duplicate for commutative `bor` for this constant version because
161+
;; we move constants to the right.)
162+
(rule (simplify (bor ty
163+
(band ty x (iconst ty (u64_from_imm64 y)))
164+
z @ (iconst ty (u64_from_imm64 zk))))
165+
(if (u64_eq zk (u64_not y)))
166+
(bor ty x z))
167+
141168
;; x*2 == 2*x == x+x.
142169
(rule (simplify (imul ty x (iconst _ (simm32 2))))
143170
(iadd ty x x))

cranelift/codegen/src/prelude.isle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@
141141
(decl pure u64_not (u64) u64)
142142
(extern constructor u64_not u64_not)
143143

144+
(decl pure u64_eq (u64 u64) u64)
145+
(extern constructor u64_eq u64_eq)
146+
144147
(decl pure u64_sextend_u32 (u64) u64)
145148
(extern constructor u64_sextend_u32 u64_sextend_u32)
146149

cranelift/filetests/filetests/egraph/algebraic.clif

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ block0(v0: i32):
4040
return v3
4141
; check: v4 = iconst.i32 0xffff_ffe0
4242
; check: v5 = band v0, v4
43-
; return v5
43+
; check: return v5
4444
}
4545

4646
function %unsigned_shift_right_shift_left_i64(i64) -> i64 {
@@ -86,3 +86,45 @@ block0(v0: i64):
8686
; check: v5 = band v0, v4
8787
; return v5
8888
}
89+
90+
function %or_and_y_with_not_y(i8, i8) -> i8 {
91+
block0(v0: i8, v1: i8):
92+
v2 = band v0, v1
93+
v3 = bnot v1
94+
v4 = bor v2, v3
95+
return v4
96+
; check: v5 = bor v0, v3
97+
; check: return v5
98+
}
99+
100+
function %or_and_constant_with_not_constant(i8) -> i8 {
101+
block0(v0: i8):
102+
v1 = iconst.i8 -4
103+
v2 = band v0, v1
104+
v3 = iconst.i8 3
105+
v4 = bor v2, v3
106+
return v4
107+
; check: v5 = bor v0, v3
108+
; check: return v5
109+
}
110+
111+
function %or_and_y_with_not_y(i8, i8) -> i8 {
112+
block0(v0: i8, v1: i8):
113+
v2 = band v0, v1
114+
v3 = bnot v1
115+
v4 = bor v3, v2
116+
return v4
117+
; check: v5 = bor v0, v3
118+
; check: return v5
119+
}
120+
121+
function %or_and_constant_with_not_constant(i8) -> i8 {
122+
block0(v0: i8):
123+
v1 = iconst.i8 -4
124+
v2 = band v0, v1
125+
v3 = iconst.i8 3
126+
v4 = bor v3, v2
127+
return v4
128+
; check: v6 = bor v0, v3
129+
; check: return v6
130+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
;; Test the rewrite: `or(and(x, y), not(y)) => or(x, not(y))`
2+
3+
test interpret
4+
test run
5+
target aarch64
6+
target x86_64
7+
target riscv64
8+
target s390x
9+
10+
function %or_and_y_with_not_y(i8, i8) -> i8 {
11+
block0(v0: i8, v1: i8):
12+
v2 = band v0, v1
13+
v3 = bnot v1
14+
v4 = bor v2, v3
15+
return v4
16+
}
17+
; run: %or_and_y_with_not_y(0xff, 0x0a) == 0xff
18+
; run: %or_and_y_with_not_y(0xff, 0xb0) == 0xff
19+
; run: %or_and_y_with_not_y(0xaa, 0x0a) == 0xff
20+
; run: %or_and_y_with_not_y(0xaa, 0xb0) == 0xef
21+
; run: %or_and_y_with_not_y(0x00, 0x0a) == 0xf5
22+
; run: %or_and_y_with_not_y(0x00, 0xb0) == 0x4f
23+
24+
function %or_and_constant_with_not_constant(i8) -> i8 {
25+
block0(v0: i8):
26+
v1 = iconst.i8 -4
27+
v2 = band v0, v1
28+
v3 = iconst.i8 3
29+
v4 = bor v2, v3
30+
return v4
31+
}
32+
; run: %or_and_constant_with_not_constant(0xff) == 0xff
33+
; run: %or_and_constant_with_not_constant(0xaa) == 0xab
34+
; run: %or_and_constant_with_not_constant(0x00) == 0x03

0 commit comments

Comments
 (0)