diff options
-rw-r--r-- | src/ast/bits.h | 47 | ||||
-rw-r--r-- | src/ast/properties.h | 77 | ||||
-rw-r--r-- | src/passes/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 282 | ||||
-rw-r--r-- | src/passes/PickLoadSigns.cpp | 107 | ||||
-rw-r--r-- | src/passes/pass.cpp | 4 | ||||
-rw-r--r-- | src/passes/passes.h | 1 | ||||
-rw-r--r-- | test/dynamicLibrary.fromasm | 5 | ||||
-rw-r--r-- | test/dynamicLibrary.fromasm.imprecise | 5 | ||||
-rw-r--r-- | test/emcc_O2_hello_world.fromasm | 21 | ||||
-rw-r--r-- | test/emcc_O2_hello_world.fromasm.imprecise | 21 | ||||
-rw-r--r-- | test/emcc_hello_world.fromasm | 167 | ||||
-rw-r--r-- | test/emcc_hello_world.fromasm.imprecise | 167 | ||||
-rw-r--r-- | test/memorygrowth.fromasm | 21 | ||||
-rw-r--r-- | test/memorygrowth.fromasm.imprecise | 21 | ||||
-rw-r--r-- | test/passes/optimize-instructions.txt | 648 | ||||
-rw-r--r-- | test/passes/optimize-instructions.wast | 782 | ||||
-rw-r--r-- | test/passes/optimize-instructions_optimize-level=2_ignore-implicit-traps.txt | 10 | ||||
-rw-r--r-- | test/passes/pick-load-signs.txt | 263 | ||||
-rw-r--r-- | test/passes/pick-load-signs.wast | 260 |
20 files changed, 2535 insertions, 375 deletions
diff --git a/src/ast/bits.h b/src/ast/bits.h new file mode 100644 index 000000000..d88cb5edb --- /dev/null +++ b/src/ast/bits.h @@ -0,0 +1,47 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef wasm_ast_bits_h +#define wasm_ast_bits_h + +#include "support/bits.h" + +namespace wasm { + +struct Bits { + // get a mask to keep only the low # of bits + static int32_t lowBitMask(int32_t bits) { + uint32_t ret = -1; + if (bits >= 32) return ret; + 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(uint32_t mask) { + if (mask == uint32_t(-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); + } +}; + +} // namespace wasm + +#endif // wasm_ast_bits_h + diff --git a/src/ast/properties.h b/src/ast/properties.h index 9834c73d0..9121deba5 100644 --- a/src/ast/properties.h +++ b/src/ast/properties.h @@ -18,6 +18,7 @@ #define wasm_ast_properties_h #include "wasm.h" +#include "ast/bits.h" namespace wasm { @@ -52,6 +53,82 @@ struct Properties { default: return false; } } + + // Check if an expression is a sign-extend, and if so, returns the value + // that is extended, otherwise nullptr + static Expression* getSignExtValue(Expression* curr) { + if (auto* outer = curr->dynCast<Binary>()) { + if (outer->op == ShrSInt32) { + if (auto* outerConst = outer->right->dynCast<Const>()) { + if (auto* inner = outer->left->dynCast<Binary>()) { + if (inner->op == ShlInt32) { + if (auto* innerConst = inner->right->dynCast<Const>()) { + if (outerConst->value == innerConst->value) { + return inner->left; + } + } + } + } + } + } + } + return nullptr; + } + + // gets the size of the sign-extended value + static Index getSignExtBits(Expression* curr) { + return 32 - curr->cast<Binary>()->right->cast<Const>()->value.geti32(); + } + + // Check if an expression is almost a sign-extend: perhaps the inner shift + // is too large. We can split the shifts in that case, which is sometimes + // useful (e.g. if we can remove the signext) + static Expression* getAlmostSignExt(Expression* curr) { + if (auto* outer = curr->dynCast<Binary>()) { + if (outer->op == ShrSInt32) { + if (auto* outerConst = outer->right->dynCast<Const>()) { + if (auto* inner = outer->left->dynCast<Binary>()) { + if (inner->op == ShlInt32) { + if (auto* innerConst = inner->right->dynCast<Const>()) { + if (outerConst->value.leU(innerConst->value).geti32()) { + return inner->left; + } + } + } + } + } + } + } + return nullptr; + } + + // gets the size of the almost sign-extended value, as well as the + // extra shifts, if any + static Index getAlmostSignExtBits(Expression* curr, Index& extraShifts) { + extraShifts = curr->cast<Binary>()->left->cast<Binary>()->right->cast<Const>()->value.geti32() - + curr->cast<Binary>()->right->cast<Const>()->value.geti32(); + return getSignExtBits(curr); + } + + // Check if an expression is a zero-extend, and if so, returns the value + // that is extended, otherwise nullptr + static Expression* getZeroExtValue(Expression* curr) { + if (auto* binary = curr->dynCast<Binary>()) { + if (binary->op == AndInt32) { + if (auto* c = binary->right->dynCast<Const>()) { + if (Bits::getMaskedBits(c->value.geti32())) { + return binary->right; + } + } + } + } + return nullptr; + } + + // gets the size of the sign-extended value + static Index getZeroExtBits(Expression* curr) { + return Bits::getMaskedBits(curr->cast<Binary>()->right->cast<Const>()->value.geti32()); + } }; } // wasm diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt index 9db1c66ae..74f120e85 100644 --- a/src/passes/CMakeLists.txt +++ b/src/passes/CMakeLists.txt @@ -13,6 +13,7 @@ SET(passes_SOURCES NameManager.cpp NameList.cpp OptimizeInstructions.cpp + PickLoadSigns.cpp PostEmscripten.cpp Precompute.cpp Print.cpp diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index bb4748a97..79c01dee7 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -166,7 +166,10 @@ struct Match { // returns the maximum amount of bits used in an integer expression // not extremely precise (doesn't look into add operands, etc.) -static Index getMaxBits(Expression* curr) { +// LocalInfoProvider is an optional class that can provide answers about +// get_local. +template<typename LocalInfoProvider> +Index getMaxBits(Expression* curr, LocalInfoProvider* localInfoProvider) { if (auto* const_ = curr->dynCast<Const>()) { switch (curr->type) { case i32: return 32 - const_->value.countLeadingZeroes().geti32(); @@ -179,17 +182,17 @@ static Index getMaxBits(Expression* curr) { case AddInt32: case SubInt32: case MulInt32: case DivSInt32: case DivUInt32: case RemSInt32: case RemUInt32: case RotLInt32: case RotRInt32: return 32; - case AndInt32: case XorInt32: return std::min(getMaxBits(binary->left), getMaxBits(binary->right)); - case OrInt32: return std::max(getMaxBits(binary->left), getMaxBits(binary->right)); + case AndInt32: return std::min(getMaxBits(binary->left, localInfoProvider), getMaxBits(binary->right, localInfoProvider)); + case OrInt32: case XorInt32: return std::max(getMaxBits(binary->left, localInfoProvider), getMaxBits(binary->right, localInfoProvider)); case ShlInt32: { if (auto* shifts = binary->right->dynCast<Const>()) { - return std::min(Index(32), getMaxBits(binary->left) + shifts->value.geti32()); + return std::min(Index(32), getMaxBits(binary->left, localInfoProvider) + shifts->value.geti32()); } return 32; } case ShrUInt32: { if (auto* shift = binary->right->dynCast<Const>()) { - auto maxBits = getMaxBits(binary->left); + auto maxBits = getMaxBits(binary->left, localInfoProvider); auto shifts = std::min(Index(shift->value.geti32()), maxBits); // can ignore more shifts than zero us out return std::max(Index(0), maxBits - shifts); } @@ -197,7 +200,7 @@ static Index getMaxBits(Expression* curr) { } case ShrSInt32: { if (auto* shift = binary->right->dynCast<Const>()) { - auto maxBits = getMaxBits(binary->left); + auto maxBits = getMaxBits(binary->left, localInfoProvider); if (maxBits == 32) return 32; auto shifts = std::min(Index(shift->value.geti32()), maxBits); // can ignore more shifts than zero us out return std::max(Index(0), maxBits - shifts); @@ -225,9 +228,19 @@ static Index getMaxBits(Expression* curr) { case ClzInt32: case CtzInt32: case PopcntInt32: return 5; case ClzInt64: case CtzInt64: case PopcntInt64: return 6; case EqZInt32: case EqZInt64: return 1; - case WrapInt64: return std::min(Index(32), getMaxBits(unary->value)); + case WrapInt64: return std::min(Index(32), getMaxBits(unary->value, localInfoProvider)); default: {} } + } else if (auto* set = curr->dynCast<SetLocal>()) { + // a tee passes through the value + return getMaxBits(set->value, localInfoProvider); + } else if (auto* get = curr->dynCast<GetLocal>()) { + return localInfoProvider->getMaxBitsForLocal(get); + } else if (auto* load = curr->dynCast<Load>()) { + // if signed, then the sign-extension might fill all the bits + if (!load->signed_) { + return 8 * load->bytes; + } } switch (curr->type) { case i32: return 32; @@ -237,68 +250,95 @@ static Index getMaxBits(Expression* curr) { } } -// Check if an expression is a sign-extend, and if so, returns the value -// that is extended, otherwise nullptr -static Expression* getSignExt(Expression* curr) { - if (auto* outer = curr->dynCast<Binary>()) { - if (outer->op == ShrSInt32) { - if (auto* outerConst = outer->right->dynCast<Const>()) { - if (auto* inner = outer->left->dynCast<Binary>()) { - if (inner->op == ShlInt32) { - if (auto* innerConst = inner->right->dynCast<Const>()) { - if (outerConst->value == innerConst->value) { - return inner->left; - } - } - } - } - } +// looks through fallthrough operations, like tee_local, block fallthrough, etc. +// too and block fallthroughs, etc. +Expression* getFallthrough(Expression* curr) { + if (auto* set = curr->dynCast<SetLocal>()) { + if (set->isTee()) { + return getFallthrough(set->value); + } + } else if (auto* block = curr->dynCast<Block>()) { + // if no name, we can't be broken to, and then can look at the fallthrough + if (!block->name.is() && block->list.size() > 0) { + return getFallthrough(block->list.back()); } } - return nullptr; + return curr; } -// gets the size of the sign-extended value -static Index getSignExtBits(Expression* curr) { - return 32 - curr->cast<Binary>()->right->cast<Const>()->value.geti32(); -} +// Useful information about locals +struct LocalInfo { + static const Index kUnknown = Index(-1); -// Check if an expression is almost a sign-extend: perhaps the inner shift -// is too large. We can split the shifts in that case, which is sometimes -// useful (e.g. if we can remove the signext) -static Expression* getAlmostSignExt(Expression* curr) { - if (auto* outer = curr->dynCast<Binary>()) { - if (outer->op == ShrSInt32) { - if (auto* outerConst = outer->right->dynCast<Const>()) { - if (auto* inner = outer->left->dynCast<Binary>()) { - if (inner->op == ShlInt32) { - if (auto* innerConst = inner->right->dynCast<Const>()) { - if (outerConst->value.leU(innerConst->value).geti32()) { - return inner->left; - } - } - } - } + Index maxBits; + Index signExtedBits; +}; + +struct LocalScanner : PostWalker<LocalScanner, Visitor<LocalScanner>> { + std::vector<LocalInfo>& localInfo; + + LocalScanner(std::vector<LocalInfo>& localInfo) : localInfo(localInfo) {} + + void doWalkFunction(Function* func) { + // prepare + localInfo.resize(func->getNumLocals()); + for (Index i = 0; i < func->getNumLocals(); i++) { + auto& info = localInfo[i]; + if (func->isParam(i)) { + info.maxBits = getBitsForType(func->getLocalType(i)); // worst-case + info.signExtedBits = LocalInfo::kUnknown; // we will never know anything + } else { + info.maxBits = info.signExtedBits = 0; // we are open to learning + } + } + // walk + PostWalker<LocalScanner, Visitor<LocalScanner>>::doWalkFunction(func); + // finalize + for (Index i = 0; i < func->getNumLocals(); i++) { + auto& info = localInfo[i]; + if (info.signExtedBits == LocalInfo::kUnknown) { + info.signExtedBits = 0; } } } - return nullptr; -} -// gets the size of the almost sign-extended value, as well as the -// extra shifts, if any -static Index getAlmostSignExtBits(Expression* curr, Index& extraShifts) { - extraShifts = curr->cast<Binary>()->left->cast<Binary>()->right->cast<Const>()->value.geti32() - - curr->cast<Binary>()->right->cast<Const>()->value.geti32(); - return getSignExtBits(curr); -} + void visitSetLocal(SetLocal* curr) { + auto* func = getFunction(); + if (func->isParam(curr->index)) return; + auto type = getFunction()->getLocalType(curr->index); + if (type != i32 && type != i64) return; + // an integer var, worth processing + auto* value = getFallthrough(curr->value); + auto& info = localInfo[curr->index]; + info.maxBits = std::max(info.maxBits, getMaxBits(value, this)); + auto signExtBits = LocalInfo::kUnknown; + if (Properties::getSignExtValue(value)) { + signExtBits = Properties::getSignExtBits(value); + } else if (auto* load = value->dynCast<Load>()) { + if (load->signed_) { + signExtBits = load->bytes * 8; + } + } + if (info.signExtedBits == 0) { + info.signExtedBits = signExtBits; // first info we see + } else if (info.signExtedBits != signExtBits) { + info.signExtedBits = LocalInfo::kUnknown; // contradictory information, give up + } + } -// get a mask to keep only the low # of bits -static int32_t lowBitMask(int32_t bits) { - uint32_t ret = -1; - if (bits >= 32) return ret; - return ret >> (32 - bits); -} + // define this for the templated getMaxBits method. we know nothing here yet about locals, so return the maxes + Index getMaxBitsForLocal(GetLocal* get) { + return getBitsForType(get->type); + } + + Index getBitsForType(WasmType type) { + switch (type) { + case i32: return 32; + case i64: return 64; + default: return -1; + } + } +}; // Main pass class struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions, UnifiedExpressionVisitor<OptimizeInstructions>>> { @@ -312,6 +352,16 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions, #endif } + void doWalkFunction(Function* func) { + // first, scan locals + { + LocalScanner scanner(localInfo); + scanner.walkFunction(func); + } + // main walk + WalkerPass<PostWalker<OptimizeInstructions, UnifiedExpressionVisitor<OptimizeInstructions>>>::doWalkFunction(func); + } + void visitExpression(Expression* curr) { // we may be able to apply multiple patterns, one may open opportunities that look deeper NB: patterns must not have cycles while (1) { @@ -351,40 +401,63 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions, std::swap(binary->left, binary->right); } } - if (auto* ext = getAlmostSignExt(binary)) { + if (auto* ext = Properties::getAlmostSignExt(binary)) { Index extraShifts; - auto bits = getAlmostSignExtBits(binary, extraShifts); - auto* load = ext->dynCast<Load>(); - // pattern match a load of 8 bits and a sign extend using a shl of 24 then shr_s of 24 as well, etc. - if (load && ((load->bytes == 1 && bits == 8) || (load->bytes == 2 && bits == 16))) { - load->signed_ = true; - return removeAlmostSignExt(binary); + auto bits = Properties::getAlmostSignExtBits(binary, extraShifts); + if (auto* load = getFallthrough(ext)->dynCast<Load>()) { + // pattern match a load of 8 bits and a sign extend using a shl of 24 then shr_s of 24 as well, etc. + if ((load->bytes == 1 && bits == 8) || (load->bytes == 2 && bits == 16)) { + // if the value falls through, we can't alter the load, as it might be captured in a tee + if (load->signed_ == true || load == ext) { + load->signed_ = true; + return removeAlmostSignExt(binary); + } + } } // if the sign-extend input cannot have a sign bit, we don't need it - if (getMaxBits(ext) + extraShifts < bits) { + // we also don't need it if it already has an identical-sized sign extend + if (getMaxBits(ext, this) + extraShifts < bits || isSignExted(ext, bits)) { return removeAlmostSignExt(binary); } - } else if (binary->op == EqInt32) { + } else if (binary->op == EqInt32 || binary->op == NeInt32) { if (auto* c = binary->right->dynCast<Const>()) { - if (auto* ext = getSignExt(binary->left)) { + if (auto* ext = Properties::getSignExtValue(binary->left)) { // we are comparing a sign extend to a constant, which means we can use a cheaper zext - auto bits = getSignExtBits(binary->left); + auto bits = Properties::getSignExtBits(binary->left); binary->left = makeZeroExt(ext, bits); // the const we compare to only needs the relevant bits - c->value = c->value.and_(Literal(lowBitMask(bits))); + c->value = c->value.and_(Literal(Bits::lowBitMask(bits))); return binary; } - if (c->value.geti32() == 0) { + if (binary->op == EqInt32 && c->value.geti32() == 0) { // equal 0 => eqz return Builder(*getModule()).makeUnary(EqZInt32, binary->left); } - } else if (auto* left = getSignExt(binary->left)) { - if (auto* right = getSignExt(binary->right)) { + } else if (auto* left = Properties::getSignExtValue(binary->left)) { + if (auto* right = Properties::getSignExtValue(binary->right)) { // we are comparing two sign-exts, so we may as well replace both with cheaper zexts - auto bits = getSignExtBits(binary->left); + auto bits = Properties::getSignExtBits(binary->left); binary->left = makeZeroExt(left, bits); binary->right = makeZeroExt(right, bits); return binary; + } else if (auto* load = binary->right->dynCast<Load>()) { + // we are comparing a load to a sign-ext, we may be able to switch to zext + auto leftBits = Properties::getSignExtBits(binary->left); + if (load->signed_ && leftBits == load->bytes * 8) { + load->signed_ = false; + binary->left = makeZeroExt(left, leftBits); + return binary; + } + } + } else if (auto* load = binary->left->dynCast<Load>()) { + if (auto* right = Properties::getSignExtValue(binary->right)) { + // we are comparing a load to a sign-ext, we may be able to switch to zext + auto rightBits = Properties::getSignExtBits(binary->right); + if (load->signed_ && rightBits == load->bytes * 8) { + load->signed_ = false; + binary->right = makeZeroExt(right, rightBits); + return binary; + } } } // note that both left and right may be consts, but then we let precompute compute the constant result @@ -404,11 +477,13 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions, if ((load->bytes == 1 && mask == 0xff) || (load->bytes == 2 && mask == 0xffff)) { load->signed_ = false; - return load; + return binary->left; + } + } else if (auto maskedBits = Bits::getMaskedBits(mask)) { + if (getMaxBits(binary->left, this) <= maskedBits) { + // a mask of lower bits is not needed if we are already smaller + return binary->left; } - } else if (mask == 1 && Properties::emitsBoolean(binary->left)) { - // (bool) & 1 does not need the outer mask - return binary->left; } } // the square of some operations can be merged @@ -468,6 +543,13 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions, default: {} } } + // eqz of a sign extension can be of zero-extension + if (auto* ext = Properties::getSignExtValue(unary->value)) { + // we are comparing a sign extend to a constant, which means we can use a cheaper zext + auto bits = Properties::getSignExtBits(unary->value); + unary->value = makeZeroExt(ext, bits); + return unary; + } } } else if (auto* set = curr->dynCast<SetGlobal>()) { // optimize out a set of a get @@ -518,6 +600,12 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions, } } } + } else if (auto* ext = Properties::getSignExtValue(binary)) { + // if sign extending the exact bit size we store, we can skip the extension + // if extending something bigger, then we just alter bits we don't save anyhow + if (Properties::getSignExtBits(binary) >= store->bytes * 8) { + store->value = ext; + } } } else if (auto* unary = store->value->dynCast<Unary>()) { if (unary->op == WrapInt64) { @@ -530,7 +618,15 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions, return nullptr; } + Index getMaxBitsForLocal(GetLocal* get) { + // check what we know about the local + return localInfo[get->index].maxBits; + } + private: + // Information about our locals + std::vector<LocalInfo> localInfo; + // Optimize given that the expression is flowing into a boolean context Expression* optimizeBoolean(Expression* boolean) { if (auto* unary = boolean->dynCast<Unary>()) { @@ -554,6 +650,10 @@ private: } } } + if (auto* ext = Properties::getSignExtValue(binary)) { + // use a cheaper zero-extent, we just care about the boolean value anyhow + return makeZeroExt(ext, Properties::getSignExtBits(binary)); + } } else if (auto* block = boolean->dynCast<Block>()) { if (block->type == i32 && block->list.size() > 0) { block->list.back() = optimizeBoolean(block->list.back()); @@ -611,7 +711,15 @@ private: }; // find all factors seek(binary, 1); - if (constants.size() <= 1) return nullptr; // nothing to do + if (constants.size() <= 1) { + // nothing much to do, except for the trivial case of adding/subbing a zero + if (auto* c = binary->right->dynCast<Const>()) { + if (c->value.geti32() == 0) { + return binary->left; + } + } + return nullptr; + } // wipe out all constants, we'll replace with a single added one for (auto* c : constants) { c->value = Literal(int32_t(0)); @@ -731,7 +839,7 @@ private: Expression* makeZeroExt(Expression* curr, int32_t bits) { Builder builder(*getModule()); - return builder.makeBinary(AndInt32, curr, builder.makeConst(Literal(lowBitMask(bits)))); + return builder.makeBinary(AndInt32, curr, builder.makeConst(Literal(Bits::lowBitMask(bits)))); } // given an "almost" sign extend - either a proper one, or it @@ -748,6 +856,18 @@ private: innerConst->value = innerConst->value.sub(outerConst->value); return inner; } + + // check if an expression is already sign-extended + bool isSignExted(Expression* curr, Index bits) { + if (Properties::getSignExtValue(curr)) { + return Properties::getSignExtBits(curr) == bits; + } + if (auto* get = curr->dynCast<GetLocal>()) { + // check what we know about the local + return localInfo[get->index].signExtedBits == bits; + } + return false; + } }; Pass *createOptimizeInstructionsPass() { diff --git a/src/passes/PickLoadSigns.cpp b/src/passes/PickLoadSigns.cpp new file mode 100644 index 000000000..6e44fddfe --- /dev/null +++ b/src/passes/PickLoadSigns.cpp @@ -0,0 +1,107 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <wasm.h> +#include <pass.h> +#include <ast/properties.h> + +namespace wasm { + +// Adjust load signedness based on usage. If a load only has uses that sign or +// unsign it anyhow, then it could be either, and picking the popular one can +// help remove the most sign/unsign operations +// unsigned, then it could be either + +struct PickLoadSigns : public WalkerPass<ExpressionStackWalker<PickLoadSigns, Visitor<PickLoadSigns>>> { + bool isFunctionParallel() override { return true; } + + Pass* create() override { return new PickLoadSigns; } + + struct Usage { + Index signedUsages = 0; + Index signedBits; + Index unsignedUsages = 0; + Index unsignedBits; + Index totalUsages = 0; + }; + std::vector<Usage> usages; // local index => usage + + std::unordered_map<Load*, Index> loads; // loads that write to a local => the local + + void doWalkFunction(Function* func) { + // prepare + usages.resize(func->getNumLocals()); + // walk + ExpressionStackWalker<PickLoadSigns, Visitor<PickLoadSigns>>::doWalkFunction(func); + // optimize based on the info we saw + for (auto& pair : loads) { + auto* load = pair.first; + auto index = pair.second; + auto& usage = usages[index]; + // if we can't optimize, give up + if (usage.totalUsages == 0 || // no usages, so no idea + usage.signedUsages + usage.unsignedUsages != usage.totalUsages || // non-sign/unsigned usages, so cannot change + (usage.signedUsages != 0 && usage.signedBits != load->bytes * 8) || // sign usages exist but the wrong size + (usage.unsignedUsages != 0 && usage.unsignedBits != load->bytes * 8)) { // unsigned usages exist but the wrong size + continue; + } + // we can pick the optimal one. our hope is to remove 2 items per + // signed use (two shifts), so we factor that in + load->signed_ = usage.signedUsages * 2 >= usage.unsignedUsages; + } + } + + 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* parent = expressionStack[expressionStack.size() - 2]; + if (Properties::getZeroExtValue(parent)) { + auto bits = Properties::getZeroExtBits(parent); + if (usage.unsignedUsages == 0) { + usage.unsignedBits = bits; + } else if (usage.unsignedBits != bits) { + usage.unsignedBits = 0; + } + usage.unsignedUsages++; + } else if (expressionStack.size() >= 3) { + auto* grandparent = expressionStack[expressionStack.size() - 3]; + if (Properties::getSignExtValue(grandparent)) { + auto bits = Properties::getSignExtBits(grandparent); + if (usage.signedUsages == 0) { + usage.signedBits = bits; + } else if (usage.signedBits != bits) { + usage.signedBits = 0; + } + usage.signedUsages++; + } + } + } + } + + void visitSetLocal(SetLocal* curr) { + if (auto* load = curr->value->dynCast<Load>()) { + loads[load] = curr->index; + } + } +}; + +Pass *createPickLoadSignsPass() { + return new PickLoadSigns(); +} + +} // namespace wasm diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 32b596eef..df98590c5 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); @@ -112,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/src/passes/passes.h b/src/passes/passes.h index cbfc48327..83bf556d8 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -39,6 +39,7 @@ Pass *createMetricsPass(); Pass *createNameListPass(); Pass *createNameManagerPass(); Pass *createOptimizeInstructionsPass(); +Pass *createPickLoadSignsPass(); Pass *createPostEmscriptenPass(); Pass *createPrinterPass(); Pass *createPrintCallGraphPass(); diff --git a/test/dynamicLibrary.fromasm b/test/dynamicLibrary.fromasm index df7825187..68cea0677 100644 --- a/test/dynamicLibrary.fromasm +++ b/test/dynamicLibrary.fromasm @@ -45,10 +45,7 @@ ) (drop (call $_puts - (i32.add - (get_global $memoryBase) - (i32.const 0) - ) + (get_global $memoryBase) ) ) (set_global $STACKTOP diff --git a/test/dynamicLibrary.fromasm.imprecise b/test/dynamicLibrary.fromasm.imprecise index 357d324cd..0c656a8e6 100644 --- a/test/dynamicLibrary.fromasm.imprecise +++ b/test/dynamicLibrary.fromasm.imprecise @@ -44,10 +44,7 @@ ) (drop (call $_puts - (i32.add - (get_global $memoryBase) - (i32.const 0) - ) + (get_global $memoryBase) ) ) (set_global $STACKTOP diff --git a/test/emcc_O2_hello_world.fromasm b/test/emcc_O2_hello_world.fromasm index 5aa32979b..f885bf5b8 100644 --- a/test/emcc_O2_hello_world.fromasm +++ b/test/emcc_O2_hello_world.fromasm @@ -8555,15 +8555,9 @@ ) ) (if - (i32.shr_s - (i32.shl - (i32.and - (get_local $1) - (i32.const 255) - ) - (i32.const 24) - ) - (i32.const 24) + (i32.and + (get_local $1) + (i32.const 255) ) (block (set_local $1 @@ -9684,12 +9678,9 @@ (func $dynCall_ii (param $0 i32) (param $1 i32) (result i32) (call_indirect $FUNCSIG$ii (get_local $1) - (i32.add - (i32.and - (get_local $0) - (i32.const 1) - ) - (i32.const 0) + (i32.and + (get_local $0) + (i32.const 1) ) ) ) diff --git a/test/emcc_O2_hello_world.fromasm.imprecise b/test/emcc_O2_hello_world.fromasm.imprecise index 39ed6731f..d0d86a165 100644 --- a/test/emcc_O2_hello_world.fromasm.imprecise +++ b/test/emcc_O2_hello_world.fromasm.imprecise @@ -8554,15 +8554,9 @@ ) ) (if - (i32.shr_s - (i32.shl - (i32.and - (get_local $1) - (i32.const 255) - ) - (i32.const 24) - ) - (i32.const 24) + (i32.and + (get_local $1) + (i32.const 255) ) (block (set_local $1 @@ -9673,12 +9667,9 @@ (func $dynCall_ii (param $0 i32) (param $1 i32) (result i32) (call_indirect $FUNCSIG$ii (get_local $1) - (i32.add - (i32.and - (get_local $0) - (i32.const 1) - ) - (i32.const 0) + (i32.and + (get_local $0) + (i32.const 1) ) ) ) diff --git a/test/emcc_hello_world.fromasm b/test/emcc_hello_world.fromasm index 71ce805ba..ecbadd304 100644 --- a/test/emcc_hello_world.fromasm +++ b/test/emcc_hello_world.fromasm @@ -174,28 +174,25 @@ (block $switch-case0 (block $switch-case (br_table $switch-case $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-case0 $switch-default - (i32.sub - (tee_local $3 - (i32.and - (tee_local $3 - (call $_bitshift64Lshr - (tee_local $2 - (i32.load - (get_global $tempDoublePtr) - ) + (tee_local $3 + (i32.and + (tee_local $3 + (call $_bitshift64Lshr + (tee_local $2 + (i32.load + (get_global $tempDoublePtr) ) - (tee_local $4 - (i32.load offset=4 - (get_global $tempDoublePtr) - ) + ) + (tee_local $4 + (i32.load offset=4 + (get_global $tempDoublePtr) ) - (i32.const 52) ) + (i32.const 52) ) - (i32.const 2047) ) + (i32.const 2047) ) - (i32.const 0) ) ) ) @@ -328,7 +325,7 @@ ) ) (if - (i32.load8_u + (i32.load8_s (get_local $0) ) (block @@ -1471,7 +1468,7 @@ ) (if (i32.ne - (i32.load8_u + (i32.load8_s (i32.add (get_local $0) (tee_local $6 @@ -1944,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 @@ -2504,13 +2498,10 @@ ) (br_if $__rjti$9 (i32.eqz - (i32.and - (tee_local $7 - (i32.load8_s - (get_local $5) - ) + (tee_local $7 + (i32.load8_s + (get_local $5) ) - (i32.const 255) ) ) ) @@ -2525,15 +2516,12 @@ (block $switch-case0 (block $switch-case (br_table $switch-case0 $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-case $switch-default - (i32.sub - (i32.shr_s - (i32.shl - (get_local $7) - (i32.const 24) - ) + (i32.shr_s + (i32.shl + (get_local $7) (i32.const 24) ) - (i32.const 0) + (i32.const 24) ) ) ) @@ -2565,7 +2553,7 @@ (loop $while-in (br_if $label$break$L12 (i32.ne - (i32.load8_u offset=1 + (i32.load8_s offset=1 (get_local $6) ) (i32.const 37) @@ -2579,7 +2567,7 @@ ) (br_if $while-in (i32.eq - (i32.load8_u + (i32.load8_s (tee_local $6 (i32.add (get_local $6) @@ -2638,21 +2626,15 @@ (i32.lt_u (tee_local $8 (i32.add - (i32.shr_s - (i32.shl - (tee_local $11 - (i32.load8_s - (tee_local $10 - (i32.add - (get_local $6) - (i32.const 1) - ) - ) + (tee_local $11 + (i32.load8_s + (tee_local $10 + (i32.add + (get_local $6) + (i32.const 1) ) ) - (i32.const 24) ) - (i32.const 24) ) (i32.const -48) ) @@ -2671,7 +2653,7 @@ (get_local $10) (tee_local $11 (i32.eq - (i32.load8_u offset=2 + (i32.load8_s offset=2 (get_local $6) ) (i32.const 36) @@ -2778,21 +2760,15 @@ (i32.eq (i32.and (tee_local $6 - (i32.shr_s - (i32.shl - (tee_local $1 - (i32.load8_s - (tee_local $10 - (i32.add - (get_local $10) - (i32.const 1) - ) - ) + (tee_local $1 + (i32.load8_s + (tee_local $10 + (i32.add + (get_local $10) + (i32.const 1) ) ) - (i32.const 24) ) - (i32.const 24) ) ) (i32.const -32) @@ -2846,7 +2822,7 @@ ) (br_if $__rjti$0 (i32.ne - (i32.load8_u offset=2 + (i32.load8_s offset=2 (get_local $10) ) (i32.const 36) @@ -3078,7 +3054,7 @@ (set_local $6 (if i32 (i32.eq - (i32.load8_u + (i32.load8_s (get_local $10) ) (i32.const 46) @@ -3086,18 +3062,15 @@ (block i32 (if (i32.ne - (i32.and - (tee_local $8 - (i32.load8_s - (tee_local $6 - (i32.add - (get_local $10) - (i32.const 1) - ) + (tee_local $8 + (i32.load8_s + (tee_local $6 + (i32.add + (get_local $10) + (i32.const 1) ) ) ) - (i32.const 255) ) (i32.const 42) ) @@ -3106,13 +3079,7 @@ (i32.lt_u (tee_local $9 (i32.add - (i32.shr_s - (i32.shl - (get_local $8) - (i32.const 24) - ) - (i32.const 24) - ) + (get_local $8) (i32.const -48) ) ) @@ -3196,7 +3163,7 @@ ) (if (i32.eq - (i32.load8_u offset=3 + (i32.load8_s offset=3 (get_local $10) ) (i32.const 36) @@ -3557,10 +3524,7 @@ (block $switch-case20 (block $switch-case19 (br_table $switch-case19 $switch-case20 $switch-case21 $switch-case22 $switch-case23 $switch-default26 $switch-case24 $switch-case25 $switch-default26 - (i32.sub - (get_local $9) - (i32.const 0) - ) + (get_local $9) ) ) (i32.store @@ -4225,7 +4189,7 @@ ) (if f64 (i32.eq - (i32.load8_u + (i32.load8_s (get_local $9) ) (i32.const 45) @@ -5285,7 +5249,7 @@ (block (br_if $do-once83 (i32.ne - (i32.load8_u + (i32.load8_s (get_local $31) ) (i32.const 45) @@ -5531,10 +5495,7 @@ (tee_local $5 (i32.add (i32.xor - (i32.and - (get_local $32) - (i32.const 1) - ) + (get_local $32) (i32.const 1) ) (get_local $17) @@ -9414,13 +9375,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) ) @@ -15761,12 +15719,9 @@ (func $dynCall_ii (param $0 i32) (param $1 i32) (result i32) (call_indirect $FUNCSIG$ii (get_local $1) - (i32.add - (i32.and - (get_local $0) - (i32.const 1) - ) - (i32.const 0) + (i32.and + (get_local $0) + (i32.const 1) ) ) ) diff --git a/test/emcc_hello_world.fromasm.imprecise b/test/emcc_hello_world.fromasm.imprecise index 58dc7b313..52fa498da 100644 --- a/test/emcc_hello_world.fromasm.imprecise +++ b/test/emcc_hello_world.fromasm.imprecise @@ -171,28 +171,25 @@ (block $switch-case0 (block $switch-case (br_table $switch-case $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-case0 $switch-default - (i32.sub - (tee_local $3 - (i32.and - (tee_local $3 - (call $_bitshift64Lshr - (tee_local $2 - (i32.load - (get_global $tempDoublePtr) - ) + (tee_local $3 + (i32.and + (tee_local $3 + (call $_bitshift64Lshr + (tee_local $2 + (i32.load + (get_global $tempDoublePtr) ) - (tee_local $4 - (i32.load offset=4 - (get_global $tempDoublePtr) - ) + ) + (tee_local $4 + (i32.load offset=4 + (get_global $tempDoublePtr) ) - (i32.const 52) ) + (i32.const 52) ) - (i32.const 2047) ) + (i32.const 2047) ) - (i32.const 0) ) ) ) @@ -325,7 +322,7 @@ ) ) (if - (i32.load8_u + (i32.load8_s (get_local $0) ) (block @@ -1468,7 +1465,7 @@ ) (if (i32.ne - (i32.load8_u + (i32.load8_s (i32.add (get_local $0) (tee_local $6 @@ -1941,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 @@ -2447,13 +2441,10 @@ ) (br_if $__rjti$9 (i32.eqz - (i32.and - (tee_local $7 - (i32.load8_s - (get_local $5) - ) + (tee_local $7 + (i32.load8_s + (get_local $5) ) - (i32.const 255) ) ) ) @@ -2468,15 +2459,12 @@ (block $switch-case0 (block $switch-case (br_table $switch-case0 $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-default $switch-case $switch-default - (i32.sub - (i32.shr_s - (i32.shl - (get_local $7) - (i32.const 24) - ) + (i32.shr_s + (i32.shl + (get_local $7) (i32.const 24) ) - (i32.const 0) + (i32.const 24) ) ) ) @@ -2508,7 +2496,7 @@ (loop $while-in (br_if $label$break$L12 (i32.ne - (i32.load8_u offset=1 + (i32.load8_s offset=1 (get_local $6) ) (i32.const 37) @@ -2522,7 +2510,7 @@ ) (br_if $while-in (i32.eq - (i32.load8_u + (i32.load8_s (tee_local $6 (i32.add (get_local $6) @@ -2581,21 +2569,15 @@ (i32.lt_u (tee_local $8 (i32.add - (i32.shr_s - (i32.shl - (tee_local $11 - (i32.load8_s - (tee_local $10 - (i32.add - (get_local $6) - (i32.const 1) - ) - ) + (tee_local $11 + (i32.load8_s + (tee_local $10 + (i32.add + (get_local $6) + (i32.const 1) ) ) - (i32.const 24) ) - (i32.const 24) ) (i32.const -48) ) @@ -2614,7 +2596,7 @@ (get_local $10) (tee_local $11 (i32.eq - (i32.load8_u offset=2 + (i32.load8_s offset=2 (get_local $6) ) (i32.const 36) @@ -2721,21 +2703,15 @@ (i32.eq (i32.and (tee_local $6 - (i32.shr_s - (i32.shl - (tee_local $1 - (i32.load8_s - (tee_local $10 - (i32.add - (get_local $10) - (i32.const 1) - ) - ) + (tee_local $1 + (i32.load8_s + (tee_local $10 + (i32.add + (get_local $10) + (i32.const 1) ) ) - (i32.const 24) ) - (i32.const 24) ) ) (i32.const -32) @@ -2789,7 +2765,7 @@ ) (br_if $__rjti$0 (i32.ne - (i32.load8_u offset=2 + (i32.load8_s offset=2 (get_local $10) ) (i32.const 36) @@ -3021,7 +2997,7 @@ (set_local $6 (if i32 (i32.eq - (i32.load8_u + (i32.load8_s (get_local $10) ) (i32.const 46) @@ -3029,18 +3005,15 @@ (block i32 (if (i32.ne - (i32.and - (tee_local $8 - (i32.load8_s - (tee_local $6 - (i32.add - (get_local $10) - (i32.const 1) - ) + (tee_local $8 + (i32.load8_s + (tee_local $6 + (i32.add + (get_local $10) + (i32.const 1) ) ) ) - (i32.const 255) ) (i32.const 42) ) @@ -3049,13 +3022,7 @@ (i32.lt_u (tee_local $9 (i32.add - (i32.shr_s - (i32.shl - (get_local $8) - (i32.const 24) - ) - (i32.const 24) - ) + (get_local $8) (i32.const -48) ) ) @@ -3139,7 +3106,7 @@ ) (if (i32.eq - (i32.load8_u offset=3 + (i32.load8_s offset=3 (get_local $10) ) (i32.const 36) @@ -3500,10 +3467,7 @@ (block $switch-case20 (block $switch-case19 (br_table $switch-case19 $switch-case20 $switch-case21 $switch-case22 $switch-case23 $switch-default26 $switch-case24 $switch-case25 $switch-default26 - (i32.sub - (get_local $9) - (i32.const 0) - ) + (get_local $9) ) ) (i32.store @@ -4186,7 +4150,7 @@ (get_local $15) ) (i32.eq - (i32.load8_u + (i32.load8_s (get_local $9) ) (i32.const 45) @@ -5222,7 +5186,7 @@ (block (br_if $do-once83 (i32.ne - (i32.load8_u + (i32.load8_s (get_local $31) ) (i32.const 45) @@ -5468,10 +5432,7 @@ (tee_local $5 (i32.add (i32.xor - (i32.and - (get_local $32) - (i32.const 1) - ) + (get_local $32) (i32.const 1) ) (get_local $17) @@ -9351,13 +9312,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) ) @@ -15697,12 +15655,9 @@ (func $dynCall_ii (param $0 i32) (param $1 i32) (result i32) (call_indirect $FUNCSIG$ii (get_local $1) - (i32.add - (i32.and - (get_local $0) - (i32.const 1) - ) - (i32.const 0) + (i32.and + (get_local $0) + (i32.const 1) ) ) ) diff --git a/test/memorygrowth.fromasm b/test/memorygrowth.fromasm index ef7dc1a78..4a3a60955 100644 --- a/test/memorygrowth.fromasm +++ b/test/memorygrowth.fromasm @@ -8474,15 +8474,9 @@ ) ) (if - (i32.shr_s - (i32.shl - (i32.and - (get_local $1) - (i32.const 255) - ) - (i32.const 24) - ) - (i32.const 24) + (i32.and + (get_local $1) + (i32.const 255) ) (block (set_local $1 @@ -9752,12 +9746,9 @@ (func $kb (param $0 i32) (param $1 i32) (result i32) (call_indirect $FUNCSIG$ii (get_local $1) - (i32.add - (i32.and - (get_local $0) - (i32.const 1) - ) - (i32.const 0) + (i32.and + (get_local $0) + (i32.const 1) ) ) ) diff --git a/test/memorygrowth.fromasm.imprecise b/test/memorygrowth.fromasm.imprecise index 2a32f7528..46ec796a5 100644 --- a/test/memorygrowth.fromasm.imprecise +++ b/test/memorygrowth.fromasm.imprecise @@ -8473,15 +8473,9 @@ ) ) (if - (i32.shr_s - (i32.shl - (i32.and - (get_local $1) - (i32.const 255) - ) - (i32.const 24) - ) - (i32.const 24) + (i32.and + (get_local $1) + (i32.const 255) ) (block (set_local $1 @@ -9741,12 +9735,9 @@ (func $kb (param $0 i32) (param $1 i32) (result i32) (call_indirect $FUNCSIG$ii (get_local $1) - (i32.add - (i32.and - (get_local $0) - (i32.const 1) - ) - (i32.const 0) + (i32.and + (get_local $0) + (i32.const 1) ) ) ) diff --git a/test/passes/optimize-instructions.txt b/test/passes/optimize-instructions.txt index 03f0f7074..d70e6a9c5 100644 --- a/test/passes/optimize-instructions.txt +++ b/test/passes/optimize-instructions.txt @@ -4,6 +4,7 @@ (type $2 (func (result i32))) (type $3 (func (param i32) (result i32))) (type $4 (func (param i32 i32))) + (type $5 (func (param i32))) (memory $0 0) (export "load-off-2" (func $load-off-2)) (func $f (type $0) (param $i1 i32) (param $i2 i64) @@ -668,15 +669,15 @@ (drop (i32.xor (i32.const 127) - (i32.const 128) + (i32.const 126) ) ) (drop (i32.shr_s (i32.shl (i32.xor + (i32.const 127) (i32.const 128) - (i32.const 129) ) (i32.const 24) ) @@ -913,6 +914,21 @@ (i32.const 25) ) ) + (drop + (i32.shr_s + (i32.shl + (i32.xor + (i32.le_u + (get_local $0) + (i32.const 2) + ) + (get_local $0) + ) + (i32.const 24) + ) + (i32.const 24) + ) + ) ) (func $linear-sums (type $4) (param $0 i32) (param $1 i32) (drop @@ -1079,4 +1095,632 @@ ) ) ) + (func $sign-ext-ne (type $4) (param $0 i32) (param $1 i32) + (drop + (i32.ne + (i32.and + (get_local $0) + (i32.const 255) + ) + (i32.const 232) + ) + ) + (drop + (i32.ne + (i32.and + (get_local $0) + (i32.const 255) + ) + (i32.const 111) + ) + ) + (drop + (i32.ne + (i32.and + (get_local $0) + (i32.const 255) + ) + (i32.and + (get_local $1) + (i32.const 255) + ) + ) + ) + ) + (func $sign-ext-eqz (type $4) (param $0 i32) (param $1 i32) + (drop + (i32.eqz + (i32.and + (get_local $0) + (i32.const 255) + ) + ) + ) + ) + (func $sign-ext-boolean (type $4) (param $0 i32) (param $1 i32) + (drop + (if i32 + (i32.and + (get_local $0) + (i32.const 255) + ) + (i32.const 100) + (i32.const 200) + ) + ) + ) + (func $add-sub-zero (type $4) (param $0 i32) (param $1 i32) + (drop + (get_local $0) + ) + (drop + (get_local $0) + ) + ) + (func $store-signext (type $5) (param $0 i32) + (i32.store8 + (i32.const 8) + (get_local $0) + ) + (i32.store8 + (i32.const 8) + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 25) + ) + (i32.const 25) + ) + ) + (i32.store8 + (i32.const 8) + (get_local $0) + ) + (i32.store16 + (i32.const 8) + (get_local $0) + ) + (i32.store16 + (i32.const 8) + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 17) + ) + (i32.const 17) + ) + ) + (i32.store16 + (i32.const 8) + (get_local $0) + ) + (i32.store + (i32.const 8) + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 16) + ) + (i32.const 16) + ) + ) + (i32.store + (i32.const 8) + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 8) + ) + (i32.const 8) + ) + ) + ) + (func $sign-ext-tee (type $4) (param $0 i32) (param $1 i32) + (drop + (i32.shr_s + (i32.shl + (tee_local $0 + (i32.const 128) + ) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (tee_local $0 + (i32.const 127) + ) + ) + ) + (func $sign-ext-load (type $4) (param $0 i32) (param $1 i32) + (drop + (i32.load8_s + (i32.const 256) + ) + ) + (drop + (i32.shr_s + (i32.shl + (i32.shr_u + (i32.load8_s + (i32.const 256) + ) + (i32.const 1) + ) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (i32.shr_u + (i32.load8_u + (i32.const 256) + ) + (i32.const 1) + ) + ) + (drop + (i32.load16_s + (i32.const 256) + ) + ) + (drop + (tee_local $1 + (i32.load8_s + (i32.const 1) + ) + ) + ) + (drop + (i32.shr_s + (i32.shl + (tee_local $1 + (i32.load8_u + (i32.const 1) + ) + ) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (i32.and + (tee_local $1 + (i32.load8_s + (i32.const 1) + ) + ) + (i32.const 255) + ) + ) + (drop + (tee_local $1 + (i32.load8_u + (i32.const 1) + ) + ) + ) + ) + (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) + ) + ) + ) + (func $local-info-zero-ext (type $4) (param $0 i32) (param $1 i32) + (local $x i32) + (local $y i32) + (local $z i32) + (local $w i32) + (set_local $x + (i32.const 212) + ) + (drop + (get_local $x) + ) + (set_local $y + (i32.const 500) + ) + (drop + (i32.and + (get_local $y) + (i32.const 255) + ) + ) + (set_local $0 + (i32.const 212) + ) + (drop + (i32.and + (get_local $0) + (i32.const 255) + ) + ) + (set_local $z + (i32.const 212) + ) + (set_local $z + (i32.const 220) + ) + (drop + (get_local $z) + ) + (set_local $w + (i32.const 212) + ) + (set_local $w + (i32.const 1000) + ) + (drop + (i32.and + (get_local $w) + (i32.const 255) + ) + ) + ) + (func $local-info-sign-ext-bitsize (type $4) (param $0 i32) (param $1 i32) + (local $x i32) + (local $y i32) + (local $z i32) + (local $w i32) + (set_local $x + (i32.const 127) + ) + (drop + (get_local $x) + ) + (set_local $y + (i32.const 128) + ) + (drop + (i32.shr_s + (i32.shl + (get_local $y) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $0 + (i32.const 127) + ) + (drop + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $z + (i32.const 127) + ) + (set_local $z + (i32.const 100) + ) + (drop + (get_local $z) + ) + (set_local $w + (i32.const 127) + ) + (set_local $w + (i32.const 150) + ) + (drop + (i32.shr_s + (i32.shl + (get_local $w) + (i32.const 24) + ) + (i32.const 24) + ) + ) + ) + (func $local-info-sign-ext-already-exted (type $4) (param $0 i32) (param $1 i32) + (local $x i32) + (local $y i32) + (local $z i32) + (local $w i32) + (set_local $x + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (get_local $x) + ) + (set_local $y + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 16) + ) + (i32.const 16) + ) + ) + (drop + (i32.shr_s + (i32.shl + (get_local $y) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $0 + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $z + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $z + (i32.shr_s + (i32.shl + (get_local $1) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (get_local $z) + ) + (set_local $w + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $w + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 23) + ) + (i32.const 24) + ) + ) + (drop + (i32.shr_s + (i32.shl + (get_local $w) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) + ) + (i32.const 23) + ) + ) + ) + (func $signed-loads-fill-the-bits (type $3) (param $$e i32) (result i32) + (local $$0 i32) + (local $$conv i32) + (set_local $$0 + (i32.load8_s + (i32.const 1024) + ) + ) + (set_local $$conv + (i32.and + (get_local $$0) + (i32.const 255) + ) + ) + (return + (i32.eq + (get_local $$conv) + (get_local $$e) + ) + ) + ) + (func $local-info-sign-ext-already-exted-by-load (type $4) (param $0 i32) (param $1 i32) + (local $x i32) + (local $y i32) + (local $z i32) + (local $w i32) + (set_local $x + (i32.load8_s + (i32.const 1024) + ) + ) + (drop + (get_local $x) + ) + (set_local $y + (i32.load8_u + (i32.const 1024) + ) + ) + (drop + (i32.shr_s + (i32.shl + (get_local $y) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $z + (i32.load16_s + (i32.const 1024) + ) + ) + (drop + (i32.shr_s + (i32.shl + (get_local $z) + (i32.const 24) + ) + (i32.const 24) + ) + ) + ) + (func $compare-load-s-sign-extend (type $4) (param $0 i32) (param $1 i32) + (drop + (i32.eq + (i32.load8_u + (get_local $0) + ) + (i32.and + (get_local $1) + (i32.const 255) + ) + ) + ) + (drop + (i32.eq + (i32.and + (get_local $1) + (i32.const 255) + ) + (i32.load8_u + (get_local $0) + ) + ) + ) + (drop + (i32.eq + (i32.load8_u + (get_local $0) + ) + (i32.shr_s + (i32.shl + (get_local $1) + (i32.const 24) + ) + (i32.const 24) + ) + ) + ) + (drop + (i32.eq + (i32.load8_s + (get_local $0) + ) + (i32.shr_s + (i32.shl + (get_local $1) + (i32.const 16) + ) + (i32.const 16) + ) + ) + ) + (drop + (i32.eq + (i32.shr_s + (i32.shl + (get_local $1) + (i32.const 24) + ) + (i32.const 24) + ) + (i32.load8_u + (get_local $0) + ) + ) + ) + (drop + (i32.eq + (i32.shr_s + (i32.shl + (get_local $1) + (i32.const 16) + ) + (i32.const 16) + ) + (i32.load8_s + (get_local $0) + ) + ) + ) + ) ) diff --git a/test/passes/optimize-instructions.wast b/test/passes/optimize-instructions.wast index c59bb3ade..51bd076d1 100644 --- a/test/passes/optimize-instructions.wast +++ b/test/passes/optimize-instructions.wast @@ -654,9 +654,9 @@ (drop (i32.shr_s (i32.shl - (i32.xor ;; takes the min, here it is ok + (i32.xor ;; takes the max, here it is ok (i32.const 127) - (i32.const 128) + (i32.const 126) ) (i32.const 24) ) @@ -666,9 +666,9 @@ (drop (i32.shr_s (i32.shl - (i32.xor ;; takes the min, here it is not + (i32.xor ;; takes the max, here it is not + (i32.const 127) (i32.const 128) - (i32.const 129) ) (i32.const 24) ) @@ -1013,6 +1013,21 @@ (i32.const 24) ) ) + (drop ;; fuzz testcase + (i32.shr_s + (i32.shl + (i32.xor ;; should be 32 bits + (i32.le_u ;; 1 bit + (get_local $0) + (i32.const 2) + ) + (get_local $0) ;; unknown, so 32 bits + ) + (i32.const 24) + ) + (i32.const 24) + ) + ) ) (func $linear-sums (param $0 i32) (param $1 i32) (drop @@ -1332,4 +1347,763 @@ ) ) ) + (func $sign-ext-ne (param $0 i32) (param $1 i32) + ;; ne of sign-ext to const, can be a zext + (drop + (i32.ne + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) + ) + (i32.const 24) + ) + (i32.const 65000) + ) + ) + (drop + (i32.ne + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) + ) + (i32.const 24) + ) + (i32.const 111) + ) + ) + (drop + (i32.ne + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) + ) + (i32.const 24) + ) + (i32.shr_s + (i32.shl + (get_local $1) + (i32.const 24) + ) + (i32.const 24) + ) + ) + ) + ) + (func $sign-ext-eqz (param $0 i32) (param $1 i32) + (drop + (i32.eqz + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) + ) + (i32.const 24) + ) + ) + ) + ) + (func $sign-ext-boolean (param $0 i32) (param $1 i32) + (drop + (if i32 + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) + ) + (i32.const 24) + ) + (i32.const 100) + (i32.const 200) + ) + ) + ) + (func $add-sub-zero (param $0 i32) (param $1 i32) + (drop + (i32.add + (get_local $0) + (i32.const 0) + ) + ) + (drop + (i32.sub + (get_local $0) + (i32.const 0) + ) + ) + ) + (func $store-signext (param $0 i32) + (i32.store8 + (i32.const 8) + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) ;; exact size we store, sign-ext of 8 bits + ) + (i32.const 24) + ) + ) + (i32.store8 + (i32.const 8) + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 25) ;; 7 bits. so the ext can alter a bit we store, do not optimize + ) + (i32.const 25) + ) + ) + (i32.store8 + (i32.const 8) + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 23) ;; 9 bits, this is good to optimize + ) + (i32.const 23) + ) + ) + (i32.store16 + (i32.const 8) + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 16) ;; exact size we store, sign-ext of 16 bits + ) + (i32.const 16) + ) + ) + (i32.store16 + (i32.const 8) + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 17) ;; 15 bits. so the ext can alter a bit we store, do not optimize + ) + (i32.const 17) + ) + ) + (i32.store16 + (i32.const 8) + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 14) ;; 17 bits, this is good to optimize + ) + (i32.const 14) + ) + ) + (i32.store + (i32.const 8) + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 16) ;; 4 bytes stored, do nothing + ) + (i32.const 16) + ) + ) + (i32.store + (i32.const 8) + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 8) ;; 4 bytes stored, do nothing + ) + (i32.const 8) + ) + ) + ) + (func $sign-ext-tee (param $0 i32) (param $1 i32) + (drop + (i32.shr_s + (i32.shl + (tee_local $0 + (i32.const 128) ;; too big + ) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (i32.shr_s + (i32.shl + (tee_local $0 + (i32.const 127) ;; just right + ) + (i32.const 24) + ) + (i32.const 24) + ) + ) + ) + (func $sign-ext-load (param $0 i32) (param $1 i32) + (drop + (i32.shr_s + (i32.shl + (i32.load8_s ;; one byte, so perfect + (i32.const 256) + ) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (i32.shr_s + (i32.shl + (i32.shr_u + (i32.load8_s ;; one byte, but sexted to 32 + (i32.const 256) + ) + (i32.const 1) + ) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (i32.shr_s + (i32.shl + (i32.shr_u + (i32.load8_u ;; one byte, but reduced to 7 + (i32.const 256) + ) + (i32.const 1) + ) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (i32.shr_s + (i32.shl + (i32.load16_s ;; two, so perfect + (i32.const 256) + ) + (i32.const 16) + ) + (i32.const 16) + ) + ) + ;; through tees, we cannot alter the load sign + (drop + (i32.shr_s + (i32.shl + (tee_local $1 + (i32.load8_s + (i32.const 1) + ) + ) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (i32.shr_s + (i32.shl + (tee_local $1 + (i32.load8_u + (i32.const 1) + ) + ) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (i32.and + (tee_local $1 + (i32.load8_s + (i32.const 1) + ) + ) + (i32.const 255) + ) + ) + (drop + (i32.and + (tee_local $1 + (i32.load8_u + (i32.const 1) + ) + ) + (i32.const 255) + ) + ) + ) + (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 + ) + ) + ) + (func $local-info-zero-ext (param $0 i32) (param $1 i32) + (local $x i32) + (local $y i32) + (local $z i32) + (local $w i32) + (set_local $x + (i32.const 212) ;; mask is unneeded, we are small + ) + (drop + (i32.and + (get_local $x) + (i32.const 255) + ) + ) + (set_local $y + (i32.const 500) ;; mask is needed, we are too big + ) + (drop + (i32.and + (get_local $y) + (i32.const 255) + ) + ) + (set_local $0 + (i32.const 212) ;; mask is unneeded, but we are a param, not a var, so no + ) + (drop + (i32.and + (get_local $0) + (i32.const 255) + ) + ) + (set_local $z + (i32.const 212) ;; mask is unneeded, we are small + ) + (set_local $z + (i32.const 220) ;; mask is still unneeded even with 2 uses + ) + (drop + (i32.and + (get_local $z) + (i32.const 255) + ) + ) + (set_local $w + (i32.const 212) ;; mask is unneeded, we are small + ) + (set_local $w + (i32.const 1000) ;; mask is needed, one use is too big + ) + (drop + (i32.and + (get_local $w) + (i32.const 255) + ) + ) + ) + (func $local-info-sign-ext-bitsize (param $0 i32) (param $1 i32) + (local $x i32) + (local $y i32) + (local $z i32) + (local $w i32) + (set_local $x + (i32.const 127) ;; mask is unneeded, we are small + ) + (drop + (i32.shr_s + (i32.shl + (get_local $x) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $y + (i32.const 128) ;; mask is needed, we are too big + ) + (drop + (i32.shr_s + (i32.shl + (get_local $y) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $0 + (i32.const 127) ;; mask is unneeded, but we are a param, not a var, so no + ) + (drop + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $z + (i32.const 127) ;; mask is unneeded, we are small + ) + (set_local $z + (i32.const 100) ;; mask is still unneeded even with 2 uses + ) + (drop + (i32.shr_s + (i32.shl + (get_local $z) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $w + (i32.const 127) ;; mask is unneeded, we are small + ) + (set_local $w + (i32.const 150) ;; mask is needed, one use is too big + ) + (drop + (i32.shr_s + (i32.shl + (get_local $w) + (i32.const 24) + ) + (i32.const 24) + ) + ) + ) + (func $local-info-sign-ext-already-exted (param $0 i32) (param $1 i32) + (local $x i32) + (local $y i32) + (local $z i32) + (local $w i32) + (set_local $x + (i32.shr_s + (i32.shl + (get_local $0) ;; already sign-exted here, so no need later + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (i32.shr_s + (i32.shl + (get_local $x) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $y + (i32.shr_s + (i32.shl + (get_local $0) ;; already sign-exted here, but wrong bit size + (i32.const 16) + ) + (i32.const 16) + ) + ) + (drop + (i32.shr_s + (i32.shl + (get_local $y) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $0 + (i32.shr_s + (i32.shl + (get_local $0) ;; already sign-exted here, so no need later, but we are a param + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (i32.shr_s + (i32.shl + (get_local $0) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $z + (i32.shr_s + (i32.shl + (get_local $0) ;; already sign-exted here, so no need later + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $z + (i32.shr_s + (i32.shl + (get_local $1) ;; already sign-exted here, so no need later + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop + (i32.shr_s + (i32.shl + (get_local $z) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $w + (i32.shr_s + (i32.shl + (get_local $0) ;; already sign-exted here, so no need later + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $w + (i32.shr_s + (i32.shl + (get_local $0) ;; not quite a sign-ext + (i32.const 23) + ) + (i32.const 24) + ) + ) + (drop + (i32.shr_s + (i32.shl + (get_local $w) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (drop ;; odd corner case + (i32.shr_s + (i32.shl + (get_local $0) ;; param, so we should know nothing + (i32.const 24) + ) + (i32.const 23) ;; different shift, smaller + ) + ) + ) + (func $signed-loads-fill-the-bits (param $$e i32) (result i32) + (local $$0 i32) + (local $$conv i32) + (set_local $$0 + (i32.load8_s ;; one byte, but 32 bits due to sign-extend + (i32.const 1024) + ) + ) + (set_local $$conv + (i32.and + (get_local $$0) + (i32.const 255) ;; so we need this zexting! + ) + ) + (return + (i32.eq + (get_local $$conv) + (get_local $$e) + ) + ) + ) + (func $local-info-sign-ext-already-exted-by-load (param $0 i32) (param $1 i32) + (local $x i32) + (local $y i32) + (local $z i32) + (local $w i32) + (set_local $x + (i32.load8_s (i32.const 1024)) ;; 8 bits, sign extended, no need to do it again + ) + (drop + (i32.shr_s + (i32.shl + (get_local $x) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $y + (i32.load8_u (i32.const 1024)) ;; 8 bits, zext, so bad + ) + (drop + (i32.shr_s + (i32.shl + (get_local $y) + (i32.const 24) + ) + (i32.const 24) + ) + ) + (set_local $z + (i32.load16_s (i32.const 1024)) ;; 16 bits sign-extended, wrong size + ) + (drop + (i32.shr_s + (i32.shl + (get_local $z) + (i32.const 24) + ) + (i32.const 24) + ) + ) + ) + (func $compare-load-s-sign-extend (param $0 i32) (param $1 i32) + (drop + (i32.eq + (i32.load8_s + (get_local $0) + ) + (i32.shr_s + (i32.shl + (get_local $1) + (i32.const 24) + ) + (i32.const 24) + ) + ) + ) + (drop + (i32.eq + (i32.shr_s + (i32.shl + (get_local $1) + (i32.const 24) + ) + (i32.const 24) + ) + (i32.load8_s + (get_local $0) ;; flip order, we should canonicalize + ) + ) + ) + (drop + (i32.eq + (i32.load8_u ;; unsigned, bad + (get_local $0) + ) + (i32.shr_s + (i32.shl + (get_local $1) + (i32.const 24) + ) + (i32.const 24) + ) + ) + ) + (drop + (i32.eq + (i32.load8_s + (get_local $0) + ) + (i32.shr_s + (i32.shl + (get_local $1) + (i32.const 16) ;; wrong size + ) + (i32.const 16) + ) + ) + ) + (drop + (i32.eq + (i32.shr_s + (i32.shl + (get_local $1) + (i32.const 24) + ) + (i32.const 24) + ) + (i32.load8_u ;; unsigned, bad + (get_local $0) + ) + ) + ) + (drop + (i32.eq + (i32.shr_s + (i32.shl + (get_local $1) + (i32.const 16) ;; wrong size + ) + (i32.const 16) + ) + (i32.load8_s + (get_local $0) + ) + ) + ) + ) ) diff --git a/test/passes/optimize-instructions_optimize-level=2_ignore-implicit-traps.txt b/test/passes/optimize-instructions_optimize-level=2_ignore-implicit-traps.txt index 243421e8c..6e2127495 100644 --- a/test/passes/optimize-instructions_optimize-level=2_ignore-implicit-traps.txt +++ b/test/passes/optimize-instructions_optimize-level=2_ignore-implicit-traps.txt @@ -115,10 +115,7 @@ (i32.add (i32.mul (tee_local $7 - (i32.add - (get_local $0) - (i32.const 0) - ) + (get_local $0) ) (get_local $0) ) @@ -211,10 +208,7 @@ (i32.add (i32.mul (i32.eqz - (i32.add - (get_local $0) - (i32.const 0) - ) + (get_local $0) ) (get_local $0) ) 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) + ) + ) +) |