Loop-invariant code motion (also called hoisting or scalar promotion) is a compiler optimization that performs this movement automatically.
For example, strength reduction could remove the two multiplications inside the loop (6*i and a[i]), and induction variable elimination could then elide i completely.
Recent work by Moyen, Rubiano and Seiller uses data-flow dependence analysis [1] to detect not only invariant commands but larger code fragments such as an inner loop.
The analysis also detects quasi-invariants of arbitrary degrees, that is commands or code fragments that become invariant after a fixed number of iterations of the loop body.
Another effect of this transformation is allowing constants to be stored in registers and not having to calculate the address and access the memory (or cache line) at each iteration.