Skip to content

Commit c6a9443

Browse files
authored
[Cranelift] add type-aware imm64 constant folding operations (#12826)
* [Cranelift] add imm64 operations * [Cranelift] add imm64 partial ops * [Cranelift] implement udiv * [Cranelift] implement urem and use imm64 ops * [Cranelift] use imm64 ops * [Cranelift] `(-X) * C = X * (-C)` * [Cranelift] update register numbering in filetests
1 parent 008fe51 commit c6a9443

File tree

7 files changed

+254
-73
lines changed

7 files changed

+254
-73
lines changed

cranelift/codegen/src/isle_prelude.rs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,17 @@ macro_rules! isle_common_prelude_methods {
7474
Some(Imm64::new(result).mask_to_width(type_width))
7575
}
7676

77+
#[inline]
78+
fn imm64_udiv(&mut self, ty: Type, x: Imm64, y: Imm64) -> Option<Imm64> {
79+
let type_width = ty.bits();
80+
assert!(type_width <= 64);
81+
let mask = self.ty_mask(ty);
82+
let x = (x.bits() as u64) & mask;
83+
let y = (y.bits() as u64) & mask;
84+
let result = x.checked_div(y)?;
85+
Some(Imm64::new(result as i64).mask_to_width(type_width))
86+
}
87+
7788
#[inline]
7889
fn imm64_srem(&mut self, ty: Type, x: Imm64, y: Imm64) -> Option<Imm64> {
7990
// Sign extend `x` and `y`.
@@ -89,6 +100,125 @@ macro_rules! isle_common_prelude_methods {
89100
Some(Imm64::new(result).mask_to_width(type_width))
90101
}
91102

103+
#[inline]
104+
fn imm64_urem(&mut self, ty: Type, x: Imm64, y: Imm64) -> Option<Imm64> {
105+
let type_width = ty.bits();
106+
assert!(type_width <= 64);
107+
let mask = self.ty_mask(ty);
108+
let x = (x.bits() as u64) & mask;
109+
let y = (y.bits() as u64) & mask;
110+
let result = x.checked_rem(y)?;
111+
Some(Imm64::new(result as i64).mask_to_width(type_width))
112+
}
113+
114+
#[inline]
115+
fn imm64_add(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
116+
let ty_mask = self.ty_mask(ty) as i64;
117+
Imm64::new(x.bits().wrapping_add(y.bits()) & ty_mask)
118+
}
119+
120+
#[inline]
121+
fn imm64_sub(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
122+
let ty_mask = self.ty_mask(ty) as i64;
123+
Imm64::new(x.bits().wrapping_sub(y.bits()) & ty_mask)
124+
}
125+
126+
#[inline]
127+
fn imm64_mul(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
128+
let ty_mask = self.ty_mask(ty) as i64;
129+
Imm64::new(x.bits().wrapping_mul(y.bits()) & ty_mask)
130+
}
131+
132+
#[inline]
133+
fn imm64_and(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
134+
let ty_mask = self.ty_mask(ty) as i64;
135+
Imm64::new((x.bits() & y.bits()) & ty_mask)
136+
}
137+
138+
#[inline]
139+
fn imm64_or(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
140+
let ty_mask = self.ty_mask(ty) as i64;
141+
Imm64::new((x.bits() | y.bits()) & ty_mask)
142+
}
143+
144+
#[inline]
145+
fn imm64_xor(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
146+
let ty_mask = self.ty_mask(ty) as i64;
147+
Imm64::new((x.bits() ^ y.bits()) & ty_mask)
148+
}
149+
150+
#[inline]
151+
fn imm64_not(&mut self, ty: Type, x: Imm64) -> Imm64 {
152+
let ty_mask = self.ty_mask(ty) as i64;
153+
Imm64::new((!x.bits()) & ty_mask)
154+
}
155+
156+
#[inline]
157+
fn imm64_neg(&mut self, ty: Type, x: Imm64) -> Imm64 {
158+
let ty_mask = self.ty_mask(ty) as i64;
159+
Imm64::new(x.bits().wrapping_neg() & ty_mask)
160+
}
161+
162+
#[inline]
163+
fn imm64_abs(&mut self, ty: Type, x: Imm64) -> Option<Imm64> {
164+
let type_width = ty.bits();
165+
assert!(type_width <= 64);
166+
167+
let x = x.sign_extend_from_width(type_width).bits();
168+
let shift = 64 - type_width;
169+
let min = ((self.ty_smin(ty) as i64) << shift) >> shift;
170+
if x == min {
171+
return None;
172+
}
173+
174+
Some(Imm64::new(x.abs()).mask_to_width(type_width))
175+
}
176+
177+
#[inline]
178+
fn imm64_ilog2(&mut self, ty: Type, x: Imm64) -> Option<Imm64> {
179+
let type_width = ty.bits();
180+
assert!(type_width <= 64);
181+
let masked = (x.bits() as u64) & self.ty_mask(ty);
182+
let result = masked.checked_ilog2()?;
183+
Some(Imm64::new(result.into()))
184+
}
185+
186+
#[inline]
187+
fn imm64_umin(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
188+
let ty_mask = self.ty_mask(ty);
189+
let x_u = (x.bits() as u64) & ty_mask;
190+
let y_u = (y.bits() as u64) & ty_mask;
191+
Imm64::new((if x_u <= y_u { x_u } else { y_u }) as i64)
192+
}
193+
194+
#[inline]
195+
fn imm64_umax(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
196+
let ty_mask = self.ty_mask(ty);
197+
let x_u = (x.bits() as u64) & ty_mask;
198+
let y_u = (y.bits() as u64) & ty_mask;
199+
Imm64::new((if x_u >= y_u { x_u } else { y_u }) as i64)
200+
}
201+
202+
#[inline]
203+
fn imm64_smin(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
204+
let type_width = ty.bits();
205+
assert!(type_width <= 64);
206+
let x_s = x.sign_extend_from_width(type_width).bits();
207+
let y_s = y.sign_extend_from_width(type_width).bits();
208+
let selected = if x_s <= y_s { x_s } else { y_s };
209+
Imm64::new(selected).mask_to_width(type_width)
210+
}
211+
212+
#[inline]
213+
fn imm64_smax(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
214+
let type_width = ty.bits();
215+
assert!(type_width <= 64);
216+
let x_s = x.sign_extend_from_width(type_width).bits();
217+
let y_s = y.sign_extend_from_width(type_width).bits();
218+
let selected = if x_s >= y_s { x_s } else { y_s };
219+
Imm64::new(selected).mask_to_width(type_width)
220+
}
221+
92222
#[inline]
93223
fn imm64_shl(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
94224
// Mask off any excess shift bits.

cranelift/codegen/src/opts/arithmetic.isle

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,10 +226,10 @@
226226
;; or(x, C) + (-C) --> and(x, ~C)
227227
(rule
228228
(simplify (iadd ty
229-
(bor ty x (iconst_s ty n))
230-
(iconst_s ty m)))
231-
(if-let m (i64_checked_neg n))
232-
(band ty x (iconst ty (imm64_masked ty (i64_cast_unsigned (i64_not n))))))
229+
(bor ty x (iconst ty n))
230+
(iconst ty m)))
231+
(if-let m (imm64_neg ty n))
232+
(band ty x (iconst ty (imm64_not ty n))))
233233

