GCC能否打印出中间结果?

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

zwo*_*wol 3

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 转储,因此最好在临时目录中执行此操作。

(嘘:每次你在括号里面加空格,上帝都会杀死一只小猫。)