summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeInstructions.cpp22
-rw-r--r--test/passes/optimize-instructions_fuzz-exec.txt37
-rw-r--r--test/passes/optimize-instructions_fuzz-exec.wast25
3 files changed, 71 insertions, 13 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 2ca670f89..2b0a95fc7 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -468,9 +468,9 @@ struct OptimizeInstructions
if (auto* binary = curr->dynCast<Binary>()) {
if (auto* ext = Properties::getAlmostSignExt(binary)) {
- Index extraShifts;
- auto bits = Properties::getAlmostSignExtBits(binary, extraShifts);
- if (extraShifts == 0) {
+ Index extraLeftShifts;
+ auto bits = Properties::getAlmostSignExtBits(binary, extraLeftShifts);
+ if (extraLeftShifts == 0) {
if (auto* load =
Properties::getFallthrough(ext, getPassOptions(), features)
->dynCast<Load>()) {
@@ -488,11 +488,17 @@ struct OptimizeInstructions
}
}
}
- // if the sign-extend input cannot have a sign bit, we don't need it
- // we also don't need it if it already has an identical-sized sign
- // extend
- if (Bits::getMaxBits(ext, this) + extraShifts < bits ||
- isSignExted(ext, bits)) {
+ // We can in some cases remove part of a sign extend, that is,
+ // (x << A) >> B => x << (A - B)
+ // If the sign-extend input cannot have a sign bit, we don't need it.
+ if (Bits::getMaxBits(ext, this) + extraLeftShifts < bits) {
+ return removeAlmostSignExt(binary);
+ }
+ // We also don't need it if it already has an identical-sized sign
+ // extend applied to it. That is, if it is already a sign-extended
+ // value, then another sign extend will do nothing. We do need to be
+ // careful of the extra shifts, though.
+ if (isSignExted(ext, bits) && extraLeftShifts == 0) {
return removeAlmostSignExt(binary);
}
} else if (binary->op == EqInt32 || binary->op == NeInt32) {
diff --git a/test/passes/optimize-instructions_fuzz-exec.txt b/test/passes/optimize-instructions_fuzz-exec.txt
index e8985222d..27d8795ed 100644
--- a/test/passes/optimize-instructions_fuzz-exec.txt
+++ b/test/passes/optimize-instructions_fuzz-exec.txt
@@ -257,19 +257,22 @@
[LoggingExternalInterface logging 1]
[LoggingExternalInterface logging 1]
[LoggingExternalInterface logging 0]
+[fuzz-exec] calling do-shift
+[LoggingExternalInterface logging -64]
[fuzz-exec] calling call-compare-maybe-signed-eq
[fuzz-exec] note result: call-compare-maybe-signed-eq => 0
[fuzz-exec] calling call-compare-maybe-signed-ne
[fuzz-exec] note result: call-compare-maybe-signed-ne => 1
(module
(type $i32_=>_none (func (param i32)))
+ (type $none_=>_none (func))
(type $none_=>_i32 (func (result i32)))
(type $i32_=>_i32 (func (param i32) (result i32)))
- (type $none_=>_none (func))
(import "fuzzing-support" "log-i32" (func $log (param i32)))
(export "foo" (func $1))
- (export "call-compare-maybe-signed-eq" (func $3))
- (export "call-compare-maybe-signed-ne" (func $5))
+ (export "do-shift" (func $3))
+ (export "call-compare-maybe-signed-eq" (func $5))
+ (export "call-compare-maybe-signed-ne" (func $7))
(func $signed-comparison-to-unsigned
(call $log
(block (result i32)
@@ -321,13 +324,35 @@
)
)
)
+ (func $shift (param $0 i32)
+ (call $log
+ (i32.shr_s
+ (i32.shl
+ (i32.shr_s
+ (i32.shl
+ (local.get $0)
+ (i32.const 24)
+ )
+ (i32.const 24)
+ )
+ (i32.const 30)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ (func $3
+ (call $shift
+ (i32.const 65419)
+ )
+ )
(func $compare-maybe-signed-eq (param $0 i32) (result i32)
(drop
(local.get $0)
)
(i32.const 0)
)
- (func $3 (result i32)
+ (func $5 (result i32)
(call $compare-maybe-signed-eq
(i32.const 128)
)
@@ -338,7 +363,7 @@
)
(i32.const 1)
)
- (func $5 (result i32)
+ (func $7 (result i32)
(call $compare-maybe-signed-ne
(i32.const 128)
)
@@ -348,6 +373,8 @@
[LoggingExternalInterface logging 1]
[LoggingExternalInterface logging 1]
[LoggingExternalInterface logging 0]
+[fuzz-exec] calling do-shift
+[LoggingExternalInterface logging -64]
[fuzz-exec] calling call-compare-maybe-signed-eq
[fuzz-exec] note result: call-compare-maybe-signed-eq => 0
[fuzz-exec] calling call-compare-maybe-signed-ne
diff --git a/test/passes/optimize-instructions_fuzz-exec.wast b/test/passes/optimize-instructions_fuzz-exec.wast
index 8bd43b694..87b6eb594 100644
--- a/test/passes/optimize-instructions_fuzz-exec.wast
+++ b/test/passes/optimize-instructions_fuzz-exec.wast
@@ -287,6 +287,31 @@
)
)
)
+ (func $shift (param $0 i32)
+ (call $log
+ ;; x << 24 >> 24 << 30 >> 24 - the extra shifts make it invalid to do the
+ ;; optimization of not repeating a sign-extend. That is, this would be valid
+ ;; if the 30 were replaced by a 24.
+ (i32.shr_s
+ (i32.shl
+ (i32.shr_s
+ (i32.shl
+ (local.get $0)
+ (i32.const 24)
+ )
+ (i32.const 24)
+ )
+ (i32.const 30)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ (func "do-shift"
+ (call $shift
+ (i32.const 65419)
+ )
+ )
;; similar, but with the value compared to having the sign bit set but no
;; upper bits
(func $compare-maybe-signed-eq (param $0 i32) (result i32)