234234
;; (x + y) - (x | y) --> x & y
235235
(rule (simplify (isub ty (iadd ty x y) (bor ty x y))) (band ty x y))
@@ -500,3 +500,6 @@
500500
(rule (simplify (ugt ty x (umax ty y x))) (iconst_u ty 0))
501501
(rule (simplify (ult ty (umax ty x y) x)) (iconst_u ty 0))
502502
(rule (simplify (ult ty (umax ty y x) x)) (iconst_u ty 0))
503+
504+
;; (-X) * C = X * (-C)
505+
(rule (simplify (imul (fits_in_64 ty) (ineg ty x) (iconst ty y))) (imul ty x (iconst ty (imm64_neg ty y))))

cranelift/codegen/src/opts/cprop.isle

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,21 @@
1313

1414
(rule (simplify
1515
(iadd (fits_in_64 ty)
16-
(iconst ty (u64_from_imm64 k1))
17-
(iconst ty (u64_from_imm64 k2))))
18-
(subsume (iconst ty (imm64_masked ty (u64_wrapping_add k1 k2)))))
16+
(iconst ty k1)
17+
(iconst ty k2)))
18+
(subsume (iconst ty (imm64_add ty k1 k2))))
1919

2020
(rule (simplify
2121
(isub (fits_in_64 ty)
22-
(iconst ty (u64_from_imm64 k1))
23-
(iconst ty (u64_from_imm64 k2))))
24-
(subsume (iconst ty (imm64_masked ty (u64_wrapping_sub k1 k2)))))
22+
(iconst ty k1)
23+
(iconst ty k2)))
24+
(subsume (iconst ty (imm64_sub ty k1 k2))))
2525

