Skip to content

Commit 7324037

Browse files
committed
fix MIN / -1 cprop and add negative tests for things simplify_skeleton cannot handle yet
1 parent d71f7d6 commit 7324037

File tree

4 files changed

+85
-11
lines changed

4 files changed

+85
-11
lines changed

cranelift/codegen/src/isle_prelude.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,25 @@ macro_rules! isle_common_prelude_methods {
105105
}
106106

107107
#[inline]
108-
fn u64_sdiv(&mut self, x: u64, y: u64) -> Option<u64> {
109-
let x = x as i64;
110-
let y = y as i64;
111-
x.checked_div(y).map(|d| d as u64)
108+
fn imm64_sdiv(&mut self, ty: Type, x: Imm64, y: Imm64) -> Option<Imm64> {
109+
// Sign extend `x` and `y`.
110+
let shift = u32::checked_sub(64, ty.bits()).unwrap_or(0);
111+
let x = (x.bits() << shift) >> shift;
112+
let y = (y.bits() << shift) >> shift;
113+
114+
// NB: We can't rely on `checked_div` to detect `ty::MIN / -1`
115+
// (which overflows and should trap) because we are working with
116+
// `i64` values here, and `i32::MIN != i64::MIN`, for
117+
// example. Therefore, we have to explicitly check for this case
118+
// ourselves.
119+
let min = ((self.ty_smin(ty) as i64) << shift) >> shift;
120+
if x == min && y == -1 {
121+
return None;
122+
}
123+
124+
let ty_mask = self.ty_mask(ty) as i64;
125+
let result = x.checked_div(y)? & ty_mask;
126+
Some(Imm64::new(result))
112127
}
113128

114129
#[inline]

cranelift/codegen/src/opts/cprop.isle

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
(subsume (iconst ty (imm64_masked ty (u64_mul k1 k2)))))
2020

2121
(rule (simplify_skeleton
22-
(sdiv (iconst_s ty k1)
23-
(iconst_s ty k2)))
24-
(if-let d (u64_sdiv (i64_as_u64 k1) (i64_as_u64 k2)))
25-
(iconst ty (imm64_masked ty d)))
22+
(sdiv (iconst ty k1)
23+
(iconst _ k2)))
24+
(if-let d (imm64_sdiv ty k1 k2))
25+
(iconst ty d))
2626

2727
(rule (simplify_skeleton
2828
(udiv (iconst_u ty k1)

cranelift/codegen/src/prelude.isle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,6 @@
228228
(decl pure u64_mul (u64 u64) u64)
229229
(extern constructor u64_mul u64_mul)
230230

231-
(decl pure partial u64_sdiv (u64 u64) u64)
232-
(extern constructor u64_sdiv u64_sdiv)
233-
234231
(decl pure partial u64_udiv (u64 u64) u64)
235232
(extern constructor u64_udiv u64_udiv)
236233

@@ -246,6 +243,9 @@
246243
(decl pure u64_shl (u64 u64) u64)
247244
(extern constructor u64_shl u64_shl)
248245

246+
(decl pure partial imm64_sdiv (Type Imm64 Imm64) Imm64)
247+
(extern constructor imm64_sdiv imm64_sdiv)
248+
249249
(decl pure imm64_shl (Type Imm64 Imm64) Imm64)
250250
(extern constructor imm64_shl imm64_shl)
251251

cranelift/filetests/filetests/egraph/skeleton.clif

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,62 @@ block0(v0: i32):
8989
return v2
9090
}
9191
; check: return v0
92+
93+
;;;;;;;;;; Tests for `simplify_skeleton` TODOs ;;;;;;;;;;;;
94+
;;
95+
;; What follows are tests for patterns that `simplify_skeleton` *should* clean
96+
;; up, but is unable to at this moment in time.
97+
98+
function %int_min_sdiv_neg_one() -> i32 {
99+
block0():
100+
v0 = iconst.i32 0x80000000
101+
v1 = iconst.i32 -1
102+
v2 = sdiv v0, v1
103+
return v2
104+
}
105+
; check: v2 = sdiv v0, v1
106+
; nextln: return v2
107+
108+
function %sdiv_zero(i32) -> i32 {
109+
block0(v0: i32):
110+
v1 = iconst.i32 0
111+
v2 = sdiv v0, v1
112+
return v2
113+
}
114+
; check: v2 = sdiv v0, v1
115+
; nextln: return v2
116+
117+
function %udiv_zero(i32) -> i32 {
118+
block0(v0: i32):
119+
v1 = iconst.i32 0
120+
v2 = udiv v0, v1
121+
return v2
122+
}
123+
; check: v2 = udiv v0, v1
124+
; nextln: return v2
125+
126+
function %always_trapping_trapz() -> i32 {
127+
block0:
128+
v0 = iconst.i32 0
129+
trapz v0, user42
130+
return v0
131+
}
132+
; check: trapz v0, user42
133+
134+
function %always_trapping_trapnz() -> i32 {
135+
block0:
136+
v0 = iconst.i32 1
137+
trapnz v0, user42
138+
return v0
139+
}
140+
; check: trapnz v0, user42
141+
142+
function %always_trapping_uadd_overflow_trap() -> i32 {
143+
block0:
144+
v0 = iconst.i32 0xffffffff
145+
v1 = iconst.i32 1
146+
v2 = uadd_overflow_trap v0, v1, user42
147+
return v2
148+
}
149+
; check: v2 = uadd_overflow_trap v0, v1, user42
150+
; nextln: return v2

0 commit comments

Comments
 (0)