If we have a guard w/loop invariant operands, which is reached along a side effect free path on the first iteration, we can hoist that guard outside the loop, even over control flow we can not analyse. Doing so may widen the condition - make it fail on more executions than the original program - but that's explicitly allowed by the documented semantics of guards.
At the moment, I'm mostly looking for feedback on approach. Is this the right framing and placement? As noted in the comment, I'm considering an alternate "spliting" framing, would that be cleaner?
I need to add dedicated tests and will rebase when done so, but for now, the GuardWidening/basics.ll test show the difference fairly well. (I have not included the output in the diff yet.)