二.处理器相关的优化ARM方法
(1)保持流水线畅通
从前面的介绍可知,流水线延迟或阻断会对处理器的性能造成影响,因此应该尽量保持流水线畅通。流水线延迟难以避免, 但可以利用延迟周期进行其它ARM操作。

LOAD/STORE 指令中的自动索引(auto-indexing)功能就是为利用ARM流水线延迟周期而设计的。当流水线处于延迟周期时, 处理器的执行单元被占用, 算术逻辑单元ARMALU )和桶形移位器却可能处于空闲状态,此时可以利用它们来完成往基址寄存器上加一个偏移量的操作,
供后面的指令使用。例如:指令 LDR R1, [R2], #4 完成 R1= *R2 R2 += 4 两个操作,是后索引(post-indexing)的例子;而指令 LDR R1, [R2, #4]! 完成 R1 = *(R2 + 4) R2 +=4 两个操作,是前索引(pre-indexing)的例子。

流水线阻断的情况可通过循环拆解等方法加以改善。一个循环可以考虑拆解以减小跳转指令在循环指令中所占的比重, 进而提高代码效率。下面以一个内存复制函数加以ARM说明。

void memcopy(char *to, char *from, unsigned int nbytes)
{
while(nbytes--)ARM
*to++ = *from++;
}

为简单起见,这里假设nbytes 16 ARM倍数(省略对余数的处理)。上面的函数每处理一个字节就要进行一次判断和跳转, 对其中的循环体可作如下拆解:

void memcopy(char *to, char *from, unsigned int nbytes)
{
while(nbytes) {
*to++ = *from++;
*to++ = *from++;ARM
*to++ = *from++;
*to++ = *from++;
nbytes - = 4;
}
}

这样一来, 循环体中的指令数增加了,循环次数却减少了。跳转指令ARM带来的负面影响得以削弱。利用ARM 7 处理器32 位字长的特性, 上述代码可进一步作如下调整:

void memcopy(char *to, char *from, unsigned int nbytes)ARM
{
int *p_to = (int *)to;
int *p_from = (int *)from;
while(nbytes) {
*p_to++ = *p_from++;
*p_to++ = *p_from++;
*p_to++ = *p_from++;
*p_to++ = *p_from++;
nbytes - = 16;
}
}
经过优化后,一次循环可以处理16 个字节。跳转指令带来的影响ARM进一步得到减弱。不过可以看出, 调整后的代码在代码量方面有所增加。

(2)使用寄存器变量
CPU 对寄存器的存取要比对内存的存取快得多ARM 因此为变量分配一个寄存器, 将有助于代码的优化和运行效率的提高。整型、指针、浮点等类型的变量都可以分配寄存器; 一个结构的部分或者全部也可以分配寄存器。给循环体中需要频繁访问的变量分配寄存器也能在
一定程度上提高程序效率。