Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions cranelift/codegen/src/isle_prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,36 @@ macro_rules! isle_common_prelude_methods {
u64::MAX >> shift
}

#[inline]
fn ty_umin(&mut self, _ty: Type) -> u64 {
0
}

#[inline]
fn ty_umax(&mut self, ty: Type) -> u64 {
self.ty_mask(ty)
}

#[inline]
fn ty_smin(&mut self, ty: Type) -> u64 {
let ty_bits = ty.bits();
debug_assert_ne!(ty_bits, 0);
let shift = 64_u64
.checked_sub(ty_bits.into())
.expect("unimplemented for > 64 bits");
(i64::MIN as u64) >> shift
}

#[inline]
fn ty_smax(&mut self, ty: Type) -> u64 {
let ty_bits = ty.bits();
debug_assert_ne!(ty_bits, 0);
let shift = 64_u64
.checked_sub(ty_bits.into())
.expect("unimplemented for > 64 bits");
(i64::MAX as u64) >> shift
}

fn fits_in_16(&mut self, ty: Type) -> Option<Type> {
if ty.bits() <= 16 && !ty.is_dynamic_vector() {
Some(ty)
Expand Down
101 changes: 89 additions & 12 deletions cranelift/codegen/src/opts/algebraic.isle
Original file line number Diff line number Diff line change
Expand Up @@ -371,20 +371,97 @@
(iconst _ (u64_from_imm64 1))))
extend)

;; `x < 0` is always false for unsigned integers, and `x >= 0` is always true
;; for unsigned integers, along with their reversals.
;; ult(x, 0) == false.
(rule (simplify
(icmp (fits_in_64 (ty_int ty))
(IntCC.UnsignedLessThan)
_
(iconst _ (u64_from_imm64 0))))
(iconst ty (imm64 0)))
(icmp (fits_in_64 (ty_int bty)) (IntCC.UnsignedLessThan) x zero @ (iconst _ (u64_from_imm64 0))))
(subsume (iconst bty (imm64 0))))

;; ule(x, 0) == eq(x, 0)
(rule (simplify
(icmp (fits_in_64 (ty_int ty))
(IntCC.UnsignedGreaterThanOrEqual)
_
(iconst _ (u64_from_imm64 0))))
(iconst ty (imm64 1)))
(icmp (fits_in_64 (ty_int bty)) (IntCC.UnsignedLessThanOrEqual) x zero @ (iconst _ (u64_from_imm64 0))))
(icmp bty (IntCC.Equal) x zero))

;; ugt(x, 0) == ne(x, 0).
(rule (simplify
(icmp (fits_in_64 (ty_int bty)) (IntCC.UnsignedGreaterThan) x zero @ (iconst _ (u64_from_imm64 0))))
(icmp bty (IntCC.NotEqual) x zero))

;; uge(x, 0) == true.
(rule (simplify
(icmp (fits_in_64 (ty_int bty)) (IntCC.UnsignedGreaterThanOrEqual) x zero @ (iconst _ (u64_from_imm64 0))))
(subsume (iconst bty (imm64 1))))

;; ult(x, UMAX) == ne(x, UMAX).
(rule (simplify
(icmp (fits_in_64 (ty_int bty)) (IntCC.UnsignedLessThan) x umax @ (iconst cty (u64_from_imm64 y))))
(if-let $true (u64_eq y (ty_umax cty)))
(icmp bty (IntCC.NotEqual) x umax))

;; ule(x, UMAX) == true.
(rule (simplify
(icmp (fits_in_64 (ty_int bty)) (IntCC.UnsignedLessThanOrEqual) x umax @ (iconst cty (u64_from_imm64 y))))
(if-let $true (u64_eq y (ty_umax cty)))
(subsume (iconst bty (imm64 1))))

;; ugt(x, UMAX) == false.
(rule (simplify
(icmp (fits_in_64 (ty_int bty)) (IntCC.UnsignedGreaterThan) x umax @ (iconst cty (u64_from_imm64 y))))
(if-let $true (u64_eq y (ty_umax cty)))
(subsume (iconst bty (imm64 0))))

