Skip to content

Commit 969fc63

Browse files
committed
[Cranelift] add type-aware rotate operations (bytecodealliance#12764)
* [Cranelift] add type-aware rotate operations * [Cranelift] add cprop rules for rotations * [Cranlift] assert datatype assumptions * add filetests for cprops
1 parent fe06ee7 commit 969fc63

7 files changed

Lines changed: 155 additions & 1 deletion

File tree

cranelift/codegen/src/isle_prelude.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,52 @@ macro_rules! isle_common_prelude_methods {
176176
Imm64::new((x >> y) & ty_mask)
177177
}
178178

179+
#[inline]
180+
fn imm64_rotl(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
181+
let bits = ty.bits();
182+
assert!(bits <= 64);
183+
// This holds for all Cranelift types ({u/i}{8,16,32,64})
184+
debug_assert!(bits.is_power_of_two());
185+
186+
let ty_mask = self.ty_mask(ty);
187+
let x = (x.bits() as u64) & ty_mask;
188+
189+
// Mask off any excess rotate bits so the rotate stays within `ty`.
190+
let shift_mask = bits - 1;
191+
let y = ((y.bits() as u64) & u64::from(shift_mask)) as u32;
192+
193+
// In Rust, x >> 64 or x << 64 panics.
194+
let result = if y == 0 {
195+
x
196+
} else {
197+
(x << y) | (x >> (u32::from(bits) - y))
198+
};
199+
200+
Imm64::new((result & ty_mask) as i64)
201+
}
202+
203+
#[inline]
204+
fn imm64_rotr(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
205+
let bits = ty.bits();
206+
assert!(bits <= 64);
207+
debug_assert!(bits.is_power_of_two());
208+
209+
let ty_mask = self.ty_mask(ty);
210+
let x = (x.bits() as u64) & ty_mask;
211+
212+
// Mask off any excess rotate bits so the rotate stays within `ty`.
213+
let shift_mask = bits - 1;
214+
let y = ((y.bits() as u64) & u64::from(shift_mask)) as u32;
215+
216+
let result = if y == 0 {
217+
x
218+
} else {
219+
(x >> y) | (x << (u32::from(bits) - y))
220+
};
221+
222+
Imm64::new((result & ty_mask) as i64)
223+
}
224+
179225
#[inline]
180226
fn i64_sextend_u64(&mut self, ty: Type, x: u64) -> i64 {
181227
let shift_amt = core::cmp::max(0, 64 - ty.bits());

cranelift/codegen/src/opts/cprop.isle

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,17 @@
9191
(iconst _ k2)))
9292
(subsume (iconst ty (imm64_sshr ty k1 k2))))
9393

94+
(rule (simplify (rotr (fits_in_64 ty)
95+
(iconst ty k1)
96+
(iconst _ k2)))
97+
(subsume (iconst ty (imm64_rotr ty k1 k2))))
98+
99+
(rule (simplify (rotl (fits_in_64 ty)
100+
(iconst ty k1)
101+
(iconst _ k2)))
102+
(subsume (iconst ty (imm64_rotl ty k1 k2))))
103+
104+
94105
(rule (simplify (ireduce narrow (iconst (fits_in_64 _) (u64_from_imm64 imm))))
95106
(subsume (iconst narrow (imm64_masked narrow imm))))
96107

cranelift/codegen/src/opts/shifts.isle

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,10 @@
266266
(rule (simplify (rotl ty (rotr ty x y @ (value_type kty)) z @ (value_type kty)))
267267
(rotr ty x (isub_uextend y z)))
268268

269+
(rule
270+
(simplify (rotr ty (iconst ty p) (select ty x (iconst ty y) (iconst ty z))))
271+
(select ty x (iconst ty (imm64_rotr ty p y)) (iconst ty (imm64_rotr ty p z))))
272+
269273
;; Convert shifts into rotates. We always normalize into a rotate left.
270274
;;
271275
;; (bor (ishl x k1) (ushr x k2)) == (rotl x k1) if k2 == ty_bits - k1
@@ -311,4 +315,3 @@
311315
(rule (simplify (iadd ty (ishl ty x z) (ishl ty y z))) (ishl ty (iadd ty x y) z))
312316

313317
(rule (simplify (ushr ty (band ty (ishl ty x y) z) y)) (band ty x (ushr ty z y)))
314-

cranelift/codegen/src/prelude.isle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@
109109
(decl pure imm64_sshr (Type Imm64 Imm64) Imm64)
110110
(extern constructor imm64_sshr imm64_sshr)
111111

