diff options
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 30 | ||||
-rw-r--r-- | src/support/bits.cpp | 14 | ||||
-rw-r--r-- | src/support/bits.h | 4 | ||||
-rw-r--r-- | test/passes/optimize-instructions_all-features.txt | 27 | ||||
-rw-r--r-- | test/passes/optimize-instructions_all-features.wast | 24 |
5 files changed, 73 insertions, 26 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 1790623eb..2736c8984 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -617,13 +617,13 @@ struct OptimizeInstructions } if (binary->op == DivFloat32) { float c = right->value.getf32(); - if (Bits::isPowerOf2Float(c)) { + if (Bits::isPowerOf2InvertibleFloat(c)) { return optimizePowerOf2FDiv(binary, c); } } if (binary->op == DivFloat64) { double c = right->value.getf64(); - if (Bits::isPowerOf2Float(c)) { + if (Bits::isPowerOf2InvertibleFloat(c)) { return optimizePowerOf2FDiv(binary, c); } } @@ -1412,18 +1412,13 @@ private: return curr; } } - // bool(x) | 1 ==> 1 - if (matches(curr, binary(Abstract::Or, pure(&left), ival(1))) && - Bits::getMaxBits(left, this) == 1) { - return right; - } - // bool(x) & 1 ==> bool(x) - if (matches(curr, binary(Abstract::And, any(&left), ival(1))) && - Bits::getMaxBits(left, this) == 1) { - return left; - } - // bool(x) == 1 ==> bool(x) - if (matches(curr, binary(EqInt32, any(&left), i32(1))) && + // i32(bool(x)) == 1 ==> i32(bool(x)) + // i32(bool(x)) != 0 ==> i32(bool(x)) + // i32(bool(x)) & 1 ==> i32(bool(x)) + // i64(bool(x)) & 1 ==> i64(bool(x)) + if ((matches(curr, binary(EqInt32, any(&left), i32(1))) || + matches(curr, binary(NeInt32, any(&left), i32(0))) || + matches(curr, binary(Abstract::And, any(&left), ival(1)))) && Bits::getMaxBits(left, this) == 1) { return left; } @@ -1436,9 +1431,14 @@ private: } // bool(x) != 1 ==> !bool(x) if (matches(curr, binary(Abstract::Ne, any(&left), ival(1))) && - Bits::getMaxBits(curr->left, this) == 1) { + Bits::getMaxBits(left, this) == 1) { return builder.makeUnary(Abstract::getUnary(type, Abstract::EqZ), left); } + // bool(x) | 1 ==> 1 + if (matches(curr, binary(Abstract::Or, pure(&left), ival(1))) && + Bits::getMaxBits(left, this) == 1) { + return right; + } // Operations on all 1s // x & -1 ==> x diff --git a/src/support/bits.cpp b/src/support/bits.cpp index 8a81a7e83..1de9a0f3b 100644 --- a/src/support/bits.cpp +++ b/src/support/bits.cpp @@ -157,12 +157,20 @@ int ceilLog2(uint32_t v) { return 32 - countLeadingZeroes(v - 1); } int ceilLog2(uint64_t v) { return 64 - countLeadingZeroes(v - 1); } -bool isPowerOf2Float(float v) { +bool isPowerOf2InvertibleFloat(float v) { // Power of two floating points should have zero as their significands, // so here we just mask the exponent range of "v" and compare it with the // unmasked input value. If they are equal, our value is a power of // two. Also, we reject all values which are less than the minimal possible // power of two or greater than the maximum possible power of two. + // We check values only with exponent in more limited ranges + // [-126..+126] for floats and [-1022..+1022] for doubles for avoiding + // overflows and reject NaNs, infinity and denormals. We also reject + // "asymmetric exponents", like +1023, because the range of + // (non-NaN, non-infinity) values is -1022..+1023, and it is convenient in + // optimizations to depend on being able to invert a power of two without + // losing precision. + // This function used in OptimizeInstruction pass. const uint32_t MIN_POT = 0x01U << 23; // 0x1p-126 const uint32_t MAX_POT = 0xFDU << 23; // 0x1p+126 const uint32_t EXP_MASK = 0xFFU << 23; // mask only exponent @@ -171,8 +179,8 @@ bool isPowerOf2Float(float v) { return u >= MIN_POT && u <= MAX_POT && (u & EXP_MASK) == u; } -bool isPowerOf2Float(double v) { - // See isPowerOf2Float(float) +bool isPowerOf2InvertibleFloat(double v) { + // See isPowerOf2InvertibleFloat(float) const uint64_t MIN_POT = 0x001ULL << 52; // 0x1p-1022 const uint64_t MAX_POT = 0x7FDULL << 52; // 0x1p+1022 const uint64_t EXP_MASK = 0x7FFULL << 52; // mask only exponent diff --git a/src/support/bits.h b/src/support/bits.h index 333eb5cc2..a34bc5067 100644 --- a/src/support/bits.h +++ b/src/support/bits.h @@ -77,8 +77,8 @@ template<typename T> bool isPowerOf2(T v) { return v != 0 && (v & (v - 1)) == 0; } -bool isPowerOf2Float(float); -bool isPowerOf2Float(double); +bool isPowerOf2InvertibleFloat(float); +bool isPowerOf2InvertibleFloat(double); template<typename T, typename U> inline static T rotateLeft(T val, U count) { auto value = typename std::make_unsigned<T>::type(val); diff --git a/test/passes/optimize-instructions_all-features.txt b/test/passes/optimize-instructions_all-features.txt index edebe0bc2..f43316f3d 100644 --- a/test/passes/optimize-instructions_all-features.txt +++ b/test/passes/optimize-instructions_all-features.txt @@ -3018,12 +3018,9 @@ ) ) (drop - (i32.ne - (i32.and - (local.get $x) - (i32.const 1) - ) - (i32.const 0) + (i32.and + (local.get $x) + (i32.const 1) ) ) (drop @@ -3868,6 +3865,24 @@ (drop (i64.const 1) ) + (drop + (i32.and + (local.get $x) + (i32.const 1) + ) + ) + (drop + (i64.ne + (local.get $y) + (i64.const 0) + ) + ) + (drop + (i32.ne + (local.get $x) + (i32.const 0) + ) + ) ) (func $optimize-bitwise-oprations (param $x i32) (param $y i32) (param $z i64) (param $w i64) (drop diff --git a/test/passes/optimize-instructions_all-features.wast b/test/passes/optimize-instructions_all-features.wast index cf3938cdf..934ccc977 100644 --- a/test/passes/optimize-instructions_all-features.wast +++ b/test/passes/optimize-instructions_all-features.wast @@ -4395,6 +4395,30 @@ ) (i64.const 1) )) + ;; i32(bool(expr)) != 0 -> i32(bool(expr)) + (drop (i32.ne + (i32.and + (local.get $x) + (i32.const 1) + ) + (i32.const 0) + )) + ;; i32(bool(expr)) != 0 -> i32(bool(expr)) + (drop (i32.ne + (i64.ne + (local.get $y) + (i64.const 0) + ) + (i32.const 0) + )) + ;; (i32(expr) != 0) != 0 -> (expr != 0) + (drop (i32.ne + (i32.ne + (local.get $x) + (i32.const 0) + ) + (i32.const 0) + )) ) (func $optimize-bitwise-oprations (param $x i32) (param $y i32) (param $z i64) (param $w i64) ;; ~(1 << x) -> rotl(-2, x) |