【发布时间】:2011-01-12 09:22:47
【问题描述】:
我正在开发一个嵌入式项目,我正在尝试为一些代码添加更多结构,这些代码使用宏来优化对 USART 寄存器的访问。我想将预处理器#define 的寄存器地址组织成 const 结构。如果我将结构定义为宏中的复合文字并将它们传递给内联函数,则 gcc 已经足够聪明,可以绕过生成的程序集中的指针并直接在代码中硬编码结构成员值。例如:
C1:
struct uart {
volatile uint8_t * ucsra, * ucsrb, *ucsrc, * udr;
volitile uint16_t * ubrr;
};
#define M_UARTX(X) \
( (struct uart) { \
.ucsra = &UCSR##X##A, \
.ucsrb = &UCSR##X##B, \
.ucsrc = &UCSR##X##C, \
.ubrr = &UBRR##X, \
.udr = &UDR##X, \
} )
void inlined_func(const struct uart * p, other_args...) {
...
(*p->ucsra) = 0;
(*p->ucsrb) = 0;
(*p->ucsrc) = 0;
}
...
int main(){
...
inlined_func(&M_UART(0), other_parms...);
...
}
这里UCSR0A、UCSR0B、&c,定义为uart寄存器为l值,如
#define UCSR0A (*(uint8_t*)0xFFFF)
gcc 能够完全消除结构字面量,并且像 inlined_func() 中所示的所有赋值都直接写入寄存器地址,无需将寄存器地址读入机器寄存器,也无需间接寻址:
A1:
movb $0, UCSR0A
movb $0, UCSR0B
movb $0, UCSR0C
这会将值直接写入 USART 寄存器,无需将地址加载到机器寄存器中,因此根本不需要将结构字面量生成到目标文件中。 struct 字面量变成了编译时结构,生成的抽象代码没有成本。
我想摆脱宏的使用,并尝试使用在标头中定义的静态常量结构:
C2:
#define M_UART0 M_UARTX(0)
#define M_UART1 M_UARTX(1)
static const struct uart * const uart[2] = { &M_UART0, &M_UART1 };
....
int main(){
...
inlined_func(uart[0], other_parms...);
...
}
但是,gcc 不能在这里完全删除结构:
A2:
movl __compound_literal.0, %eax
movb $0, (%eax)
movl __compound_literal.0+4, %eax
movb $0, (%eax)
movl __compound_literal.0+8, %eax
movb $0, (%eax)
这会将寄存器地址加载到机器寄存器中,并使用间接寻址来写入寄存器。有谁知道无论如何我可以说服 gcc 为 C2 C 代码生成 A1 汇编代码?我尝试了 __restrict 修饰符的各种用法,但均无济于事。
【问题讨论】:
-
不要使用
struct在结构成员和 USART 寄存器之间进行 1:1 映射。允许编译器在struct、class或union的成员之间添加填充(在您不知情的情况下)。我认为将struct映射到 USART 寄存器没有任何好处。另一方面,如果您想使用类建模 USART,那就是另一个话题了... -
如果将结构本身存储在数组中而不是指向它们的指针(即(未经测试)
static const struct uart uart[2] = { M_UART0, M_UART1 };? -
@Christoph:我想到了这一点并尝试了,但没有帮助。
-
您使用哪些编译器/优化级别 - 我的 gcc-4.0.0 确实在
-O1... -
@Christoph:我试过 -O1-3。我正在使用 gcc 4.2.3。
标签: c optimization gcc constants literals