112+
(decl pure imm64_rotl (Type Imm64 Imm64) Imm64)
113+
(extern constructor imm64_rotl imm64_rotl)
114+
115+
(decl pure imm64_rotr (Type Imm64 Imm64) Imm64)
116+
(extern constructor imm64_rotr imm64_rotr)
117+
112118
;; Sign extends a u64 from ty bits up to 64bits
113119
(decl pure i64_sextend_u64 (Type u64) i64)
114120
(extern constructor i64_sextend_u64 i64_sextend_u64)

cranelift/filetests/filetests/egraph/cprop.clif

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,55 @@ block0:
158158
; check: v3 = iconst.i16 -4
159159
; check: return v3
160160

161+
;; 0xf0 == 0b00001111
162+
function %rotr() -> i8 {
163+
block0:
164+
v0 = iconst.i8 0x0f
165+
v1 = iconst.i8 2
166+
v2 = rotr v0, v1
167+
return v2
168+
}
169+
170+
;; 0b11000011 == -61
171+
; check: v3 = iconst.i8 -61
172+
; check: return v3
173+
174+
function %rotr_i16() -> i16 {
175+
block0:
176+
v0 = iconst.i16 0x0f
177+
v1 = iconst.i8 2
178+
v2 = rotr v0, v1
179+
return v2
180+
}
181+
182+
;; 0b1100000000000011 == -16381
183+
; check: v3 = iconst.i16 -16381
184+
; check: return v3
185+
186+
function %rotl() -> i8 {
187+
block0:
188+
v0 = iconst.i8 0xf0
189+
v1 = iconst.i8 2
190+
v2 = rotl v0, v1
191+
return v2
192+
}
193+
194+
;; 0b11000011 == -61
195+
; check: v3 = iconst.i8 -61
196+
; check: return v3
197+
198+
function %rotl_i16() -> i16 {
199+
block0:
200+
v0 = iconst.i16 0xf000
201+
v1 = iconst.i8 2
202+
v2 = rotl v0, v1
203+
return v2
204+
}
205+
206+
;; 0b11000011 == -61
207+
; check: v3 = iconst.i16 -16381
208+
; check: return v3
209+
161210
function %icmp_eq_i32() -> i8 {
162211
block0:
163212
v0 = iconst.i32 1

cranelift/filetests/filetests/egraph/shifts.clif

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,21 @@ block0(v0: i8, v1: i8):
758758

759759
; check: return v0
760760

761+
function %rotr_iconst_select_iconsts(i8) -> i8 {
762+
block0(v0: i8):
763+
v1 = iconst.i8 1
764+
v2 = iconst.i8 1
765+
v3 = iconst.i8 2
766+
v4 = select v0, v2, v3
767+
v5 = rotr.i8 v1, v4
768+
return v5
769+
}
770+
771+
; check: v6 = iconst.i8 -128
772+
; check: v7 = iconst.i8 64
773+
; check: v8 = select v0, v6, v7
774+
; check: return v8
775+
761776
function %shifts_to_rotl(i64) -> i64 {
762777
block0(v0: i64):
763778
v1 = iconst.i16 3

cranelift/filetests/filetests/runtests/rotr.clif

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,30 @@ block0(v0: i8, v1: i8):
231231
; run: %rotr_i8_i8(0xe0, 65) == 0x70
232232
; run: %rotr_i8_i8(0xe0, 66) == 0x38
233233

234+
function %rotr_iconst_select_iconsts_i8(i8) -> i8 {
235+
block0(v0: i8):
236+
v1 = iconst.i8 1
237+
v2 = iconst.i8 1
238+
v3 = iconst.i8 2
239+
v4 = select v0, v2, v3
240+
v5 = rotr.i8 v1, v4
241+
return v5
242+
}
243+
; run: %rotr_iconst_select_iconsts_i8(0) == 0x40
244+
; run: %rotr_iconst_select_iconsts_i8(1) == 0x80
245+
246+
function %rotr_iconst_select_iconsts_i32(i32) -> i32 {
247+
block0(v0: i32):
248+
v1 = iconst.i32 1
249+
v2 = iconst.i32 1
250+
v3 = iconst.i32 2
251+
v4 = select v0, v2, v3
252+
v5 = rotr.i32 v1, v4
253+
return v5
254+
}
255+
; run: %rotr_iconst_select_iconsts_i32(0) == 0x40000000
256+
; run: %rotr_iconst_select_iconsts_i32(1) == 0x80000000
257+
234258

235259

236260
;; This is a regression test for rotates on x64

0 commit comments

Comments
 (0)