2626
(rule (simplify
2727
(imul (fits_in_64 ty)
28-
(iconst ty (u64_from_imm64 k1))
29-
(iconst ty (u64_from_imm64 k2))))
30-
(subsume (iconst ty (imm64_masked ty (u64_wrapping_mul k1 k2)))))
28+
(iconst ty k1)
29+
(iconst ty k2)))
30+
(subsume (iconst ty (imm64_mul ty k1 k2))))
3131

3232
(rule (simplify_skeleton
3333
(sdiv (iconst ty k1)
@@ -42,39 +42,39 @@
4242
(iconst ty d))
4343

4444
(rule (simplify_skeleton
45-
(udiv (iconst_u ty k1)
46-
(iconst_u ty k2)))
47-
(if-let d (u64_checked_div k1 k2))
48-
(iconst ty (imm64_masked ty d)))
45+
(udiv (iconst ty k1)
46+
(iconst ty k2)))
47+
(if-let d (imm64_udiv ty k1 k2))
48+
(iconst ty d))
4949

5050
(rule (simplify_skeleton
51-
(urem (iconst_u ty k1)
52-
(iconst_u ty k2)))
53-
(if-let d (u64_checked_rem k1 k2))
54-
(iconst ty (imm64_masked ty d)))
51+
(urem (iconst ty k1)
52+
(iconst ty k2)))
53+
(if-let d (imm64_urem ty k1 k2))
54+
(iconst ty d))
5555

5656
(rule (simplify
5757
(bor (fits_in_64 ty)
58-
(iconst ty (u64_from_imm64 k1))
59-
(iconst ty (u64_from_imm64 k2))))
60-
(subsume (iconst ty (imm64_masked ty (u64_or k1 k2)))))
58+
(iconst ty k1)
59+
(iconst ty k2)))
60+
(subsume (iconst ty (imm64_or ty k1 k2))))
6161

6262
(rule (simplify
6363
(band (fits_in_64 ty)
64-
(iconst ty (u64_from_imm64 k1))
65-
(iconst ty (u64_from_imm64 k2))))
66-
(subsume (iconst ty (imm64_masked ty (u64_and k1 k2)))))
64+
(iconst ty k1)
65+
(iconst ty k2)))
66+
(subsume (iconst ty (imm64_and ty k1 k2))))
6767

6868
(rule (simplify
6969
(bxor (fits_in_64 ty)
70-
(iconst ty (u64_from_imm64 k1))
71-
(iconst ty (u64_from_imm64 k2))))
72-
(subsume (iconst ty (imm64_masked ty (u64_xor k1 k2)))))
70+
(iconst ty k1)
71+
(iconst ty k2)))
72+
(subsume (iconst ty (imm64_xor ty k1 k2))))
7373

