The purpose of this patch is to eliminate a pass ordering dependence between LoopPredication and LICM. To understand the purpose, consider the following snippet of code inside some loop 'L' with IV 'i'
A = _a.length;
guard (i < A)
a = _a[i]
B = _b.length;
guard (i < B);
b = _b[i];
Z = _z.length;
guard (i < Z)
z = _z[i]
accum += a + b + ... + z;
Today, we need LICM to hoist the length loads, LoopPredication to make the guards loop invariant, and TrivialUnswitch to eliminate the loop invariant guard to establish must execute for the next length load. Today, if we can't prove speculation safety, we'd have to iterate these three passes 26 times to reduce this example down to the minimal form.
Using the fact that the array lengths are known to be invariant, we can short circuit this iteration. By forming the loop invariant form of all the guards at once, we remove the need for LoopPredication from the iterative cycle. At the moment, we'd still have to iterate LICM and TrivialUnswitch; we'll leave that part for later.
There are two high level design questions on this patch I'd like input on:
- I realized I'm essentially duplicating most of the loop disposition logic from SCEV, but expressed over IR. The critical missing piece is that SCEV does not consider a SCEVUknown for an invariant load w/invariant operands to be invariant. Would it make sense to implement this in SCEV?
- Anyone see a better way to handle the adjustment of the insertion point? I want to be inserting in the preheader if possible, and only falling back to in the loop if required. I thought about inserting in the loop and then hoisting, but we may have expressions we can't prove the safety of in IR which SCEV has already established. Wasting that opportunity is undesirable, but mucking around with the insertion point is also quite ugly. Ideas?