summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-12-20 14:37:28 -0800
committerGitHub <noreply@github.com>2022-12-20 14:37:28 -0800
commit94a45c6aba605f0f7e0a2fac227a2dd7c03a391f (patch)
treea6e1c6e056636ff70fa99216e4f0219b4d60d7dd /test
parent8c2696b78f5658888d0d480eaddd9eed045b3e7b (diff)
downloadbinaryen-94a45c6aba605f0f7e0a2fac227a2dd7c03a391f.tar.gz
binaryen-94a45c6aba605f0f7e0a2fac227a2dd7c03a391f.tar.bz2
binaryen-94a45c6aba605f0f7e0a2fac227a2dd7c03a391f.zip
OptimizeInstructions: Check for possible added-constant overflows (#5227)
Fix a regression from #5025 : we subtract constants there, and we need to be aware that such subtraction can change a constant from signed to unsigned if the comparison is signed, as 0x80000000 - 1 = 0x7fffffff 0x8000000 is a negative number when seen as signed, but always positive after the subtraction.
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/optimize-instructions-mvp.wast299
1 files changed, 299 insertions, 0 deletions
diff --git a/test/lit/passes/optimize-instructions-mvp.wast b/test/lit/passes/optimize-instructions-mvp.wast
index 8a86e259f..db864087d 100644
--- a/test/lit/passes/optimize-instructions-mvp.wast
+++ b/test/lit/passes/optimize-instructions-mvp.wast
@@ -16594,4 +16594,303 @@
)
)
)
+
+ ;; CHECK: (func $skip-added-constants-overflow (result i32)
+ ;; CHECK-NEXT: (i32.ge_s
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (i32.shr_u
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const -2147483648)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $skip-added-constants-overflow (result i32)
+ ;; If we subtracted 0x80000000 - 1 we'd get something that changes sign if
+ ;; the comparison is signed (as the sign bit is no longer set). To avoid
+ ;; that we skip optimizing cases where subtracting the constants might lead
+ ;; to an overflow.
+ (i32.ge_s
+ (i32.add
+ (i32.shr_u
+ (i32.load
+ (i32.const 0)
+ )
+ (i32.const 1)
+ )
+ (i32.const 1)
+ )
+ (i32.const 0x80000000)
+ )
+ )
+
+ ;; CHECK: (func $skip-added-constants-overflow-unsigned (result i32)
+ ;; CHECK-NEXT: (i32.ge_u
+ ;; CHECK-NEXT: (i32.shr_u
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 2147483647)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $skip-added-constants-overflow-unsigned (result i32)
+ ;; As above, but unsigned. This is ok for us to optimize.
+ (i32.ge_u
+ (i32.add
+ (i32.shr_u
+ (i32.load
+ (i32.const 0)
+ )
+ (i32.const 1)
+ )
+ (i32.const 1)
+ )
+ (i32.const 0x80000000)
+ )
+ )
+
+ ;; CHECK: (func $skip-added-constants-zero (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.shr_u
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ (func $skip-added-constants-zero (result i32)
+ ;; A zero in either constant means we should not optimize using an added
+ ;; constant. However, other optimizations kick in here, as adding zero does
+ ;; nothing, and we end up with [max 31 bits] >=_s MIN_INT which is true.
+ (i32.ge_s
+ (i32.add
+ (i32.shr_u
+ (i32.load
+ (i32.const 0)
+ )
+ (i32.const 1)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0x80000000)
+ )
+ )
+
+ ;; CHECK: (func $skip-added-constants-zero-a (result i32)
+ ;; CHECK-NEXT: (i32.ge_s
+ ;; CHECK-NEXT: (i32.sub
+ ;; CHECK-NEXT: (i32.shr_u
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const -2147483648)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $skip-added-constants-zero-a (result i32)
+ ;; A zero in the last constant means we should not optimize.
+ (i32.ge_s
+ (i32.add
+ (i32.shr_u
+ (i32.load
+ (i32.const 0)
+ )
+ (i32.const 1)
+ )
+ (i32.const 0x80000000)
+ )
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $skip-added-constants-zero-b (result i32)
+ ;; CHECK-NEXT: (i32.ge_u
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (i32.shr_u
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $skip-added-constants-zero-b (result i32)
+ ;; Parallel case to the above, with a zero in the added constant. We do not
+ ;; optimize.
+ (i32.ge_u
+ (i32.add
+ (i32.shr_u
+ (i32.load
+ (i32.const 0)
+ )
+ (i32.const 1)
+ )
+ (i32.const 1)
+ )
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $skip-added-constants-negative (result i32)
+ ;; CHECK-NEXT: (i32.ge_s
+ ;; CHECK-NEXT: (i32.sub
+ ;; CHECK-NEXT: (i32.shr_u
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const -20)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $skip-added-constants-negative (result i32)
+ ;; Reasonable negative constants can be optimized. But the add is
+ ;; canoncalized into a sub, and atm we do not optimize such added constants.
+ (i32.ge_s
+ (i32.add
+ (i32.shr_u
+ (i32.load
+ (i32.const 0)
+ )
+ (i32.const 1)
+ )
+ (i32.const -10)
+ )
+ (i32.const -20)
+ )
+ )
+
+ ;; CHECK: (func $skip-added-constants-negative-flip (result i32)
+ ;; CHECK-NEXT: (i32.ge_s
+ ;; CHECK-NEXT: (i32.sub
+ ;; CHECK-NEXT: (i32.shr_u
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 20)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const -10)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $skip-added-constants-negative-flip (result i32)
+ ;; As above, but flipped. The add is canoncalized into a sub, and atm we do
+ ;; not optimize such added constants.
+ (i32.ge_s
+ (i32.add
+ (i32.shr_u
+ (i32.load
+ (i32.const 0)
+ )
+ (i32.const 1)
+ )
+ (i32.const -20)
+ )
+ (i32.const -10)
+ )
+ )
+
+ ;; CHECK: (func $skip-added-constants-mix (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.shr_u
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ (func $skip-added-constants-mix (result i32)
+ ;; A case of one negative and one positive constant. Here we have
+ ;; [max 31 bits] + 10 >=_s -20 which is always true.
+ (i32.ge_s
+ (i32.add
+ (i32.shr_u
+ (i32.load
+ (i32.const 0)
+ )
+ (i32.const 1)
+ )
+ (i32.const 10)
+ )
+ (i32.const -20)
+ )
+ )
+
+ ;; CHECK: (func $skip-added-constants-mix-flip (result i32)
+ ;; CHECK-NEXT: (i32.ge_s
+ ;; CHECK-NEXT: (i32.sub
+ ;; CHECK-NEXT: (i32.shr_u
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 20)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $skip-added-constants-mix-flip (result i32)
+ ;; As above, but with sign flipped. The add is canoncalized into a sub, and
+ ;; atm we do not optimize such added constants.
+ (i32.ge_s
+ (i32.add
+ (i32.shr_u
+ (i32.load
+ (i32.const 0)
+ )
+ (i32.const 1)
+ )
+ (i32.const -20)
+ )
+ (i32.const 10)
+ )
+ )
+
+ ;; CHECK: (func $skip-added-constants-mix-flip-other (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.shr_u
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ (func $skip-added-constants-mix-flip-other (result i32)
+ ;; As above, but with the sign the same while the absolute values are
+ ;; flipped. Here we have [max 31 bits] + 20 >=_s -10 which is always true.
+ (i32.ge_s
+ (i32.add
+ (i32.shr_u
+ (i32.load
+ (i32.const 0)
+ )
+ (i32.const 1)
+ )
+ (i32.const 20)
+ )
+ (i32.const -10)
+ )
+ )
)