jip*_*pie 7 c++ linux gcc avr-gcc
检查以下代码:
#include <avr/io.h>
const uint16_t baudrate = 9600;
void setupUART( void ) {
uint16_t ubrr = ( ( F_CPU / ( 16 * (float) baudrate ) ) - 1 + .5 );
UBRRH = ubrr >> 8;
UBRRL = ubrr & 0xff;
}
int main( void ) {
setupUART();
}
Run Code Online (Sandbox Code Playgroud)
这是用于编译代码的命令:
avr-gcc -g -DF_CPU=4000000 -Wall -Os -Werror -Wextra -mmcu=attiny2313 -Wa,-ahlmns=project.lst -c -o project.o project.cpp
Run Code Online (Sandbox Code Playgroud)
ubrr由编译器计算为25,到目前为止一直很好.但是,为了检查编译器计算的内容,我查看了反汇编列表.
000000ae <setupUART()>:
ae: 12 b8 out UBRRH, r1 ; 0x02
b0: 89 e1 ldi r24, 0x19 ; 25
b2: 89 b9 out UBRRL, r24 ; 0x09
b4: 08 95 ret
Run Code Online (Sandbox Code Playgroud)
是否可以在编译时avr-gcc打印出中间结果(或从.o文件中提取信息),所以当我编译代码时会打印出类似或类似的行?这样我可以快速检查计算和设置.(uint16_t) ubbr = 25
GCC 有命令行选项来请求它在编译的任何阶段之后转储其中间表示。“树”转储采用伪 C 语法,包含您想要的信息。对于您想要做的事情,-fdump-tree-original和-fdump-tree-optimized转储发生在优化管道中的有用点。我手边没有 AVR 编译器,所以我修改了您的测试用例,使其成为独立的并且可以与我拥有的编译器进行编译:
typedef unsigned short uint16_t;
const int F_CPU = 4000000;
const uint16_t baudrate = 9600;
extern uint16_t UBRRH, UBRRL;
void
setupUART(void)
{
uint16_t ubrr = ((F_CPU / (16 * (float) baudrate)) - 1 + .5);
UBRRH = ubrr >> 8;
UBRRL = ubrr & 0xff;
}
Run Code Online (Sandbox Code Playgroud)
进而
$ gcc -O2 -S -fdump-tree-original -fdump-tree-optimized test.c
$ cat test.c.003t.original
;; Function setupUART (null)
;; enabled by -tree-original
{
uint16_t ubrr = 25;
uint16_t ubrr = 25;
UBRRH = (uint16_t) ((short unsigned int) ubrr >> 8);
UBRRL = ubrr & 255;
}
$ cat test.c.149t.optimized
;; Function setupUART (setupUART, funcdef_no=0, decl_uid=1728, cgraph_uid=0)
setupUART ()
{
<bb 2>:
UBRRH = 0;
UBRRL = 25;
return;
}
Run Code Online (Sandbox Code Playgroud)
您可以看到常量表达式折叠完成得很早,以至于它已经发生在“原始”转储(这是您可以拥有的最早的可理解转储)中,并且优化已进一步将移位和掩码操作折叠到写入的语句中UBRRH 和 UBRRL。
文件名中的数字(003t 和 149t)可能与您不同。如果您想查看所有“树”转储,请使用-fdump-tree-all. 还有“RTL”转储,它们看起来一点也不像 C,而且可能对您没有用处。不过,如果你好奇的话,-fdump-rtl-all可以打开它们。总共有大约 100 个树转储和 60 个 RTL 转储,因此最好在临时目录中执行此操作。
(嘘:每次你在括号里面加空格,上帝都会杀死一只小猫。)