7474
(rule (simplify
7575
(bnot (fits_in_64 ty)
76-
(iconst ty (u64_from_imm64 k))))
77-
(subsume (iconst ty (imm64_masked ty (u64_not k)))))
76+
(iconst ty k)))
77+
(subsume (iconst ty (imm64_not ty k))))
7878

7979
(rule (simplify (ishl (fits_in_64 ty)
8080
(iconst ty k1)
@@ -166,25 +166,25 @@
166166
;; - (add (sub x k1) k2) -> (add x (sub k2 k1))
167167
;; - (add (sub k1 x) k2) -> (sub (add k1 k2) x)
168168
(rule (simplify (isub ty
169-
(isub ty x (iconst ty (u64_from_imm64 k1)))
170-
(iconst ty (u64_from_imm64 k2))))
171-
(isub ty x (iconst ty (imm64_masked ty (u64_wrapping_add k1 k2)))))
169+
(isub ty x (iconst ty k1))
170+
(iconst ty k2)))
171+
(isub ty x (iconst ty (imm64_add ty k1 k2))))
172172
(rule (simplify (isub ty
173-
(isub ty (iconst ty (u64_from_imm64 k1)) x)
174-
(iconst ty (u64_from_imm64 k2))))
175-
(isub ty (iconst ty (imm64_masked ty (u64_wrapping_sub k1 k2))) x))
173+
(isub ty (iconst ty k1) x)
174+
(iconst ty k2)))
175+
(isub ty (iconst ty (imm64_sub ty k1 k2)) x))
176176
(rule (simplify (isub ty
177-
(iadd ty x (iconst ty (u64_from_imm64 k1)))
178-
(iconst ty (u64_from_imm64 k2))))
179-
(isub ty x (iconst ty (imm64_masked ty (u64_wrapping_sub k2 k1)))))
177+
(iadd ty x (iconst ty k1))
178+
(iconst ty k2)))
179+
(isub ty x (iconst ty (imm64_sub ty k2 k1))))
180180
(rule (simplify (iadd ty
181-
(isub ty x (iconst ty (u64_from_imm64 k1)))
182-
(iconst ty (u64_from_imm64 k2))))
183-
(iadd ty x (iconst ty (imm64_masked ty (u64_wrapping_sub k2 k1)))))
181+
(isub ty x (iconst ty k1))
182+
(iconst ty k2)))
183+
(iadd ty x (iconst ty (imm64_sub ty k2 k1))))
184184
(rule (simplify (iadd ty
185-
(isub ty (iconst ty (u64_from_imm64 k1)) x)
186-
(iconst ty (u64_from_imm64 k2))))
187-
(isub ty (iconst ty (imm64_masked ty (u64_wrapping_add k1 k2))) x))
185+
(isub ty (iconst ty k1) x)
186+
(iconst ty k2)))
187+
(isub ty (iconst ty (imm64_add ty k1 k2)) x))
188188

189189
(rule (simplify
190190
(imul ty (imul ty x k1 @ (iconst ty _)) k2 @ (iconst ty _)))
@@ -231,7 +231,7 @@
231231
(rule (simplify (isub ty x (iconst_s ty k)))
232232
(if-let true (u64_lt (i64_cast_unsigned (i64_wrapping_neg k))
233233
(i64_cast_unsigned k)))
234-
(iadd ty x (iconst ty (imm64_masked ty (i64_cast_unsigned (i64_wrapping_neg k))))))
234+
(iadd ty x (iconst ty (imm64_neg ty (imm64 (i64_cast_unsigned k))))))
235235

236236
;; A splat of a constant can become a direct `vconst` with the appropriate bit
237237
;; pattern.

cranelift/codegen/src/opts/selects.isle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,10 @@
9494

