@@ -2822,8 +2822,12 @@ struct OptimizeInstructions
28222822 }
28232823
28242824 // To be equal, they must also be known to return the same result
2825- // deterministically.
2826- return !Properties::isGenerative (left);
2825+ // deterministically. We check the right side, as if the right is marked
2826+ // idempotent, that is enough (that tells us it does not generate a new
2827+ // value; logically, of course, as left is equal to right, they are calling
2828+ // the same thing, so it is odd to only annotate one, but this is consistent
2829+ // and easy to check).
2830+ return !Properties::isGenerative (right, getFunction (), *getModule ());
28272831 }
28282832
28292833 // Check if two consecutive inputs to an instruction are equal and can also be
@@ -2841,9 +2845,51 @@ struct OptimizeInstructions
28412845 }
28422846
28432847 // To fold the right side into the left, it must have no effects.
2844- if (EffectAnalyzer (getPassOptions (), *getModule (), right)
2845- .hasUnremovableSideEffects ()) {
2846- return false ;
2848+ auto rightMightHaveEffects = true ;
2849+ if (auto * call = right->dynCast <Call>()) {
2850+ // If these are a pair of idempotent calls, then the second has no
2851+ // effects. (We didn't check if left is a call, but the equality check
2852+ // below does that.)
2853+ if (Intrinsics (*getModule ())
2854+ .getCallAnnotations (call, getFunction ())
2855+ .idempotent ) {
2856+ // We must still check for effects in the parameters. Imagine that we
2857+ // have
2858+ //
2859+ // (call $idempotent (global.get $g))
2860+ // (call $idempotent (global.get $g))
2861+ //
2862+ // Then the first call has effects, and those might alter $g if the
2863+ // global is mutable. That is, all that idempotency tells us is that
2864+ // the second call has no effects, but its parameters can still have
2865+ // read effects that interact. Also, the parameter might have write
2866+ // effects,
2867+ //
2868+ // (call $idempotent (call $other))
2869+ //
2870+ // We must check that as well.
2871+ EffectAnalyzer childEffects (getPassOptions (), *getModule ());
2872+ for (auto * child : call->operands ) {
2873+ childEffects.walk (child);
2874+ }
2875+ if (childEffects.hasUnremovableSideEffects ()) {
2876+ return false ;
2877+ }
2878+ ShallowEffectAnalyzer parentEffects (
2879+ getPassOptions (), *getModule (), call);
2880+ if (parentEffects.invalidates (childEffects)) {
2881+ return false ;
2882+ }
2883+ // No effects are possible.
2884+ rightMightHaveEffects = false ;
2885+ }
2886+ }
2887+ if (rightMightHaveEffects) {
2888+ // So far it looks like right has effects, so check fully.
2889+ if (EffectAnalyzer (getPassOptions (), *getModule (), right)
2890+ .hasUnremovableSideEffects ()) {
2891+ return false ;
2892+ }
28472893 }
28482894
28492895 return areConsecutiveInputsEqual (left, right);
0 commit comments