Generalize u/sextend constant folding to all types (#5706)

Also move these optimization rules to cprop.isle; it's where all the
other similar rules are.

Like the other cprop rules, these can subsume any other rules. We can't
do better than reducing an expression to a constant.

The new i64_sextend_imm64 and u64_uextend_imm64 constructors are useful
helpers to clean up other code. I applied them to `imm64_icmp` while I
was here, as well as using the existing `ty_mask` helper to clean up
`imm64_masked`.
This commit is contained in:
Jamey Sharp
2023-02-03 17:29:21 -08:00
committed by GitHub
parent 331bc281a1
commit 97381792ac
4 changed files with 30 additions and 35 deletions

View File

@@ -140,33 +140,33 @@ macro_rules! isle_common_prelude_methods {
} }
#[inline] #[inline]
fn u64_sextend_u32(&mut self, x: u64) -> u64 { fn i64_sextend_imm64(&mut self, ty: Type, mut x: Imm64) -> i64 {
x as u32 as i32 as i64 as u64 x.sign_extend_from_width(ty.bits());
x.bits()
} }
#[inline] #[inline]
fn u64_uextend_u32(&mut self, x: u64) -> u64 { fn u64_uextend_imm64(&mut self, ty: Type, x: Imm64) -> u64 {
x & 0xffff_ffff (x.bits() as u64) & self.ty_mask(ty)
} }
#[inline] #[inline]
fn imm64_icmp(&mut self, ty: Type, cc: &IntCC, x: Imm64, y: Imm64) -> Imm64 { fn imm64_icmp(&mut self, ty: Type, cc: &IntCC, x: Imm64, y: Imm64) -> Imm64 {
let shift = u32::checked_sub(64, ty.bits()).unwrap_or(0); let ux = self.u64_uextend_imm64(ty, x);
let mask = u64::MAX >> shift; let uy = self.u64_uextend_imm64(ty, y);
let x = (x.bits() as u64) & mask; let sx = self.i64_sextend_imm64(ty, x);
let y = (y.bits() as u64) & mask; let sy = self.i64_sextend_imm64(ty, y);
let sext = |v| ((v << shift) as i64) >> shift;
let result = match cc { let result = match cc {
IntCC::Equal => x == y, IntCC::Equal => ux == uy,
IntCC::NotEqual => x != y, IntCC::NotEqual => ux != uy,
IntCC::UnsignedGreaterThanOrEqual => x >= y, IntCC::UnsignedGreaterThanOrEqual => ux >= uy,
IntCC::UnsignedGreaterThan => x > y, IntCC::UnsignedGreaterThan => ux > uy,
IntCC::UnsignedLessThanOrEqual => x <= y, IntCC::UnsignedLessThanOrEqual => ux <= uy,
IntCC::UnsignedLessThan => x < y, IntCC::UnsignedLessThan => ux < uy,
IntCC::SignedGreaterThanOrEqual => sext(x) >= sext(y), IntCC::SignedGreaterThanOrEqual => sx >= sy,
IntCC::SignedGreaterThan => sext(x) > sext(y), IntCC::SignedGreaterThan => sx > sy,
IntCC::SignedLessThanOrEqual => sext(x) <= sext(y), IntCC::SignedLessThanOrEqual => sx <= sy,
IntCC::SignedLessThan => sext(x) < sext(y), IntCC::SignedLessThan => sx < sy,
}; };
Imm64::new(result.into()) Imm64::new(result.into())
} }
@@ -586,12 +586,7 @@ macro_rules! isle_common_prelude_methods {
#[inline] #[inline]
fn imm64_masked(&mut self, ty: Type, x: u64) -> Imm64 { fn imm64_masked(&mut self, ty: Type, x: u64) -> Imm64 {
debug_assert!(ty.bits() <= 64); Imm64::new((x & self.ty_mask(ty)) as i64)
// Careful: we can't do `(1 << bits) - 1` because that
// would overflow for `bits == 64`. Instead,
// right-shift an all-ones mask.
let mask = u64::MAX >> (64 - ty.bits());
Imm64::new((x & mask) as i64)
} }
#[inline] #[inline]

View File

@@ -6,12 +6,6 @@
;; than a piece of the input or a new node that we construct; but we ;; than a piece of the input or a new node that we construct; but we
;; can freely rewrite e.g. `x+y-y` to `x`. ;; can freely rewrite e.g. `x+y-y` to `x`.
;; uextend/sextend of a constant.
(rule (simplify (uextend $I64 (iconst $I32 (u64_from_imm64 imm))))
(iconst $I64 (imm64 (u64_uextend_u32 imm))))
(rule (simplify (sextend $I64 (iconst $I32 (u64_from_imm64 imm))))
(iconst $I64 (imm64 (u64_sextend_u32 imm))))
;; x+0 == 0+x == x. ;; x+0 == 0+x == x.
(rule (simplify (iadd ty (rule (simplify (iadd ty
x x

View File

@@ -70,6 +70,12 @@
(iconst _ k2))) (iconst _ k2)))
(subsume (iconst ty (imm64_sshr ty k1 k2)))) (subsume (iconst ty (imm64_sshr ty k1 k2))))
(rule (simplify (uextend wide (iconst narrow imm)))
(subsume (iconst wide (imm64 (u64_uextend_imm64 narrow imm)))))
(rule (simplify (sextend wide (iconst narrow imm)))
(subsume (iconst wide (imm64_masked wide (i64_as_u64 (i64_sextend_imm64 narrow imm))))))
(rule (simplify (rule (simplify
(icmp result_ty (icmp result_ty
cc cc

View File

@@ -144,11 +144,11 @@
(decl pure u64_eq (u64 u64) bool) (decl pure u64_eq (u64 u64) bool)
(extern constructor u64_eq u64_eq) (extern constructor u64_eq u64_eq)
(decl pure u64_sextend_u32 (u64) u64) (decl pure i64_sextend_imm64 (Type Imm64) i64)
(extern constructor u64_sextend_u32 u64_sextend_u32) (extern constructor i64_sextend_imm64 i64_sextend_imm64)
(decl pure u64_uextend_u32 (u64) u64) (decl pure u64_uextend_imm64 (Type Imm64) u64)
(extern constructor u64_uextend_u32 u64_uextend_u32) (extern constructor u64_uextend_imm64 u64_uextend_imm64)
(decl pure imm64_icmp (Type IntCC Imm64 Imm64) Imm64) (decl pure imm64_icmp (Type IntCC Imm64 Imm64) Imm64)
(extern constructor imm64_icmp imm64_icmp) (extern constructor imm64_icmp imm64_icmp)