From 13f9265b9632f887e6c22a024c4c4d8ded187dd1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 14 Feb 2017 15:18:46 -0800 Subject: refactor sign/zero extension code into nice headers, and prepare PickLoadSigns pass --- src/passes/pass.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/passes/pass.cpp') diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 32b596eef..2741e200a 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -77,6 +77,7 @@ void PassRegistry::registerPasses() { registerPass("nm", "name list", createNameListPass); registerPass("name-manager", "utility pass to manage names in modules", createNameManagerPass); registerPass("optimize-instructions", "optimizes instruction combinations", createOptimizeInstructionsPass); + registerPass("pick-load-signs", "pick load signs based on their uses", createPickLoadSignsPass); registerPass("post-emscripten", "miscellaneous optimizations for Emscripten-generated code", createPostEmscriptenPass); registerPass("print", "print in s-expression format", createPrinterPass); registerPass("print-minified", "print in minified s-expression format", createMinifiedPrinterPass); -- cgit v1.2.3 From 63230c06a8d98f4326de5d1a2ef6e908ed6a5945 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 14 Feb 2017 15:31:40 -0800 Subject: finish PickLoadSigns pass --- src/passes/PickLoadSigns.cpp | 15 ++- src/passes/pass.cpp | 3 + test/passes/pick-load-signs.txt | 263 +++++++++++++++++++++++++++++++++++++++ test/passes/pick-load-signs.wast | 260 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 533 insertions(+), 8 deletions(-) create mode 100644 test/passes/pick-load-signs.txt create mode 100644 test/passes/pick-load-signs.wast (limited to 'src/passes/pass.cpp') 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 WalkerPassindex]; + 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= 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) + ) + ) +) -- cgit v1.2.3