Skip to content

Commit d5b6972

Browse files
authored
[OptimizeInstructions] Canonicalize relational ops near min/max values (#4282)
A continuation of #4272. ``` (signed)x < s_min + 1 ==> x == s_min (signed)x >= s_min + 1 ==> x != s_min (signed)x > s_max - 1 ==> x == s_max (signed)x <= s_max - 1 ==> x != s_max (unsigned)x <= u_max - 1 ==> x != u_max (unsigned)x > u_max - 1 ==> x == u_max ```
1 parent c929cf6 commit d5b6972

File tree

3 files changed

+192
-1
lines changed

3 files changed

+192
-1
lines changed

src/passes/OptimizeInstructions.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2157,6 +2157,67 @@ struct OptimizeInstructions
21572157
c->value = Literal::makeZero(c->type);
21582158
return;
21592159
}
2160+
// Prefer compare to signed min (s_min) instead of s_min + 1.
2161+
// (signed)x < s_min + 1 ==> x == s_min
2162+
if (binary->op == LtSInt32 && c->value.geti32() == INT32_MIN + 1) {
2163+
binary->op = EqInt32;
2164+
c->value = Literal::makeSignedMin(Type::i32);
2165+
return;
2166+
}
2167+
if (binary->op == LtSInt64 && c->value.geti64() == INT64_MIN + 1) {
2168+
binary->op = EqInt64;
2169+
c->value = Literal::makeSignedMin(Type::i64);
2170+
return;
2171+
}
2172+
// (signed)x >= s_min + 1 ==> x != s_min
2173+
if (binary->op == GeSInt32 && c->value.geti32() == INT32_MIN + 1) {
2174+
binary->op = NeInt32;
2175+
c->value = Literal::makeSignedMin(Type::i32);
2176+
return;
2177+
}
2178+
if (binary->op == GeSInt64 && c->value.geti64() == INT64_MIN + 1) {
2179+
binary->op = NeInt64;
2180+
c->value = Literal::makeSignedMin(Type::i64);
2181+
return;
2182+
}
2183+
// Prefer compare to signed max (s_max) instead of s_max - 1.
2184+
// (signed)x > s_max - 1 ==> x == s_max
2185+
if (binary->op == GtSInt32 && c->value.geti32() == INT32_MAX - 1) {
2186+
binary->op = EqInt32;
2187+
c->value = Literal::makeSignedMax(Type::i32);
2188+
return;
2189+
}
2190+
if (binary->op == GtSInt64 && c->value.geti64() == INT64_MAX - 1) {
2191+
binary->op = EqInt64;
2192+
c->value = Literal::makeSignedMax(Type::i64);
2193+
return;
2194+
}
2195+
// (signed)x <= s_max - 1 ==> x != s_max
2196+
if (binary->op == LeSInt32 && c->value.geti32() == INT32_MAX - 1) {
2197+
binary->op = NeInt32;
2198+
c->value = Literal::makeSignedMax(Type::i32);
2199+
return;
2200+
}
2201+
if (binary->op == LeSInt64 && c->value.geti64() == INT64_MAX - 1) {
2202+
binary->op = NeInt64;
2203+
c->value = Literal::makeSignedMax(Type::i64);
2204+
return;
2205+
}
2206+
// Prefer compare to unsigned max (u_max) instead of u_max - 1.
2207+
// (unsigned)x <= u_max - 1 ==> x != u_max
2208+
if (binary->op == Abstract::getBinary(c->type, Abstract::LeU) &&
2209+
c->value.getInteger() == (int64_t)(UINT64_MAX - 1)) {
2210+
binary->op = Abstract::getBinary(c->type, Abstract::Ne);
2211+
c->value = Literal::makeUnsignedMax(c->type);
2212+
return;
2213+
}
2214+
// (unsigned)x > u_max - 1 ==> x == u_max
2215+
if (binary->op == Abstract::getBinary(c->type, Abstract::GtU) &&
2216+
c->value.getInteger() == (int64_t)(UINT64_MAX - 1)) {
2217+
binary->op = Abstract::getBinary(c->type, Abstract::Eq);
2218+
c->value = Literal::makeUnsignedMax(c->type);
2219+
return;
2220+
}
21602221
return;
21612222
}
21622223
// Prefer a get on the right.

