summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/PickLoadSigns.cpp15
-rw-r--r--src/passes/pass.cpp3
-rw-r--r--test/passes/pick-load-signs.txt263
-rw-r--r--test/passes/pick-load-signs.wast260
4 files changed, 533 insertions, 8 deletions
diff --git a/src/passes/PickLoadSigns.cpp b/src/passes/PickLoadSigns.cpp
index afd7262f5..6e44fddfe 100644
--- a/src/passes/PickLoadSigns.cpp
+++ b/src/passes/PickLoadSigns.cpp
@@ -66,8 +66,9 @@ struct PickLoadSigns : public WalkerPass<ExpressionStackWalker<PickLoadSigns, Vi
void visitGetLocal(GetLocal* curr) {
// this is a use. check from the context what it is, signed or unsigned, etc.
+ auto& usage = usages[curr->index];
+ usage.totalUsages++;
if (expressionStack.size() >= 2) {
- auto& usage = usages[curr->index];
auto* parent = expressionStack[expressionStack.size() - 2];
if (Properties::getZeroExtValue(parent)) {
auto bits = Properties::getZeroExtBits(parent);
@@ -77,18 +78,16 @@ struct PickLoadSigns : public WalkerPass<ExpressionStackWalker<PickLoadSigns, Vi
usage.unsignedBits = 0;
}
usage.unsignedUsages++;
- usage.totalUsages++;
} else if (expressionStack.size() >= 3) {
auto* grandparent = expressionStack[expressionStack.size() - 3];
if (Properties::getSignExtValue(grandparent)) {
auto bits = Properties::getSignExtBits(grandparent);
- if (usage.unsignedUsages == 0) {
- usage.unsignedBits = bits;
- } else if (usage.unsignedBits != bits) {
- usage.unsignedBits = 0;
+ if (usage.signedUsages == 0) {
+ usage.signedBits = bits;
+ } else if (usage.signedBits != bits) {
+ usage.signedBits = 0;
}
- usage.unsignedUsages++;
- usage.totalUsages++;
+ usage.signedUsages++;
}
}
}
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index 2741e200a..df98590c5 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -113,6 +113,9 @@ void PassRunner::addDefaultFunctionOptimizationPasses() {
add("remove-unused-brs");
add("remove-unused-names");
add("optimize-instructions");
+ if (options.optimizeLevel >= 2 || options.shrinkLevel >= 2) {
+ add("pick-load-signs");
+ }
add("precompute");
if (options.optimizeLevel >= 2 || options.shrinkLevel >= 2) {
add("code-pushing");
diff --git a/test/passes/pick-load-signs.txt b/test/passes/pick-load-signs.txt
new file mode 100644
index 000000000..bbf6dc647
--- /dev/null
+++ b/test/passes/pick-load-signs.txt
@@ -0,0 +1,263 @@
+(module
+ (type $0 (func))
+ (type $1 (func (result i32)))
+ (memory $0 0)
+ (func $a (type $0)
+ (local $y i32)
+ (set_local $y
+ (i32.load8_u
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ )
+ (func $b (type $0)
+ (local $y i32)
+ (set_local $y
+ (i32.load16_u
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 65535)
+ )
+ )
+ )
+ (func $c (type $0)
+ (local $y i32)
+ (set_local $y
+ (i32.load8_u
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ )
+ (func $d (type $0)
+ (local $y i32)
+ (set_local $y
+ (i32.load16_u
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 65535)
+ )
+ )
+ )
+ (func $one-of-each (type $0)
+ (local $y i32)
+ (set_local $y
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ (drop
+ (i32.shr_s
+ (i32.shl
+ (get_local $y)
+ (i32.const 24)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ (func $more-of-one (type $0)
+ (local $y i32)
+ (set_local $y
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ (drop
+ (i32.shr_s
+ (i32.shl
+ (get_local $y)
+ (i32.const 24)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ (func $many-more-of-one (type $0)
+ (local $y i32)
+ (set_local $y
+ (i32.load8_u
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ (drop
+ (i32.shr_s
+ (i32.shl
+ (get_local $y)
+ (i32.const 24)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ (func $a-sign (type $0)
+ (local $y i32)
+ (set_local $y
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.shr_s
+ (i32.shl
+ (get_local $y)
+ (i32.const 24)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ (func $multivar (type $0)
+ (local $x i32)
+ (local $y i32)
+ (set_local $x
+ (i32.load8_u
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $x)
+ (i32.const 255)
+ )
+ )
+ (set_local $y
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.shr_s
+ (i32.shl
+ (get_local $y)
+ (i32.const 24)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ (func $corners (type $0)
+ (local $y i32)
+ (drop
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.load8_u
+ (i32.const 1024)
+ )
+ )
+ (set_local $y
+ (i32.const 1024)
+ )
+ )
+ (func $wrong-size (type $0)
+ (local $y i32)
+ (set_local $y
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 65535)
+ )
+ )
+ )
+ (func $wrong-size_s (type $0)
+ (local $y i32)
+ (set_local $y
+ (i32.load8_u
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.shr_s
+ (i32.shl
+ (get_local $y)
+ (i32.const 16)
+ )
+ (i32.const 16)
+ )
+ )
+ )
+ (func $non-sign-or-unsigned-use (type $0)
+ (local $y i32)
+ (set_local $y
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ (drop
+ (get_local $y)
+ )
+ )
+ (func $toplevel-load (type $1) (result i32)
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+)
diff --git a/test/passes/pick-load-signs.wast b/test/passes/pick-load-signs.wast
new file mode 100644
index 000000000..49105e497
--- /dev/null
+++ b/test/passes/pick-load-signs.wast
@@ -0,0 +1,260 @@
+(module
+ (func $a ;; load 8s, but use is 8u, so load should be signed
+ (local $y i32)
+ (set_local $y
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ )
+ (func $b ;; load 16s, but use is 16u, so load should be signed
+ (local $y i32)
+ (set_local $y
+ (i32.load16_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 65535)
+ )
+ )
+ )
+ (func $c ;; load 8u, keep
+ (local $y i32)
+ (set_local $y
+ (i32.load8_u
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ )
+ (func $d ;; load 16u, keep
+ (local $y i32)
+ (set_local $y
+ (i32.load16_u
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 65535)
+ )
+ )
+ )
+ (func $one-of-each ;; prefer the signed, potential code removal is bigger
+ (local $y i32)
+ (set_local $y
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ (drop
+ (i32.shr_s
+ (i32.shl
+ (get_local $y)
+ (i32.const 24)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ (func $more-of-one ;; prefer the signed even if 2x more unsigned
+ (local $y i32)
+ (set_local $y
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ (drop
+ (i32.shr_s
+ (i32.shl
+ (get_local $y)
+ (i32.const 24)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ (func $many-more-of-one ;; but not 3x
+ (local $y i32)
+ (set_local $y
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ (drop
+ (i32.shr_s
+ (i32.shl
+ (get_local $y)
+ (i32.const 24)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ (func $a-sign ;; load 8s, use is s, so keep
+ (local $y i32)
+ (set_local $y
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.shr_s
+ (i32.shl
+ (get_local $y)
+ (i32.const 24)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ (func $multivar
+ (local $x i32)
+ (local $y i32)
+ (set_local $x
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $x)
+ (i32.const 255)
+ )
+ )
+ (set_local $y
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.shr_s
+ (i32.shl
+ (get_local $y)
+ (i32.const 24)
+ )
+ (i32.const 24)
+ )
+ )
+ )
+ (func $corners
+ (local $y i32)
+ (drop
+ (i32.load8_s ;; not sent into a set_local
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.load8_u ;; not sent into a set_local
+ (i32.const 1024)
+ )
+ )
+ (set_local $y
+ (i32.const 1024) ;; not a load
+ )
+ )
+ (func $wrong-size ;; load 8s, but use is 16
+ (local $y i32)
+ (set_local $y
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 65535)
+ )
+ )
+ )
+ (func $wrong-size_s ;; load 8s, but use is 16
+ (local $y i32)
+ (set_local $y
+ (i32.load8_u
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.shr_s
+ (i32.shl
+ (get_local $y)
+ (i32.const 16)
+ )
+ (i32.const 16)
+ )
+ )
+ )
+ (func $non-sign-or-unsigned-use
+ (local $y i32)
+ (set_local $y
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+ (drop
+ (i32.and
+ (get_local $y)
+ (i32.const 255)
+ )
+ )
+ (drop
+ (get_local $y)
+ )
+ )
+ (func $toplevel-load (result i32)
+ (i32.load8_s
+ (i32.const 1024)
+ )
+ )
+)