;; uge(x, UMAX) == eq(x, UMAX).
(rule (simplify
(icmp (fits_in_64 (ty_int bty)) (IntCC.UnsignedGreaterThanOrEqual) x umax @ (iconst cty (u64_from_imm64 y))))
(if-let $true (u64_eq y (ty_umax cty)))
(icmp bty (IntCC.Equal) x umax))

;; slt(x, SMIN) == false.
(rule (simplify
(icmp (fits_in_64 (ty_int bty)) (IntCC.SignedLessThan) x smin @ (iconst cty (u64_from_imm64 y))))
(if-let $true (u64_eq y (ty_smin cty)))
(subsume (iconst bty (imm64 0))))

;; sle(x, SMIN) == eq(x, SMIN).
(rule (simplify
(icmp (fits_in_64 (ty_int bty)) (IntCC.SignedLessThanOrEqual) x smin @ (iconst cty (u64_from_imm64 y))))
(if-let $true (u64_eq y (ty_smin cty)))
(icmp bty (IntCC.Equal) x smin))

;; sgt(x, SMIN) == ne(x, SMIN).
(rule (simplify
(icmp (fits_in_64 (ty_int bty)) (IntCC.SignedGreaterThan) x smin @ (iconst cty (u64_from_imm64 y))))
(if-let $true (u64_eq y (ty_smin cty)))
(icmp bty (IntCC.NotEqual) x smin))

;; sge(x, SMIN) == true.
(rule (simplify
(icmp (fits_in_64 (ty_int bty)) (IntCC.SignedGreaterThanOrEqual) x smin @ (iconst cty (u64_from_imm64 y))))
(if-let $true (u64_eq y (ty_smin cty)))
(subsume (iconst bty (imm64 1))))

;; slt(x, SMAX) == ne(x, SMAX).
(rule (simplify
(icmp (fits_in_64 (ty_int bty)) (IntCC.SignedLessThan) x smax @ (iconst cty (u64_from_imm64 y))))
(if-let $true (u64_eq y (ty_smax cty)))
(icmp bty (IntCC.NotEqual) x smax))

;; sle(x, SMAX) == true.
(rule (simplify
(icmp (fits_in_64 (ty_int bty)) (IntCC.SignedLessThanOrEqual) x smax @ (iconst cty (u64_from_imm64 y))))
(if-let $true (u64_eq y (ty_smax cty)))
(subsume (iconst bty (imm64 1))))

;; sgt(x, SMAX) == false.
(rule (simplify
(icmp (fits_in_64 (ty_int bty)) (IntCC.SignedGreaterThan) x smax @ (iconst cty (u64_from_imm64 y))))
(if-let $true (u64_eq y (ty_smax cty)))
(subsume (iconst bty (imm64 0))))

;; sge(x, SMAX) == eq(x, SMAX).
(rule (simplify
(icmp (fits_in_64 (ty_int bty)) (IntCC.SignedGreaterThanOrEqual) x smax @ (iconst cty (u64_from_imm64 y))))
(if-let $true (u64_eq y (ty_smax cty)))
(icmp bty (IntCC.Equal) x smax))

