@@ -145,9 +145,20 @@ static void replaceInPlaceIfPossible(Ref target, Ref value) {
145145static void optimizeJS (Ref ast) {
146146 // Helpers
147147
148- auto isOrZero = [](Ref node) {
148+ auto isBinary = [](Ref node, IString op ) {
149149 return node->isArray () && !node->empty () && node[0 ] == BINARY &&
150- node[1 ] == OR && node[3 ]->isNumber () && node[3 ]->getNumber () == 0 ;
150+ node[1 ] == op;
151+ };
152+
153+ auto isConstantBinary = [&](Ref node, IString op, int num) {
154+ return isBinary (node, op) && node[3 ]->isNumber () &&
155+ node[3 ]->getNumber () == num;
156+ };
157+
158+ auto isOrZero = [&](Ref node) { return isConstantBinary (node, OR, 0 ); };
159+
160+ auto isTrshiftZero = [&](Ref node) {
161+ return isConstantBinary (node, TRSHIFT, 0 );
151162 };
152163
153164 auto isPlus = [](Ref node) {
@@ -174,11 +185,6 @@ static void optimizeJS(Ref ast) {
174185 node[1 ] == op;
175186 };
176187
177- auto isConstantBitwise = [](Ref node, IString op, int num) {
178- return node->isArray () && !node->empty () && node[0 ] == BINARY &&
179- node[1 ] == op && node[3 ]->isNumber () && node[3 ]->getNumber () == num;
180- };
181-
182188 auto isWhile = [](Ref node) {
183189 return node->isArray () && !node->empty () && node[0 ] == WHILE;
184190 };
@@ -243,11 +249,14 @@ static void optimizeJS(Ref ast) {
243249 };
244250
245251 auto optimizeBoolean = [&](Ref node) {
246- // x ^ 1 => !x
247- if ( isConstantBitwise (node, XOR, 1 )) {
252+ if ( isConstantBinary (node, XOR, 1 )) {
253+ // x ^ 1 => !x
248254 node[0 ]->setString (UNARY_PREFIX);
249255 node[1 ]->setString (L_NOT);
250256 node[3 ]->setNull ();
257+ } else if (isOrZero (node) || isTrshiftZero (node)) {
258+ // Just being different from 0 is enough, casts don't matter.
259+ return node[2 ];
251260 }
252261 return node;
253262 };
@@ -257,7 +266,7 @@ static void optimizeJS(Ref ast) {
257266 // Pre-simplification
258267 traversePost (ast, [&](Ref node) {
259268 // x >> 0 => x | 0
260- if (isConstantBitwise (node, RSHIFT, 0 )) {
269+ if (isConstantBinary (node, RSHIFT, 0 )) {
261270 node[1 ]->setString (OR);
262271 }
263272 });
@@ -270,10 +279,7 @@ static void optimizeJS(Ref ast) {
270279 // x | 0 | 0 => x | 0
271280 if (isOrZero (node)) {
272281 if (isBitwise (node[2 ])) {
273- auto child = node[2 ];
274- node[1 ] = child[1 ];
275- node[2 ] = child[2 ];
276- node[3 ] = child[3 ];
282+ replaceInPlace (node, node[2 ]);
277283 }
278284 }
279285 if (isHeapAccess (node[2 ])) {
@@ -284,7 +290,7 @@ static void optimizeJS(Ref ast) {
284290 if (isIntegerHeap (heap)) {
285291 replacementHeap = heap;
286292 }
287- } else if (isConstantBitwise (node, TRSHIFT, 0 )) {
293+ } else if (isTrshiftZero (node)) {
288294 // For signed or unsigned loads smaller than 32 bits, doing an | 0
289295 // was safe either way - they aren't in the range an | 0 can affect.
290296 // For >>> 0 however, a negative value would change, so we still
@@ -308,7 +314,7 @@ static void optimizeJS(Ref ast) {
308314 // better performance (perhaps since HEAPU32 is at risk of not being a
309315 // smallint).
310316 if (node[1 ] == AND) {
311- if (isConstantBitwise (node, AND, 1 )) {
317+ if (isConstantBinary (node, AND, 1 )) {
312318 if (heap == HEAPU8) {
313319 setHeapOnAccess (node[2 ], HEAP8);
314320 } else if (heap == HEAPU16) {
@@ -348,6 +354,21 @@ static void optimizeJS(Ref ast) {
348354 } else if (isUnary (node, L_NOT)) {
349355 node[2 ] = optimizeBoolean (node[2 ]);
350356 }
357+ // Add/subtract can merge coercions up.
358+ else if (isBinary (node, PLUS) || isBinary (node, MINUS)) {
359+ auto left = node[2 ];
360+ auto right = node[3 ];
361+ if (isOrZero (left) && isOrZero (right)) {
362+ auto op = node[1 ]->getIString ();
363+ // Add a coercion on top.
364+ node[1 ]->setString (OR);
365+ node[2 ] = left;
366+ node[3 ] = ValueBuilder::makeNum (0 );
367+ // Add/subtract the inner uncoerced values.
368+ left[1 ]->setString (op);
369+ left[3 ] = right[2 ];
370+ }
371+ }
351372 // Assignment into a heap coerces.
352373 else if (node->isAssign ()) {
353374 auto assign = node->asAssign ();
@@ -357,12 +378,12 @@ static void optimizeJS(Ref ast) {
357378 if (isIntegerHeap (heap)) {
358379 if (heap == HEAP8 || heap == HEAPU8) {
359380 while (isOrZero (assign->value ()) ||
360- isConstantBitwise (assign->value (), AND, 255 )) {
381+ isConstantBinary (assign->value (), AND, 255 )) {
361382 assign->value () = assign->value ()[2 ];
362383 }
363384 } else if (heap == HEAP16 || heap == HEAPU16) {
364385 while (isOrZero (assign->value ()) ||
365- isConstantBitwise (assign->value (), AND, 65535 )) {
386+ isConstantBinary (assign->value (), AND, 65535 )) {
366387 assign->value () = assign->value ()[2 ];
367388 }
368389 } else {
0 commit comments