While working on an optimization for DSE I've noticed that for an example like the one below we return getLoopGuardBranch == nullptr and isGuarded == false for both loops even if they are in rotated form. See IR in an example on godbolt.
Technically, entry block decides if both loops execute, but there is a block with br i1 %3, label %7, label %14 where %3 is a icmp in entry block, so it can be a guard for the second loop.
void func(int *P, int N) { for (int i = 0; i < N; ++i) { P[i] = 1; } for (int i = 0; i < N; ++i) { P[i] = 2; } }
This happens because loops are not in canonical form (specifically, because of no dedicated exits). I suggest to relax a little this requirement to have dedicated exits and add a check for a case when there is an exit that has exactly two predecessors and both of them are latch from loop and the block whose branch instruction we return in getLoopGuardBranch. So, we find a guard in a case as in the example above.
no need braces for single statement block.