diff options
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 19 | ||||
-rw-r--r-- | test/emcc_hello_world.fromasm | 20 | ||||
-rw-r--r-- | test/emcc_hello_world.fromasm.imprecise | 20 | ||||
-rw-r--r-- | test/passes/optimize-instructions.txt | 54 | ||||
-rw-r--r-- | test/passes/optimize-instructions.wast | 66 |
5 files changed, 150 insertions, 29 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 49100a9f4..844ed06ac 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -305,6 +305,17 @@ static int32_t lowBitMask(int32_t bits) { return ret >> (32 - bits); } +// checks if the input is a mask of lower bits, i.e., all 1s up to some high bit, and all zeros +// from there. returns the number of masked bits, or 0 if this is not such a mask +static uint32_t getMaskedBits(int32_t mask) { + if (mask == -1) return 32; // all the bits + if (mask == 0) return 0; // trivially not a mask + // otherwise, see if adding one turns this into a 1-bit thing, 00011111 + 1 => 00100000 + if (PopCount(mask + 1) != 1) return 0; + // this is indeed a mask + return 32 - CountLeadingZeroes(mask); +} + // performs a dynCast on the fallthrough value, i.e., looks through // too and block fallthroughs, etc. template<typename T> @@ -436,9 +447,11 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions, return binary->left; } } - } else if (mask == 1 && Properties::emitsBoolean(binary->left)) { - // (bool) & 1 does not need the outer mask - return binary->left; + } else if (auto maskedBits = getMaskedBits(mask)) { + if (getMaxBits(binary->left) <= maskedBits) { + // a mask of lower bits is not needed if we are already smaller + return binary->left; + } } } // the square of some operations can be merged diff --git a/test/emcc_hello_world.fromasm b/test/emcc_hello_world.fromasm index 78f0460fa..88db1c1ce 100644 --- a/test/emcc_hello_world.fromasm +++ b/test/emcc_hello_world.fromasm @@ -1941,14 +1941,11 @@ (i32.load8_u (get_local $2) ) - (i32.and - (tee_local $1 - (i32.and - (get_local $1) - (i32.const 255) - ) + (tee_local $1 + (i32.and + (get_local $1) + (i32.const 255) ) - (i32.const 255) ) ) (block @@ -9393,13 +9390,10 @@ (i32.shl (get_local $8) (i32.xor - (i32.and - (tee_local $6 - (i32.eqz - (get_local $9) - ) + (tee_local $6 + (i32.eqz + (get_local $9) ) - (i32.const 1) ) (i32.const 1) ) diff --git a/test/emcc_hello_world.fromasm.imprecise b/test/emcc_hello_world.fromasm.imprecise index ba1a50ca7..5ed229e6f 100644 --- a/test/emcc_hello_world.fromasm.imprecise +++ b/test/emcc_hello_world.fromasm.imprecise @@ -1938,14 +1938,11 @@ (i32.load8_u (get_local $2) ) - (i32.and - (tee_local $1 - (i32.and - (get_local $1) - (i32.const 255) - ) + (tee_local $1 + (i32.and + (get_local $1) + (i32.const 255) ) - (i32.const 255) ) ) (block @@ -9330,13 +9327,10 @@ (i32.shl (get_local $8) (i32.xor - (i32.and - (tee_local $6 - (i32.eqz - (get_local $9) - ) + (tee_local $6 + (i32.eqz + (get_local $9) ) - (i32.const 1) ) (i32.const 1) ) diff --git a/test/passes/optimize-instructions.txt b/test/passes/optimize-instructions.txt index 3b4718f6a..31dceaf60 100644 --- a/test/passes/optimize-instructions.txt +++ b/test/passes/optimize-instructions.txt @@ -1290,4 +1290,58 @@ ) ) ) + (func $mask-bits (type $4) (param $0 i32) (param $1 i32) + (drop + (tee_local $0 + (i32.const 127) + ) + ) + (drop + (tee_local $0 + (i32.const 128) + ) + ) + (drop + (i32.and + (tee_local $0 + (i32.const 128) + ) + (i32.const 254) + ) + ) + (drop + (i32.and + (tee_local $0 + (i32.const 128) + ) + (i32.const 1279) + ) + ) + (drop + (i32.and + (tee_local $0 + (i32.const 128) + ) + (i32.const 1290) + ) + ) + (drop + (tee_local $0 + (i32.const 128) + ) + ) + (drop + (tee_local $0 + (i32.const 128) + ) + ) + (drop + (i32.and + (tee_local $0 + (i32.const 128) + ) + (i32.const 127) + ) + ) + ) ) diff --git a/test/passes/optimize-instructions.wast b/test/passes/optimize-instructions.wast index f8c93d03c..c305ccbbb 100644 --- a/test/passes/optimize-instructions.wast +++ b/test/passes/optimize-instructions.wast @@ -1625,4 +1625,70 @@ ) ) ) + (func $mask-bits (param $0 i32) (param $1 i32) + (drop + (i32.and + (tee_local $0 + (i32.const 127) ;; 7 bits + ) + (i32.const 255) ;; mask 8, so we don't need this + ) + ) + (drop + (i32.and + (tee_local $0 + (i32.const 128) ;; 8 bits + ) + (i32.const 255) ;; mask 8, so we don't need this + ) + ) + (drop + (i32.and + (tee_local $0 + (i32.const 128) + ) + (i32.const 254) ;; improper mask, small + ) + ) + (drop + (i32.and + (tee_local $0 + (i32.const 128) + ) + (i32.const 1279) ;; improper mask, large + ) + ) + (drop + (i32.and + (tee_local $0 + (i32.const 128) + ) + (i32.const 1290) ;; improper mask, large + ) + ) + (drop + (i32.and + (tee_local $0 + (i32.const 128) + ) + (i32.const 4095) ;; proper mask, huge + ) + ) + (drop + (i32.and + (tee_local $0 + (i32.const 128) + ) + (i32.const 511) ;; proper mask, large + ) + ) + (drop + (i32.and + (tee_local $0 + (i32.const 128) + ) + (i32.const 127) ;; proper mask, just too small + ) + ) + ) ) |