Классический разворот цикла порождает зависимость по данным. Вернемся к листингу14. Несмотря на то, что загрузка обрабатываемых ячеек происходит параллельно, следующая операция сложения начинается только после завершения предыдущей, а все остальное время процессор ждет.
Чтобы избавиться от зависимости по данным, необходимо развернуть не только цикл, но и "расщепить" переменную, используемую для суммирования. Такая техника оптимизации называется программной конвейеризацией (software pipelining) и из всех рассматриваемых компиляторов ее поддерживает только GCC, да и то лишь частично. В тоже самое время, она элементарно реализуется "руками":
// обрабатываем первые XXL
– (XXL
% 4) итераций
for(i=0; i<XXL;i+=4)
{
sum_1 += a[i+0];
sum_2 += a[i+2];
sum_3 += a[i+3];
sum_4 += a[i+4];
}
// обрабатываем оставшийся "хвост"
for(i-=XXL; i<XXL;i++)
sum += a[i];
// складываем все воедино
sum
+= sum_1 + sum_2 + sum_3 + sum_4;