First of all, the compiler doing this, or you are doing this, is in theory completely different things. Just because it looks equivalent, it doesnโt, the compiler is allowed to use any dirty hacks that work regardless of whether they are expressible or defined in fully standard C.
Of course, prefetching does not generate signals *, it would be almost useless if this happened. This can be very slow for some invalid pointers, although, depending on whether they trigger TLB skips. Thus, the compiler can use it safely, but it should not indiscriminately use it for everything.
Now, using pointer arithmetic to create bounds pointers (except for the end) is theoretically UB, but when applied to a pointer, it is a type of UB that will work anyway (with flat memory it's just an addition, the only way it can to fail is that the compiler does this to detect it, which means that it will have to reason about dynamic sizes). Obviously, the above case should be supported by compilers claiming to support SSE, otherwise you could not reasonably use prefetching as demonstrated in this answer (and there are more additional guarantees that they must fulfill over the standard).
* from the manual:
The PREFETCHh instruction is just a hint and does not affect the behavior of the program.
The signal will affect the behavior of the program, so they cannot be generated.
source share