;; 32-bit integers zero-extended to 64-bit integers are never negative
(rule (simplify
Expand Down
17 changes: 17 additions & 0 deletions cranelift/codegen/src/prelude.isle
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,23 @@

(extern const $I32X4XN Type)

;; Get the unsigned minimum value for a given type.
;; This always zero, but is included for completeness.
(decl pure ty_umin (Type) u64)
(extern constructor ty_umin ty_umin)

;; Get the unsigned maximum value for a given type.
(decl pure ty_umax (Type) u64)
(extern constructor ty_umax ty_umax)

;; Get the signed minimum value for a given type.
(decl pure ty_smin (Type) u64)
(extern constructor ty_smin ty_smin)

;; Get the signed maximum value for a given type.
(decl pure ty_smax (Type) u64)
(extern constructor ty_smax ty_smax)

;; Get the bit width of a given type.
(decl pure ty_bits (Type) u8)
(extern constructor ty_bits ty_bits)
Expand Down
160 changes: 132 additions & 28 deletions cranelift/filetests/filetests/egraph/algebraic.clif
Original file line number Diff line number Diff line change
Expand Up @@ -402,45 +402,149 @@ block0(v1: i64, v2: i64):
; check: v4 = uextend.i64 v3
; check: return v4

function %ult_zero_always_false(i64) -> i8 {
block0(v1: i64):
v2 = iconst.i64 0
v3 = icmp ult v1, v2
return v3
function %icmp_ult_0(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0
v2 = icmp ult v0, v1
return v2
; check: v3 = iconst.i8 0
; check: return v3
}

; check: v4 = iconst.i8 0
; check: return v4
function %icmp_ule_0(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0
v2 = icmp ule v0, v1
return v2
; check: v3 = icmp eq v0, v1
; check: return v3
}

function %ugt_zero_always_false(i64) -> i8 {
block0(v1: i64):
v2 = iconst.i64 0
v3 = icmp ugt v2, v1
return v3
function %icmp_ugt_0(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0
v2 = icmp ugt v0, v1
return v2
; check: v3 = icmp ne v0, v1
; check: return v3
}

; check: v5 = iconst.i8 0
; check: return v5
function %icmp_uge_0(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0
v2 = icmp uge v0, v1
return v2
; check: v3 = iconst.i8 1
; check: return v3
}

function %uge_zero_always_false(i64) -> i8 {
block0(v1: i64):
v2 = iconst.i64 0
v3 = icmp uge v1, v2
return v3
function %icmp_ult_umax(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0xffff_ffff
v2 = icmp ult v0, v1
return v2
; check: v3 = icmp ne v0, v1
; check: return v3
}

; check: v4 = iconst.i8 1
; check: return v4
function %icmp_ule_umax(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0xffff_ffff
v2 = icmp ule v0, v1
return v2
; check: v3 = iconst.i8 1
; check: return v3
}

function %ule_zero_always_false(i64) -> i8 {
block0(v1: i64):
v2 = iconst.i64 0
v3 = icmp ule v2, v1
return v3
function %icmp_ugt_umax(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0xffff_ffff
v2 = icmp ugt v0, v1
return v2
; check: v3 = iconst.i8 0
; check: return v3
}

; check: v5 = iconst.i8 1
; check: return v5
function %icmp_uge_umax(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0xffff_ffff
v2 = icmp uge v0, v1
return v2
; check: v3 = icmp eq v0, v1
; check: return v3
}

function %icmp_slt_smin(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0x8000_0000
v2 = icmp slt v0, v1
return v2
; check: v3 = iconst.i8 0
; check: return v3
}

function %icmp_sle_smin(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0x8000_0000
v2 = icmp sle v0, v1
return v2
; check: v3 = icmp eq v0, v1
; check: return v3
}

function %icmp_sgt_smin(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0x8000_0000
v2 = icmp sgt v0, v1
return v2
; check: v3 = icmp ne v0, v1
; check: return v3
}

function %icmp_sge_smin(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0x8000_0000
v2 = icmp sge v0, v1
return v2
; check: v3 = iconst.i8 1
; check: return v3
}

function %icmp_slt_smax(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0x7FFF_FFFF
v2 = icmp slt v0, v1
return v2
; check: v3 = icmp ne v0, v1
; check: return v3
}

function %icmp_sle_smax(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0x7FFF_FFFF
v2 = icmp sle v0, v1
return v2
; check: v3 = iconst.i8 1
; check: return v3
}

function %icmp_sgt_smax(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0x7FFF_FFFF
v2 = icmp sgt v0, v1
return v2
; check: v3 = iconst.i8 0
; check: return v3
}

function %icmp_sge_smax(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0x7FFF_FFFF
v2 = icmp sge v0, v1
return v2
; check: v3 = icmp eq v0, v1
; check: return v3
}

function %extend_always_above_zero(i32) -> i8 {
block0(v1: i32):
Expand Down