Optimizing Compilers for Modern Architectures: A Dependence-Based Approach

Although most programmers would naturally write loop nests that achieve a high degree of reuse, there are many situations in which fusion of loop nests might produce good results. An important example is when the loop nests are produced as a result of some form of preprocessing, such as when Fortran 90 array statements are converted to scalar loops, as discussed in Chapter 13.
Consider the following Fortran 90 example:
A(1:N) = C(1:N) + D(1:N) B(1:N) = C(1:N) D(1:N)<a name="876"></a><a name="beginpage.BB0F2FC0-20E2-409F-B9AD-A83711BF3147"></a>
In this case both statements use identical sections of C and D. It is clear from these statements that the common elements should be reused from registers. Certainly, if we had a machine with vector registers of length 256, it should be relatively straightforward for a compiler to retain the operands in registers. However, when these statements are converted to scalar form in a naive way, the common operands move apart:
DO I = 1, N A(I) = C(I) + D(I) ENDDO DO I = 1, N B(I) = C(I) D(I) ENDDO
In this form, the common operands have been separated; the first loop runs through all elements of C and D before the second loop accesses any element of either array. Thus, every element...