When we have a loop with a known upper bound on the number of iterations, and furthermore know that either the number of iterations will be either exactly that upper bound or zero, then we can fully unroll up to that upper bound keeping only the first loop test to check for the zero iteration case.
Most of the work here is in plumbing this 'max-or-zero' information from the part of scalar evolution where it's detected through to loop unrolling. I've also gone for the safe default of 'false' everywhere but howManyLessThans which could probably be improved.
I've only taken a brief look at this, but it might be a nicer interface to add a getMaxOrZeroBackedgeTakenCount. That way we don't have to add the MaxOrZero everywhere (same in other places) and would look more like the existing code.