When analyzing operands of loads/stores, if we can guarantee that a GEP
is always zero-indexed, it is better to modify the GEP such that other
users can take advantage of the simplification, rather than just cloning
it for one specific load/store user. Edit: implementation changed to
call replaceInstUsesWith instead of modifying in place.
Without this change, replaceGEPIdxWithZero clones the GEP for the
triggering load/store, leaving the original variable-indexed GEP in
place. Other users of that GEP (e.g., a constant-offset GEP feeding a
second load) miss the simplification. Testcase demonstrates this:
without the first load _modifying_ the gep, the _second_ load will still
be dependent on both GEPs, and thus unnecessarily dependent on the %idx.
This lack of simplification can cause issues with later passes such as
LICM.
Alternative approaches could be to add a version of this transform into
visitGEP, but there is precedent to doing so in visitLoad/visitStore,
see simplifyNonNullOperand. And because the optimization is tied to the
dereference that happens in the load/store, I think it reasonably fits
here.
Alive2 proof: https://alive2.llvm.org/ce/z/-HZd9c
Alive2 counterexample showing why we cannot blindly modify the gep in
place without some sort of condition:
https://alive2.llvm.org/ce/z/dzKuc3