微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 高效的C编程之:寄存器分配

高效的C编程之:寄存器分配

时间:08-30 来源:3721RD 点击:

14.7 寄存器分配

编译器一项很重要的优化功能就是对寄存器的分配。与分配在寄存器中的变量相比,分配到内存的变量访问要慢得多。所以如何将尽可能多的变量分配到寄存器,是编程时应该重点考虑的问题。

注意

当使用-g或-dubug选项编译程序时,为了确保调试信息的完整性,寄存器分配的效率比不使用-g或-dubug选项低很多。

14.7.1 变量寄存器分配

一般情况下,编译器会对C函数中的每一个局部变量分配一个寄存器。如果多个局部变量不会交迭使用,那么编译器会对它们分配同一个寄存器。当局部变量多于可用的寄存器时,编译器会把多余的变量存储到堆栈。这些被写入堆栈需要访问存储器的变量被称为溢出(Spilled)变量。

为了提高程序的执行效率:

· 使溢出变量的数量最少;

· 确保最重要的和经常用到的变量被分配在寄存器中。

可以被分配到寄存器的变量包括:

· 程序中的局部变量;

· 调用子程序时传递的参数;

· 与地址无关变量。

另外,在一些特定条件下,结构体中的域也可以被分配到寄存器中。

表14.1显示了当C编译器采用ARM-Thumb过程调用标准时,内部寄存器的编号、名字和分配方法。

表14.1 C编译器寄存器用法

寄存器编号

可选寄存器名

特殊寄存器名

寄存器用法

r0

a1

函数调用时的参数寄存器,用来存放前4个函数参数和存放返回值。在函数内如果将这些寄存器用作其他用途,将破坏其值。

r1

a2

r2

a3

r3

a4

r4

v1

通用变量寄存器

r5

v2

r6

v3

r7

v4

r8

v5

r9

v6或SB或TR

平台寄存器,不同的平台对该寄存器的定义不同

r10

v7

通用变量寄存器。在使用堆栈边界检测的情况下,r10保存堆栈边界的地址

r11

v8

通用变量寄存器。

r12

IP

临时过渡寄存器,函数调用时会破坏其中的值

r13

SP

堆栈指针

r14

LR

链接寄存器

r15

PC

程序计数器

从表14.1可以看出,编译器可以分配14个变量到寄存器而不会发生溢出。但有些寄存器编译器会有特殊用途(如r12),所以在编写程序时应尽量限制变量的数目,使函数内部最多使用12个寄存器。

注意

在C语言中,可以使用关键词register给指定变量分配专用寄存器。但不同的编译器对该关键词的处理可能不同,使用时要查阅相关手册。

14.7.2 指针别名

C语言中的指针变量可以给编程带来很大的方便。但使用指针变量时要特别小心,它很可能使程序的执行效率下降。在一个函数中,编译器通常不知道是否有2个或2个以上的指针指向同一个地址对象。所以编译器认为,对任何一个指针的写入都将会影响从任何其他指针的读出,但这样会明显降低代码执行的效率。这就是著名的"寄存器别名(Pointer Aliasing)"问题。

注意

一些编译器提供了"忽略指针别名"选项,但这可能给程序带来潜在的bug。ARM编译器是遵循ANSI/ISO标准的编译器,不提供该选项。

1.局部变量指针别名问题

通常情况下,编译器会试图对C函数中的每一个局部变量分配一个寄存器。但当局部变量是指向内存地址的指针时,情况有所不同。先来看一个简单的例子。

void add(int * i)

{

int total1=0,total2=0;

total1+= *i;

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top