You'd have to use annotations or asserts.
Or rely on literal whole program analysis to prove upper bounds of parameters/etc (which still may not be possible statically)
I took a couple examples where gcc failed vectorization for unsigned indexes and tried to rewrite them in a way that didn't sacrifice 1/2 of the type's range just to satisfy the optimizer. In the first example I could just change a "<= n" to "!= n + 1", and the second example, which was based on your comment, could be solved by using pointers instead of indexing. I still wonder how many examples can't be solved without using signed types.
In reality I'm not sure what kind of loop would have an index only fitting in an unsigned type.
On a 32-bit machine an unsigned array index means one object using more than half the address space. It's sensible to use unsigned 64-bit for file sizes, but I think it's quite odd that C programers would use it for a loop or array index. Wrong, but defined, behavior is worse than undefined behavior, you know.
On a 64-bit machine, well, it shouldn't be a problem to use signed long long.
The issue i raised is that you replaced a perfectly functioning loop with one that does not work properly (it does iterate the same number of times for all inputs)
You said "I can change <= n to != n + 1".
You cannot.
for n == UNSIGNED_MAX, the former loop will iterate infinitely, the latter loop will never iterate.
Both are well defined to occur.
You cannot change the loop behavior and say you have the same loop :)
I never meant to imply that changing "<= n" to "!= n + 1" does not change the semantics of the unsigned loop. This was an example shown in some LLVM documentation as to why you should use signed loop variables. I was just showing that you can still use unsigned variables, have the same semantics as _the signed loop_ ,and get vectorized code.