I was playing around with souper recently on some wasms I had lying around and these are some optimization opportunities that popped out which seemed easy-enough to add to the egraph-based optimizations.
340 lines
6.5 KiB
Plaintext
340 lines
6.5 KiB
Plaintext
test optimize
|
|
set opt_level=speed
|
|
set use_egraphs=true
|
|
target x86_64
|
|
|
|
function %f0(i32) -> i32 {
|
|
block0(v0: i32):
|
|
v1 = iconst.i32 2
|
|
v2 = imul v0, v1
|
|
; check: v5 = ishl v0, v4 ; v4 = 1
|
|
; check: return v5
|
|
return v2
|
|
}
|
|
|
|
function %f1() -> i64 {
|
|
block0:
|
|
v0 = iconst.i32 0xffff_ffff_9876_5432
|
|
v1 = uextend.i64 v0
|
|
return v1
|
|
; check: v2 = iconst.i64 0x9876_5432
|
|
; check: return v2 ; v2 = 0x9876_5432
|
|
}
|
|
|
|
function %unsigned_shift_right_shift_left_i8(i8) -> i8 {
|
|
block0(v0: i8):
|
|
v1 = iconst.i8 5
|
|
v2 = ushr v0, v1
|
|
v3 = ishl v2, v1
|
|
return v3
|
|
; check: v4 = iconst.i8 224
|
|
; check: v5 = band v0, v4
|
|
; return v5
|
|
}
|
|
|
|
function %unsigned_shift_right_shift_left_i32(i32) -> i32 {
|
|
block0(v0: i32):
|
|
v1 = iconst.i32 5
|
|
v2 = ushr v0, v1
|
|
v3 = ishl v2, v1
|
|
return v3
|
|
; check: v4 = iconst.i32 0xffff_ffe0
|
|
; check: v5 = band v0, v4
|
|
; check: return v5
|
|
}
|
|
|
|
function %unsigned_shift_right_shift_left_i64(i64) -> i64 {
|
|
block0(v0: i64):
|
|
v1 = iconst.i64 5
|
|
v2 = ushr v0, v1
|
|
v3 = ishl v2, v1
|
|
return v3
|
|
; check: v4 = iconst.i64 -32
|
|
; check: v5 = band v0, v4
|
|
; return v5
|
|
}
|
|
|
|
function %signed_shift_right_shift_left_i8(i8) -> i8 {
|
|
block0(v0: i8):
|
|
v1 = iconst.i8 5
|
|
v2 = sshr v0, v1
|
|
v3 = ishl v2, v1
|
|
return v3
|
|
; check: v4 = iconst.i8 224
|
|
; check: v5 = band v0, v4
|
|
; return v5
|
|
}
|
|
|
|
function %signed_shift_right_shift_left_i32(i32) -> i32 {
|
|
block0(v0: i32):
|
|
v1 = iconst.i32 5
|
|
v2 = sshr v0, v1
|
|
v3 = ishl v2, v1
|
|
return v3
|
|
; check: v4 = iconst.i32 0xffff_ffe0
|
|
; check: v5 = band v0, v4
|
|
; return v5
|
|
}
|
|
|
|
function %signed_shift_right_shift_left_i64(i64) -> i64 {
|
|
block0(v0: i64):
|
|
v1 = iconst.i64 5
|
|
v2 = sshr v0, v1
|
|
v3 = ishl v2, v1
|
|
return v3
|
|
; check: v4 = iconst.i64 -32
|
|
; check: v5 = band v0, v4
|
|
; return v5
|
|
}
|
|
|
|
function %signed_shift_right_shift_left_i8_mask_rhs(i8) -> i8 {
|
|
block0(v0: i8):
|
|
v1 = iconst.i8 0xf5
|
|
v2 = sshr v0, v1
|
|
v3 = ishl v2, v1
|
|
return v3
|
|
; check: v4 = iconst.i8 224
|
|
; check: v5 = band v0, v4
|
|
; return v5
|
|
}
|
|
|
|
function %or_and_y_with_not_y_i8(i8, i8) -> i8 {
|
|
block0(v0: i8, v1: i8):
|
|
v2 = band v0, v1
|
|
v3 = bnot v1
|
|
v4 = bor v2, v3
|
|
return v4
|
|
; check: v5 = bor v0, v3
|
|
; check: return v5
|
|
}
|
|
|
|
function %or_and_constant_with_not_constant_i8(i8) -> i8 {
|
|
block0(v0: i8):
|
|
v1 = iconst.i8 -4
|
|
v2 = band v0, v1
|
|
v3 = iconst.i8 3
|
|
v4 = bor v2, v3
|
|
return v4
|
|
; check: v5 = bor v0, v3
|
|
; check: return v5
|
|
}
|
|
|
|
function %or_and_y_with_not_y_i8(i8, i8) -> i8 {
|
|
block0(v0: i8, v1: i8):
|
|
v2 = band v0, v1
|
|
v3 = bnot v1
|
|
v4 = bor v3, v2
|
|
return v4
|
|
; check: v5 = bor v0, v3
|
|
; check: return v5
|
|
}
|
|
|
|
function %or_and_constant_with_not_constant_i8(i8) -> i8 {
|
|
block0(v0: i8):
|
|
v1 = iconst.i8 -4
|
|
v2 = band v0, v1
|
|
v3 = iconst.i8 3
|
|
v4 = bor v3, v2
|
|
return v4
|
|
; check: v6 = bor v0, v3
|
|
; check: return v6
|
|
}
|
|
|
|
function %or_and_constant_with_any_constant_should_not_apply_rule_i8(i8) -> i8 {
|
|
block0(v0: i8):
|
|
v1 = iconst.i8 -4
|
|
v2 = band v0, v1
|
|
;; `v3` is not `bnot(v1)` so the rewrite should not apply.
|
|
v3 = iconst.i8 -5
|
|
v4 = bor v2, v3
|
|
return v4
|
|
; check: return v4
|
|
}
|
|
|
|
function %or_and_y_with_not_y_i64(i64, i64) -> i64 {
|
|
block0(v0: i64, v1: i64):
|
|
v2 = band v0, v1
|
|
v3 = bnot v1
|
|
v4 = bor v2, v3
|
|
return v4
|
|
; check: v5 = bor v0, v3
|
|
; check: return v5
|
|
}
|
|
|
|
function %or_and_constant_with_not_constant_i64(i64) -> i64 {
|
|
block0(v0: i64):
|
|
v1 = iconst.i64 -4
|
|
v2 = band v0, v1
|
|
v3 = iconst.i64 3
|
|
v4 = bor v2, v3
|
|
return v4
|
|
; check: v5 = bor v0, v3
|
|
; check: return v5
|
|
}
|
|
|
|
function %or_and_y_with_not_y_i64(i64, i64) -> i64 {
|
|
block0(v0: i64, v1: i64):
|
|
v2 = band v0, v1
|
|
v3 = bnot v1
|
|
v4 = bor v3, v2
|
|
return v4
|
|
; check: v5 = bor v0, v3
|
|
; check: return v5
|
|
}
|
|
|
|
function %or_and_constant_with_not_constant_i64(i64) -> i64 {
|
|
block0(v0: i64):
|
|
v1 = iconst.i64 -4
|
|
v2 = band v0, v1
|
|
v3 = iconst.i64 3
|
|
v4 = bor v3, v2
|
|
return v4
|
|
; check: v6 = bor v0, v3
|
|
; check: return v6
|
|
}
|
|
|
|
function %or_and_constant_with_any_constant_should_not_apply_rule_i64(i64) -> i64 {
|
|
block0(v0: i64):
|
|
v1 = iconst.i64 -4
|
|
v2 = band v0, v1
|
|
;; `v3` is not `bnot(v1)` so the rewrite should not apply.
|
|
v3 = iconst.i64 -5
|
|
v4 = bor v2, v3
|
|
return v4
|
|
; check: return v4
|
|
}
|
|
|
|
function %f2(i8) -> i8 {
|
|
block0(v1: i8):
|
|
v2 = icmp eq v1, v1
|
|
return v2
|
|
}
|
|
|
|
; check: v3 = iconst.i8 1
|
|
; check: return v3
|
|
|
|
function %f3(i8) -> i8 {
|
|
block0(v1: i8):
|
|
v2 = icmp ne v1, v1
|
|
return v2
|
|
}
|
|
|
|
; check: v3 = iconst.i8 0
|
|
; check: return v3
|
|
|
|
function %bnot1(i8) -> i8 {
|
|
block0(v1: i8):
|
|
v2 = iconst.i8 -1
|
|
v3 = bxor v1, v2
|
|
return v3
|
|
}
|
|
|
|
; check: v4 = bnot v1
|
|
; check: return v4
|
|
|
|
function %bnot2(i64) -> i64 {
|
|
block0(v1: i64):
|
|
v2 = iconst.i64 -1
|
|
v3 = bxor v1, v2
|
|
return v3
|
|
}
|
|
|
|
; check: v4 = bnot v1
|
|
; check: return v4
|
|
|
|
function %bnot3(i64) -> i64 {
|
|
block0(v1: i64):
|
|
v2 = iconst.i64 -1
|
|
v3 = bxor v2, v1
|
|
return v3
|
|
}
|
|
|
|
; check: v5 = bnot v1
|
|
; check: return v5
|
|
|
|
function %mask_icmp_result(i64, i64) -> i8 {
|
|
block0(v1: i64, v2: i64):
|
|
v3 = icmp ult v1, v2
|
|
v4 = iconst.i8 1
|
|
v5 = band v3, v4
|
|
return v5
|
|
}
|
|
|
|
; check: v3 = icmp ult v1, v2
|
|
; check: return v3
|
|
|
|
function %mask_icmp_extend_result(i64, i64) -> i64 {
|
|
block0(v1: i64, v2: i64):
|
|
v3 = icmp ult v1, v2
|
|
v4 = uextend.i64 v3
|
|
v5 = iconst.i64 1
|
|
v6 = band v4, v5
|
|
return v6
|
|
}
|
|
|
|
; check: v3 = icmp ult v1, v2
|
|
; 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
|
|
}
|
|
|
|
; check: v4 = iconst.i8 0
|
|
; check: return v4
|
|
|
|
function %ugt_zero_always_false(i64) -> i8 {
|
|
block0(v1: i64):
|
|
v2 = iconst.i64 0
|
|
v3 = icmp ugt v2, v1
|
|
return v3
|
|
}
|
|
|
|
; check: v5 = iconst.i8 0
|
|
; check: return v5
|
|
|
|
function %uge_zero_always_false(i64) -> i8 {
|
|
block0(v1: i64):
|
|
v2 = iconst.i64 0
|
|
v3 = icmp uge v1, v2
|
|
return v3
|
|
}
|
|
|
|
; check: v4 = iconst.i8 1
|
|
; check: return v4
|
|
|
|
function %ule_zero_always_false(i64) -> i8 {
|
|
block0(v1: i64):
|
|
v2 = iconst.i64 0
|
|
v3 = icmp ule v2, v1
|
|
return v3
|
|
}
|
|
|
|
; check: v5 = iconst.i8 1
|
|
; check: return v5
|
|
|
|
function %extend_always_above_zero(i32) -> i8 {
|
|
block0(v1: i32):
|
|
v2 = uextend.i64 v1
|
|
v3 = iconst.i64 0
|
|
v4 = icmp slt v2, v3
|
|
return v4
|
|
}
|
|
|
|
; check: v5 = iconst.i8 0
|
|
; check: return v5
|
|
|
|
function %extend_always_above_zero2(i32) -> i8 {
|
|
block0(v1: i32):
|
|
v2 = uextend.i64 v1
|
|
v3 = iconst.i64 0
|
|
v4 = icmp sge v2, v3
|
|
return v4
|
|
}
|
|
|
|
; check: v5 = iconst.i8 1
|
|
; check: return v5
|