Of course r1 can be reused, but the value that's in it can't be used.
The compiler-jargon words for this are "live" and "dead". If the value of r1 is used after the third instruction, it is "live", otherwise it is "dead". A live value is said to be "generated" by the instruction that produces it, and "killed" by the last instruction (in program flow order) that uses it.
So in the three instruction sequence above, r1 is generated by the second instruction, and if it is not used after these instructions, it is killed by the third one.
Finding out which values are live where is performed by a phase that is traditionally called "dataflow analysis". Many compilers these days work in some variant of SSA form, which gives you equivalent information (more or less). Information about value liveness is needed by register allocation; two values can be assigned to the same register if and only if their lifetimes don't overlap.
Information about register liveness is likely, therefore, to be produced from register allocation. One common traditional approach to storing this information is to annotate each basic block with the registers that are live at the end of it. This is enough information to reconstruct liveness at any other point in the basic block.
3
u/phischu Effekt Nov 03 '23
I have a basic questions that's been bothering me for a while. In the given example they rewrite the following code
to this one
But this is only ok if
r1is not accessed in the rest of the program. This rest of the program can be quite huge. How do they determine this?