summaryrefslogtreecommitdiff
path: root/src/passes/OptimizeInstructions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes/OptimizeInstructions.cpp')
-rw-r--r--src/passes/OptimizeInstructions.cpp46
1 files changed, 32 insertions, 14 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index de6f96ccc..4fd7cbe8d 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -29,6 +29,7 @@
#include <ast/effects.h>
#include <ast/manipulation.h>
#include <ast/properties.h>
+#include <ast/literal-utils.h>
namespace wasm {
@@ -188,14 +189,14 @@ Index getMaxBits(Expression* curr, LocalInfoProvider* 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, localInfoProvider) + shifts->value.geti32());
+ return std::min(Index(32), getMaxBits(binary->left, localInfoProvider) + Bits::getEffectiveShifts(shifts));
}
return 32;
}
case ShrUInt32: {
if (auto* shift = binary->right->dynCast<Const>()) {
auto maxBits = getMaxBits(binary->left, localInfoProvider);
- auto shifts = std::min(Index(shift->value.geti32()), maxBits); // can ignore more shifts than zero us out
+ auto shifts = std::min(Index(Bits::getEffectiveShifts(shift)), maxBits); // can ignore more shifts than zero us out
return std::max(Index(0), maxBits - shifts);
}
return 32;
@@ -204,7 +205,7 @@ Index getMaxBits(Expression* curr, LocalInfoProvider* localInfoProvider) {
if (auto* shift = binary->right->dynCast<Const>()) {
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
+ auto shifts = std::min(Index(Bits::getEffectiveShifts(shift)), maxBits); // can ignore more shifts than zero us out
return std::max(Index(0), maxBits - shifts);
}
return 32;
@@ -533,9 +534,16 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
} else if (left->op == OrInt32) {
leftRight->value = leftRight->value.or_(right->value);
return left;
- } else if (left->op == ShlInt32 || left->op == ShrUInt32 || left->op == ShrSInt32) {
- leftRight->value = leftRight->value.add(right->value);
- return left;
+ } else if (left->op == ShlInt32 || left->op == ShrUInt32 || left->op == ShrSInt32 ||
+ left->op == ShlInt64 || left->op == ShrUInt64 || left->op == ShrSInt64) {
+ // shifts only use an effective amount from the constant, so adding must
+ // be done carefully
+ auto total = Bits::getEffectiveShifts(leftRight) + Bits::getEffectiveShifts(right);
+ if (total == Bits::getEffectiveShifts(total, right->type)) {
+ // no overflow, we can do this
+ leftRight->value = LiteralUtils::makeLiteralFromInt32(total, right->type);
+ return left;
+ } // TODO: handle overflows
}
}
}
@@ -874,14 +882,17 @@ private:
auto* left = binary->left;
auto* right = binary->right;
if (!Properties::emitsBoolean(left) || !Properties::emitsBoolean(right)) return nullptr;
- auto leftEffects = EffectAnalyzer(getPassOptions(), left).hasSideEffects();
- auto rightEffects = EffectAnalyzer(getPassOptions(), right).hasSideEffects();
- if (leftEffects && rightEffects) return nullptr; // both must execute
- // canonicalize with side effects, if any, happening on the left
- if (rightEffects) {
+ auto leftEffects = EffectAnalyzer(getPassOptions(), left);
+ auto rightEffects = EffectAnalyzer(getPassOptions(), right);
+ auto leftHasSideEffects = leftEffects.hasSideEffects();
+ auto rightHasSideEffects = rightEffects.hasSideEffects();
+ if (leftHasSideEffects && rightHasSideEffects) return nullptr; // both must execute
+ // canonicalize with side effects, if any, happening on the left
+ if (rightHasSideEffects) {
if (CostAnalyzer(left).cost < MIN_COST) return nullptr; // avoidable code is too cheap
+ if (leftEffects.invalidates(rightEffects)) return nullptr; // cannot reorder
std::swap(left, right);
- } else if (leftEffects) {
+ } else if (leftHasSideEffects) {
if (CostAnalyzer(right).cost < MIN_COST) return nullptr; // avoidable code is too cheap
} else {
// no side effects, reorder based on cost estimation
@@ -908,8 +919,15 @@ private:
// it's better to do the opposite for gzip purposes as well as for readability.
auto* last = ptr->dynCast<Const>();
if (last) {
- last->value = Literal(int32_t(last->value.geti32() + offset));
- offset = 0;
+ // don't do this if it would wrap the pointer
+ uint64_t value64 = last->value.geti32();
+ uint64_t offset64 = offset;
+ if (value64 <= std::numeric_limits<int32_t>::max() &&
+ offset64 <= std::numeric_limits<int32_t>::max() &&
+ value64 + offset64 <= std::numeric_limits<int32_t>::max()) {
+ last->value = Literal(int32_t(value64 + offset64));
+ offset = 0;
+ }
}
}