9595
;; fold add-select to select-add
9696
(rule (simplify
97-
(iadd ty (select ty c (iconst_u ty x) (iconst_u ty y)) (iconst_u ty z)))
97+
(iadd ty (select ty c (iconst ty x) (iconst ty y)) (iconst ty z)))
9898
(select ty c
99-
(iconst ty (imm64_masked ty (u64_wrapping_add x z)))
100-
(iconst ty (imm64_masked ty (u64_wrapping_add y z)))))
99+
(iconst ty (imm64_add ty x z))
100+
(iconst ty (imm64_add ty y z))))
101101

102102
(rule (simplify (select ty d a (select ty d _ y))) (select ty d a y))
103103
(rule (simplify (select ty d (select ty d x _) a)) (select ty d x a))

cranelift/codegen/src/prelude.isle

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,57 @@
7373
(decl pure partial imm64_sdiv (Type Imm64 Imm64) Imm64)
7474
(extern constructor imm64_sdiv imm64_sdiv)
7575

76+
(decl pure partial imm64_udiv (Type Imm64 Imm64) Imm64)
77+
(extern constructor imm64_udiv imm64_udiv)
78+
7679
(decl pure partial imm64_srem (Type Imm64 Imm64) Imm64)
7780
(extern constructor imm64_srem imm64_srem)
7881

82+
(decl pure partial imm64_urem (Type Imm64 Imm64) Imm64)
83+
(extern constructor imm64_urem imm64_urem)
84+
85+
(decl pure imm64_add (Type Imm64 Imm64) Imm64)
86+
(extern constructor imm64_add imm64_add)
87+
88+
(decl pure imm64_sub (Type Imm64 Imm64) Imm64)
89+
(extern constructor imm64_sub imm64_sub)
90+
91+
(decl pure imm64_mul (Type Imm64 Imm64) Imm64)
92+
(extern constructor imm64_mul imm64_mul)
93+
94+
(decl pure imm64_and (Type Imm64 Imm64) Imm64)
95+
(extern constructor imm64_and imm64_and)
96+
97+
(decl pure imm64_or (Type Imm64 Imm64) Imm64)
98+
(extern constructor imm64_or imm64_or)
99+
100+
(decl pure imm64_xor (Type Imm64 Imm64) Imm64)
101+
(extern constructor imm64_xor imm64_xor)
102+
103+
(decl pure imm64_not (Type Imm64) Imm64)
104+
(extern constructor imm64_not imm64_not)
105+
106+
(decl pure imm64_neg (Type Imm64) Imm64)
107+
(extern constructor imm64_neg imm64_neg)
108+
109+
(decl pure partial imm64_abs (Type Imm64) Imm64)
110+
(extern constructor imm64_abs imm64_abs)
111+
112+
(decl pure partial imm64_ilog2 (Type Imm64) Imm64)
113+
(extern constructor imm64_ilog2 imm64_ilog2)
114+
115+
(decl pure imm64_umin (Type Imm64 Imm64) Imm64)
116+
(extern constructor imm64_umin imm64_umin)
117+
118+
(decl pure imm64_umax (Type Imm64 Imm64) Imm64)
119+
(extern constructor imm64_umax imm64_umax)
120+
121+
(decl pure imm64_smin (Type Imm64 Imm64) Imm64)
122+
(extern constructor imm64_smin imm64_smin)
123+
124+
(decl pure imm64_smax (Type Imm64 Imm64) Imm64)
125+
(extern constructor imm64_smax imm64_smax)
126+
79127
(decl pure imm64_shl (Type Imm64 Imm64) Imm64)
80128
(extern constructor imm64_shl imm64_shl)
81129

cranelift/filetests/filetests/egraph/issue-10409.clif

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ function u0:1(i64) -> i64 system_v {
2323
return v4
2424
}
2525

26-
; check: v5 = ireduce.i32 v1
27-
; next: v6 = uextend.i64 v5
28-
; next: return v6
26+
; check: v7 = ireduce.i32 v1
27+
; next: v8 = uextend.i64 v7
28+
; next: return v8

0 commit comments

Comments
 (0)