Cranelift: Generalize (x << k) >> k optimization (#5746)

* Generalize unsigned `(x << k) >> k` optimization

Split the existing rule into three parts:
- A dual of the rule for `(x >> k) << k` that is only valid for unsigned
  shifts.
- Known-bits analysis for `(band (uextend x) k)`.
- A new rule for converting `sextend` to `uextend` if the sign-extended
  bits are masked out anyway.

The first two together cover the existing rule.

* Generalize signed `(x << k) >> k` optimization

* Review comments

* Generalize sign-extending shifts further

The shifts can be eliminated even if the shift amount isn't exactly
equal to the difference in bit-widths between the narrow and wide types.

* Add filetests
This commit is contained in:
Jamey Sharp
2023-02-27 09:34:46 -08:00
committed by GitHub
parent 6f64e39dda
commit 6cf7155052
4 changed files with 209 additions and 13 deletions

View File

@@ -29,7 +29,7 @@ block0(v0: i8):
return v3
; check: v4 = iconst.i8 224
; check: v5 = band v0, v4
; return v5
; check: return v5
}
function %unsigned_shift_right_shift_left_i32(i32) -> i32 {
@@ -51,7 +51,7 @@ block0(v0: i64):
return v3
; check: v4 = iconst.i64 -32
; check: v5 = band v0, v4
; return v5
; check: return v5
}
function %signed_shift_right_shift_left_i8(i8) -> i8 {
@@ -62,7 +62,7 @@ block0(v0: i8):
return v3
; check: v4 = iconst.i8 224
; check: v5 = band v0, v4
; return v5
; check: return v5
}
function %signed_shift_right_shift_left_i32(i32) -> i32 {
@@ -73,7 +73,7 @@ block0(v0: i32):
return v3
; check: v4 = iconst.i32 0xffff_ffe0
; check: v5 = band v0, v4
; return v5
; check: return v5
}
function %signed_shift_right_shift_left_i64(i64) -> i64 {
@@ -84,7 +84,7 @@ block0(v0: i64):
return v3
; check: v4 = iconst.i64 -32
; check: v5 = band v0, v4
; return v5
; check: return v5
}
function %signed_shift_right_shift_left_i8_mask_rhs(i8) -> i8 {
@@ -95,7 +95,133 @@ block0(v0: i8):
return v3
; check: v4 = iconst.i8 224
; check: v5 = band v0, v4
; return v5
; check: return v5
}
function %sextend_shift_32_64_unsigned(i32) -> i64 {
block0(v0: i32):
v1 = iconst.i8 32
v2 = sextend.i64 v0
v3 = ishl v2, v1
v4 = ushr v3, v1
return v4
; check: v7 = uextend.i64 v0
; check: return v7
}
function %sextend_shift_32_64_signed(i32) -> i64 {
block0(v0: i32):
v1 = iconst.i8 32
v2 = sextend.i64 v0
v3 = ishl v2, v1
v4 = sshr v3, v1
return v4
; check: return v2
}
function %sextend_undershift_32_64_unsigned(i32) -> i64 {
block0(v0: i32):
v1 = iconst.i8 31
v2 = sextend.i64 v0
v3 = ishl v2, v1
v4 = ushr v3, v1
return v4
; check: v5 = iconst.i64 0x0001_ffff_ffff
; check: v6 = band v2, v5
; check: return v6
}
function %sextend_undershift_32_64_signed(i32) -> i64 {
block0(v0: i32):
v1 = iconst.i8 31
v2 = sextend.i64 v0
v3 = ishl v2, v1
v4 = sshr v3, v1
return v4
; check: return v2
}
function %sextend_shift_8_64_unsigned(i8) -> i64 {
block0(v0: i8):
v1 = iconst.i8 56
v2 = sextend.i64 v0
v3 = ishl v2, v1
v4 = ushr v3, v1
return v4
; check: v7 = uextend.i64 v0
; check: return v7
}
function %sextend_shift_8_64_signed(i8) -> i64 {
block0(v0: i8):
v1 = iconst.i8 56
v2 = sextend.i64 v0
v3 = ishl v2, v1
v4 = sshr v3, v1
return v4
; check: return v2
}
function %uextend_shift_32_64_unsigned(i32) -> i64 {
block0(v0: i32):
v1 = iconst.i8 32
v2 = uextend.i64 v0
v3 = ishl v2, v1
v4 = ushr v3, v1
return v4
; check: return v2
}
function %uextend_shift_32_64_signed(i32) -> i64 {
block0(v0: i32):
v1 = iconst.i8 32
v2 = uextend.i64 v0
v3 = ishl v2, v1
v4 = sshr v3, v1
return v4
; check: v5 = sextend.i64 v0
; check: return v5
}
function %uextend_undershift_32_64_unsigned(i32) -> i64 {
block0(v0: i32):
v1 = iconst.i8 31
v2 = uextend.i64 v0
v3 = ishl v2, v1
v4 = ushr v3, v1
return v4
; check: return v2
}
function %uextend_undershift_32_64_signed(i32) -> i64 {
block0(v0: i32):
v1 = iconst.i8 31
v2 = uextend.i64 v0
v3 = ishl v2, v1
v4 = sshr v3, v1
return v4
; check: return v2
}
function %uextend_shift_8_64_unsigned(i8) -> i64 {
block0(v0: i8):
v1 = iconst.i8 56
v2 = uextend.i64 v0
v3 = ishl v2, v1
v4 = ushr v3, v1
return v4
; check: return v2
}
function %uextend_shift_8_64_signed(i8) -> i64 {
block0(v0: i8):
v1 = iconst.i8 56
v2 = uextend.i64 v0
v3 = ishl v2, v1
v4 = sshr v3, v1
return v4
; check: v5 = sextend.i64 v0
; check: return v5
}
function %or_and_y_with_not_y_i8(i8, i8) -> i8 {