test/lit/passes/optimize-instructions.wast

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1644,6 +1644,136 @@
16441644
(i32.const 1)
16451645
))
16461646
)
1647+
;; CHECK: (func $canonicalize-cmp-near-min-max (param $x i32) (param $y i64)
1648+
;; CHECK-NEXT: (drop
1649+
;; CHECK-NEXT: (i32.eq
1650+
;; CHECK-NEXT: (local.get $x)
1651+
;; CHECK-NEXT: (i32.const -2147483648)
1652+
;; CHECK-NEXT: )
1653+
;; CHECK-NEXT: )
1654+
;; CHECK-NEXT: (drop
1655+
;; CHECK-NEXT: (i64.eq
1656+
;; CHECK-NEXT: (local.get $y)
1657+
;; CHECK-NEXT: (i64.const -9223372036854775808)
1658+
;; CHECK-NEXT: )
1659+
;; CHECK-NEXT: )
1660+
;; CHECK-NEXT: (drop
1661+
;; CHECK-NEXT: (i32.ne
1662+
;; CHECK-NEXT: (local.get $x)
1663+
;; CHECK-NEXT: (i32.const -2147483648)
1664+
;; CHECK-NEXT: )
1665+
;; CHECK-NEXT: )
1666+
;; CHECK-NEXT: (drop
1667+
;; CHECK-NEXT: (i64.ne
1668+
;; CHECK-NEXT: (local.get $y)
1669+
;; CHECK-NEXT: (i64.const -9223372036854775808)
1670+
;; CHECK-NEXT: )
1671+
;; CHECK-NEXT: )
1672+
;; CHECK-NEXT: (drop
1673+
;; CHECK-NEXT: (i32.eq
1674+
;; CHECK-NEXT: (local.get $x)
1675+
;; CHECK-NEXT: (i32.const 2147483647)
1676+
;; CHECK-NEXT: )
1677+
;; CHECK-NEXT: )
1678+
;; CHECK-NEXT: (drop
1679+
;; CHECK-NEXT: (i64.eq
1680+
;; CHECK-NEXT: (local.get $y)
1681+
;; CHECK-NEXT: (i64.const 9223372036854775807)
1682+
;; CHECK-NEXT: )
1683+
;; CHECK-NEXT: )
1684+
;; CHECK-NEXT: (drop
1685+
;; CHECK-NEXT: (i32.ne
1686+
;; CHECK-NEXT: (local.get $x)
1687+
;; CHECK-NEXT: (i32.const 2147483647)
1688+
;; CHECK-NEXT: )
1689+
;; CHECK-NEXT: )
1690+
;; CHECK-NEXT: (drop
1691+
;; CHECK-NEXT: (i64.ne
1692+
;; CHECK-NEXT: (local.get $y)
1693+
;; CHECK-NEXT: (i64.const 9223372036854775807)
1694+
;; CHECK-NEXT: )
1695+
;; CHECK-NEXT: )
1696+
;; CHECK-NEXT: (drop
1697+
;; CHECK-NEXT: (i32.ne
1698+
;; CHECK-NEXT: (local.get $x)
1699+
;; CHECK-NEXT: (i32.const -1)
1700+
;; CHECK-NEXT: )
1701+
;; CHECK-NEXT: )
1702+
;; CHECK-NEXT: (drop
1703+
;; CHECK-NEXT: (i64.ne
1704+
;; CHECK-NEXT: (local.get $y)
1705+
;; CHECK-NEXT: (i64.const -1)
1706+
;; CHECK-NEXT: )
1707+
;; CHECK-NEXT: )
1708+
;; CHECK-NEXT: (drop
1709+
;; CHECK-NEXT: (i32.eq
1710+
;; CHECK-NEXT: (local.get $x)
1711+
;; CHECK-NEXT: (i32.const -1)
1712+
;; CHECK-NEXT: )
1713+
;; CHECK-NEXT: )
1714+
;; CHECK-NEXT: (drop
1715+
;; CHECK-NEXT: (i64.eq
1716+
;; CHECK-NEXT: (local.get $y)
1717+
;; CHECK-NEXT: (i64.const -1)
1718+
;; CHECK-NEXT: )
1719+
;; CHECK-NEXT: )
1720+
;; CHECK-NEXT: )
1721+
(func $canonicalize-cmp-near-min-max (param $x i32) (param $y i64)
1722+
;; (signed)x < s_min + 1 ==> x == s_min
1723+
(drop (i32.lt_s
1724+
(local.get $x)
1725+
(i32.const -2147483647)
1726+
))
1727+
(drop (i64.lt_s
1728+
(local.get $y)
1729+
(i64.const -9223372036854775807)
1730+
))
1731+
;; (signed)x >= s_min + 1 ==> x != s_min
1732+
(drop (i32.ge_s
1733+
(local.get $x)
1734+
(i32.const -2147483647)
1735+
))
1736+
(drop (i64.ge_s
1737+
(local.get $y)
1738+
(i64.const -9223372036854775807)
1739+
))
1740+
;; (signed)x > s_max - 1 ==> x == s_max
1741+
(drop (i32.gt_s
1742+
(local.get $x)
1743+
(i32.const 2147483646)
1744+
))
1745+
(drop (i64.gt_s
1746+
(local.get $y)
1747+
(i64.const 9223372036854775806)
1748+
))
1749+
;; (signed)x <= s_max - 1 ==> x != s_max
1750+
(drop (i32.le_s
1751+
(local.get $x)
1752+
(i32.const 2147483646)
1753+
))
1754+
(drop (i64.le_s
1755+
(local.get $y)
1756+
(i64.const 9223372036854775806)
1757+
))
1758+
;; (unsigned)x <= u_max - 1 ==> x == u_max
1759+
(drop (i32.le_u
1760+
(local.get $x)
1761+
(i32.const -2)
1762+
))
1763+
(drop (i64.le_u
1764+
(local.get $y)
1765+
(i64.const -2)
1766+
))
1767+
;; (unsigned)x > u_max - 1 ==> x != u_max
1768+
(drop (i32.gt_u
1769+
(local.get $x)
1770+
(i32.const -2)
1771+
))
1772+
(drop (i64.gt_u
1773+
(local.get $y)
1774+
(i64.const -2)
1775+
))
1776+
)
16471777
;; CHECK: (func $canonicalize-cmp-const (param $x i32) (param $fx f64)
16481778
;; CHECK-NEXT: (drop
16491779
;; CHECK-NEXT: (i32.le_s

test/lit/wat-kitchen-sink.wast

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
;; CHECK: (type $i32_=>_none (func_subtype (param i32) func))
1111

12-
;; CHECK: (rec
12+
;; CHECK: (rec
1313
;; CHECK-NEXT: (type $s0 (struct_subtype data))
1414
(type $s0 (sub (struct)))
1515
;; CHECK: (type $s1 (struct_subtype data))

0 commit comments

Comments
 (0)