In practice, you want to do both.IE hoist everything you can, sink everything you can.
But not because of
"That is, if a function terminates early, you're not evaluating the expressions unnecessarily, no?"
If the function terminates early, and you've moved the expression computation before or after an early termination point, you've by definition changed what paths it is computed on (unless it was already computed there).
That is not legal in all cases (it's speculative PRE/PDE)
PRE and VBE (which is what this is) guarantee that the expression is still computed at on the same paths.
They just make it so it's computed once.
What is happening here is really a size optimization.
If it can prove that it is always executed, it has one copy of the computation, instead of multiple ones.