[js/rust] Improve constant propagation
Makes the same improvement to constant propagation in both the JS and Rust versions. The core algorithm only populates phi variables if all operands have a known value (no back edges) and all those values are the same: this allows us to propagate constants in most cases and simply punts on handling propagating values that are affected by loops. However, since we collapse if statements into gotos when the test condition is a constant, there can be cases where a phi that originally existed will be pruned out: ``` // bb0 let x1; if (true) { // bb1 x2 = 1; } else { // bb2 x3 = 2; // this block becomes unreachable } // bb3 x4 = phi(bb1: x2, bb2: x3); // this phi will get pruned s.t. x4 = x2 = 1 return x4; ``` However, the algorithm doesn't prune phis until _after_ applying constants, so currently we would see this phi node w different inputs and not propagate a constant for the final usage of x, even though it will clearly be `1`. The change is to make constant propagation use fixpoint iteration, iterating so long as terminals changed on the previous iteration. If no terminals change the algorithm completes in a single pass, but if terminals do change then we update phis and continue. As you can see from the new test case this allows us to find arbitrary length sequences of values and terminals that can be pruned.