1 void combine6(vec_ptr v, data_t *dest)
2 {
3 long i;
4 long length = vec_length(v);
5 long limit = length - 1;
6 data_t *data = get_vec_start(v);
7 data_t acc0 = IDENT;
8 data_t acc1 = IDENT;
9
10 /* Combine 2 element at a time */
11 for(i=0; i<length; i+=2)
12 {
13 acc0 = acc0 OP data[i];
14 acc1 = acc1 OP data[i+1];
15 }
16
17 /* Finish any remaining elements */
18 for(; i<length; i++)
19 {
20 acc0 = acc0 OP data[i];
21 }
22 *dest = acc0 OP acc1;
23 }
Combine6既使用了两次循环展开,以使每次迭代合并更过的元素,也使用两路并行,将索引值为偶数的元素累积在变量acc0中,而索引值为计数的元素累积在变量acc1中。于是,我们将其称为“2 x 2”循环展开。对于循环长度不为2的倍数时,这个循环要累积所有剩下的数组元素。然后,我们在对acc0和acc1应用合并运算,计算最终的结果。 比较只做循环展开和既做循环展开同时也使用两路并行的方法,我们得到下面的性能:
2.9.2 重新结合变换
1 void combine7(vec_ptr v, data_t *dest)
2 {
3 long i;
4 long length = vec_length(v);
5 long limit = length - 1;
6 data_t *data = get_vec_start(v);
7 data_t acc = IDENT;
8
9 /* Combine 2 element at a time */
10 for(i=0; i<length; i+=2)
11 {
12 acc = acc OP (data[i] OP data[i+1]);
13 }
14
15 /* Finish any remaining elements */
16 for(; i<length; i++)
17 {
18 acc = acc OP data[i];
19 }
20 *dest = acc;
21 }
上述函数与combine5的唯一差异点在于内循环中元素的合并方式。在combine5中,合并是下面这条语句来实现的: 12 acc = (acc OP data[i]) OP data[i+1]; 而在combine7中,合并是以这条语句来实现的: 12 acc = acc OP (data[i] OP data[i+1]);
差别在于两个括号是如何放置的。我们称之为重新结合变换,因为括号改变了向量元素与累计值acc的合并顺序,产生了我们成为“2 x 1a”的循环展开形式。 针对以上函数,测量的结果如下: