This is my attempt to clarify the wording in the LangRef w.r.t. the implied semantics of the !invariant.load metadata. To the best of my knowledge, the revised wording respects the actual implementation and understanding of issues involved highlighted in the recent 'Optimization hints for "constant" loads' thread on LLVMDev.
In particular, I'm aiming for the following results:
- To clarify that an invariant.load can fault and must respect control dependence. In particular, it is not sound to unconditionally pull an invariant load out of a loop if that loop would potentially never execute.
- To clarify that the invariant nature of a given pointer does not preclude the modification of that location through a pointer which is unrelated to the load operand. In particular, initializing a location and then passing a pointer through an opaque intrinsic which produces a new unrelated pointer, should behave as expected provided that the intrinsic is memory dependent on the initializing store.
- To clarify that storing a value to an invariant location is defined. It can not, for example, be considered unreachable. The value stored can be assumed to be equal to the value of any previous (or following!) invariant load, but the store itself is defined.
I would really appreciate some careful thought by others familiar with the semantics here. Are the revised semantics consistent with our actual implementation? With the expectations of current users? With the optimizations we'd like to see applied going forward?
Once we agree on the semantics here, my plan is to extend a couple of places in the optimizer with support for invariant loads. In particular, EarlyCSE & GVN can do more aggressive value forwarding and dead store elimination for locations touched by invariant loads. An InstCombine rule of the form store (store (load x invariant), x) -> (nop) also seems useful.
it's -> its