diff options
-rw-r--r-- | src/passes/PickLoadSigns.cpp | 15 | ||||
-rw-r--r-- | src/passes/pass.cpp | 3 | ||||
-rw-r--r-- | test/passes/pick-load-signs.txt | 263 | ||||
-rw-r--r-- | test/passes/pick-load-signs.wast | 260 |
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) + ) + ) +) |