Joe Savona 832285fed2 Only create mutable ranges for phis *mutated* later
This PR was the result of a long chain of ~yak-shaving~ debugging kicked off as 
a result of fixing up invariants. Where this started was that i noticed some 
cases of loops where the first instance we saw of a reactive scope was after its 
starting instruction. Eg instruction N would have an operand with scope 
Start:End, where Start was _before_  N. One of the cases involved a phi with a 
backedge. Then i noticed that we assign scopes differently for phis with and 
without backedges: 

``` 

[1] let x0 = init; 

[2] if (x0 < limit) { 

[3] x1 += increment; 

} 

x2 = phi(x0, x1); 

[4] x2; 

``` 

The phi isn't mutated _or_ reassigned after its creation, so we don't assign a 
mutable range to the phi or any of its operands. We also don't create a scope 
for `x`. 

But change the `if` to a `while` and now the phi moves - now there's a backedge: 

``` 

[1] let x0 = init; 

[2] while (x0 < limit) { 

x2 = phi(x0, x2); // now this is "mutated" later!!! 

[3] x2 += increment; 

} 

[4] x2; 

``` 

What was happening here is that x2 has a mutable range which is "after" the phi 
instruction, so it would appear that the phi was actually being mutated later. 
Ie, this was treated equivalently to the original "if" version, but with a 
mutation: 

``` 

let x = []; 

if (cond) { 

x = {}; 

} 

mutate(x); // later mutation of the phi 

``` 

But these latter two cases are different! We only need to (should) create a 
mutable range for a phi _if its value is actually mutated_. If it's just being 
reassigned, well then it shouldn't matter if there are back edges or not. 

So this PR implements that intuition: only create a mutable range for a phi if 
it is actually _mutated_ later, ie don't assign a mutable range if it is only 
_reassigned_ later. Concretely in InferMutableRanges: 

* InferMutableLifetimes no longer has to initialize a range for phis during the 
first pass (inferMutableRangesForStores=false). We wait to see if the phi is 
mutated during the main fixpoint iteration of InferMutableRanges 

* The main fixpoint iteration in InferMutableRanges already aliases phi operands 
if the phi is later mutated, which will extend the end of the mutable range of 
all the operands accordingly. 

* Finally, InferMutableLifetimes's second run 
(inferMutableRangesForStores=true), we ensure that any phis mutated later have a 
valid mutable range, specifically setting the `start` of the range since the 
fixpoint only updates the `end` value.
2024-04-01 14:21:48 -07:00
S
Description
No description provided
MIT 1.8 GiB
Languages
JavaScript 67.1%
TypeScript 29.4%
HTML 1.5%
CSS 1.1%
C++ 0.6%
Other 0.2%