2929#include < ast/effects.h>
3030#include < ast/manipulation.h>
3131#include < ast/properties.h>
32+ #include < ast/literal-utils.h>
3233
3334namespace wasm {
3435
@@ -188,14 +189,14 @@ Index getMaxBits(Expression* curr, LocalInfoProvider* localInfoProvider) {
188189 case OrInt32: case XorInt32: return std::max (getMaxBits (binary->left , localInfoProvider), getMaxBits (binary->right , localInfoProvider));
189190 case ShlInt32: {
190191 if (auto * shifts = binary->right ->dynCast <Const>()) {
191- return std::min (Index (32 ), getMaxBits (binary->left , localInfoProvider) + shifts-> value . geti32 ( ));
192+ return std::min (Index (32 ), getMaxBits (binary->left , localInfoProvider) + Bits::getEffectiveShifts (shifts ));
192193 }
193194 return 32 ;
194195 }
195196 case ShrUInt32: {
196197 if (auto * shift = binary->right ->dynCast <Const>()) {
197198 auto maxBits = getMaxBits (binary->left , localInfoProvider);
198- auto shifts = std::min (Index (shift-> value . geti32 ( )), maxBits); // can ignore more shifts than zero us out
199+ auto shifts = std::min (Index (Bits::getEffectiveShifts (shift )), maxBits); // can ignore more shifts than zero us out
199200 return std::max (Index (0 ), maxBits - shifts);
200201 }
201202 return 32 ;
@@ -204,7 +205,7 @@ Index getMaxBits(Expression* curr, LocalInfoProvider* localInfoProvider) {
204205 if (auto * shift = binary->right ->dynCast <Const>()) {
205206 auto maxBits = getMaxBits (binary->left , localInfoProvider);
206207 if (maxBits == 32 ) return 32 ;
207- auto shifts = std::min (Index (shift-> value . geti32 ( )), maxBits); // can ignore more shifts than zero us out
208+ auto shifts = std::min (Index (Bits::getEffectiveShifts (shift )), maxBits); // can ignore more shifts than zero us out
208209 return std::max (Index (0 ), maxBits - shifts);
209210 }
210211 return 32 ;
@@ -533,9 +534,16 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
533534 } else if (left->op == OrInt32) {
534535 leftRight->value = leftRight->value .or_ (right->value );
535536 return left;
536- } else if (left->op == ShlInt32 || left->op == ShrUInt32 || left->op == ShrSInt32) {
537- leftRight->value = leftRight->value .add (right->value );
538- return left;
537+ } else if (left->op == ShlInt32 || left->op == ShrUInt32 || left->op == ShrSInt32 ||
538+ left->op == ShlInt64 || left->op == ShrUInt64 || left->op == ShrSInt64) {
539+ // shifts only use an effective amount from the constant, so adding must
540+ // be done carefully
541+ auto total = Bits::getEffectiveShifts (leftRight) + Bits::getEffectiveShifts (right);
542+ if (total == Bits::getEffectiveShifts (total, right->type )) {
543+ // no overflow, we can do this
544+ leftRight->value = LiteralUtils::makeLiteralFromInt32 (total, right->type );
545+ return left;
546+ } // TODO: handle overflows
539547 }
540548 }
541549 }
@@ -874,14 +882,17 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
874882 auto * left = binary->left ;
875883 auto * right = binary->right ;
876884 if (!Properties::emitsBoolean (left) || !Properties::emitsBoolean (right)) return nullptr ;
877- auto leftEffects = EffectAnalyzer (getPassOptions (), left).hasSideEffects ();
878- auto rightEffects = EffectAnalyzer (getPassOptions (), right).hasSideEffects ();
879- if (leftEffects && rightEffects) return nullptr ; // both must execute
880- // canonicalize with side effects, if any, happening on the left
881- if (rightEffects) {
885+ auto leftEffects = EffectAnalyzer (getPassOptions (), left);
886+ auto rightEffects = EffectAnalyzer (getPassOptions (), right);
887+ auto leftHasSideEffects = leftEffects.hasSideEffects ();
888+ auto rightHasSideEffects = rightEffects.hasSideEffects ();
889+ if (leftHasSideEffects && rightHasSideEffects) return nullptr ; // both must execute
890+ // canonicalize with side effects, if any, happening on the left
891+ if (rightHasSideEffects) {
882892 if (CostAnalyzer (left).cost < MIN_COST) return nullptr ; // avoidable code is too cheap
893+ if (leftEffects.invalidates (rightEffects)) return nullptr ; // cannot reorder
883894 std::swap (left, right);
884- } else if (leftEffects ) {
895+ } else if (leftHasSideEffects ) {
885896 if (CostAnalyzer (right).cost < MIN_COST) return nullptr ; // avoidable code is too cheap
886897 } else {
887898 // no side effects, reorder based on cost estimation
@@ -908,8 +919,15 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions,
908919 // it's better to do the opposite for gzip purposes as well as for readability.
909920 auto * last = ptr->dynCast <Const>();
910921 if (last) {
911- last->value = Literal (int32_t (last->value .geti32 () + offset));
912- offset = 0 ;
922+ // don't do this if it would wrap the pointer
923+ uint64_t value64 = last->value .geti32 ();
924+ uint64_t offset64 = offset;
925+ if (value64 <= std::numeric_limits<int32_t >::max () &&
926+ offset64 <= std::numeric_limits<int32_t >::max () &&
927+ value64 + offset64 <= std::numeric_limits<int32_t >::max ()) {
928+ last->value = Literal (int32_t (value64 + offset64));
929+ offset = 0 ;
930+ }
913931 }
914932 }
915933
0 commit comments