If we unroll the loop in larger blocks, we may get better performance. The optimal block size can be difficult to determine, and changes from processor to processor, making it hard to write portable code. Also, the hand-unrolled code becomes more difficult to read and maintain. What we'd really like is to keep the code simple and tell the compiler that pointers cannot be aliased, then let the compiler do the loop unrolling and scheduling as it sees fit. There are a couple of ways to do this.
Many compilers have options to override their default aliasing assumptions.
You may be able to move certain functions to separate source files and compile just those files with these switches. In some cases, you cannot use these switches at all, because within a single function, some pointers are aliases and others are not. The restrict keyword is a very clean, high-performance way of addressing the pointer aliasing problem, without many of the drawbacks of the other methods. The restrict keyword tells the compiler to assume that dereferencing the qualified pointer is the only way the program can access the memory pointed to by that pointer. Hence loads and stores through such a pointer are assumed not to alias with any other loads and stores in the program, except other loads and stores through the same pointer variable.