Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/svn/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Llvm 如何告诉clang不要将寄存器保存到堆栈? 目标_Llvm_Clang_Avr_Llvm Clang_Optimization - Fatal编程技术网

Llvm 如何告诉clang不要将寄存器保存到堆栈? 目标

Llvm 如何告诉clang不要将寄存器保存到堆栈? 目标,llvm,clang,avr,llvm-clang,optimization,Llvm,Clang,Avr,Llvm Clang,Optimization,我目前正在试用avr llvm(一种支持avr作为目标的llvm)。我的主要目标是使用它最好的优化器(与gcc优化器相比)来实现更小的二进制文件。如果你对AVR略知一二,你就会知道你只有很少的记忆 我目前使用的是一个45英寸、4KB的闪存和256字节(只是字节而不是KB!)的SRAM 问题 我试图编译一个简单的C程序(见下文),以检查生成了什么汇编代码以及机器代码大小是如何发展的。我使用“clang-Oz-stest.c”来生成程序集输出,并对其进行优化以获得最小的尺寸。我的问题是不必要地保存寄

我目前正在试用avr llvm(一种支持avr作为目标的llvm)。我的主要目标是使用它最好的优化器(与gcc优化器相比)来实现更小的二进制文件。如果你对AVR略知一二,你就会知道你只有很少的记忆

我目前使用的是一个45英寸、4KB的闪存和256字节(只是字节而不是KB!)的SRAM

问题 我试图编译一个简单的C程序(见下文),以检查生成了什么汇编代码以及机器代码大小是如何发展的。我使用“clang-Oz-stest.c”来生成程序集输出,并对其进行优化以获得最小的尺寸。我的问题是不必要地保存寄存器值,因为知道此方法永远不会返回

我的问题。。。 我如何告诉llvm,如果需要的话,它可以直接删除任何寄存器,而不保存/恢复它的内容?有没有办法进一步优化它(例如,更有效地设置堆栈)

详情/例子 这是我的测试程序。如上所述,它是使用“clang-Oz-S test.c”编译的

是啊!对于这样一个简单的程序来说,这是大量的机器代码。我刚刚测试了一些变化,并查看了AVR的参考手册。。。所以我可以解释发生了什么。让我们看看每个部分

这是“牛肉”,它只是做我们的c程序所要做的。它用值“1”加载r24,该值存储在Y+1(堆栈指针+1)处的内存中。当然,还有我们无尽的循环:

ldi r24, 1
std Y+1, r24

.BB0_1:
    rjmp    .BB0_1
注意:需要无限循环。否则将忽略
\uuuuu属性((noreturn))
,并在稍后恢复堆栈指针+保存的寄存器

在此之前,设置“Y”中的指针:

in  r28, 61
in  r29, 62
sbiw    r29:r28, 1
in  r0, 63
cli
out 62, r29
out 63, r0
out 61, r28
这里发生的是:

  • Y(寄存器对r28:r29相当于“Y”)从端口61和62加载,这些端口映射到一些“寄存器”,即SPL和SPH(“S”tack“P”指针的L”ow和“H”igh字节)
  • 加载值递减(sbiw r29:r28)
  • 堆栈指针的更改值保存回端口;我想是为了避免出现问题:中断以前是禁用的;“cli/sti”[存储在寄存器63(SREG)]中的状态保存到r0,然后恢复到端口63
  • 堆栈寄存器的这种设置似乎效率低下。要增加堆栈指针,我只需要将r0“推送到堆栈。然后我可以将SPH/SPL的值加载到r29:r28中。然而,这可能需要在源代码中对llvm的优化器进行一些更改。如果必须为局部变量保留超过3个字节的堆栈(即使优化-O3,对于-Oz,最多6个字节也有意义),那么上面的代码才有意义。无论如何。。。我想我们需要触及llvm的来源;所以这超出了范围

    更有趣的是这一部分:

        push    r28
        push    r29
    
    因为main()不打算返回,所以这没有意义。这只是为了愚蠢的指令而浪费RAM和闪存(请记住:在某些设备中,我们只有64、128或256字节的SRAM可用)

    我对此做了进一步的研究:如果我们让main返回(例如,没有无止境的循环)堆栈指针被还原,那么我们在末尾有一条“ret”指令,寄存器r28和r29通过“pop r29,pop 28”从堆栈还原。但是编译器应该知道,如果函数“main”的作用域从未离开,那么所有寄存器都可以被删除,而不必将它们存储到堆栈中

    当我们谈到2字节RAM时,这个问题似乎有点“愚蠢”。但是只要想想如果程序开始使用其余的寄存器会发生什么

    所有这些确实改变了我对当前“编译器”的看法。我认为今天通过汇编程序进行优化的空间不大。但似乎有

    所以,问题仍然是……

    您是否知道如何改善这种情况(除了提交错误报告/功能请求)

    我的意思是:是否有一些编译器开关我可能忽略了

    附加信息 使用
    \uuuu属性(OS\u main))
    适用于avr gcc

    输出如下:

        .file   "test.c"
    __SREG__ = 0x3f
    __SP_H__ = 0x3e
    __SP_L__ = 0x3d
    __CCP__  = 0x34
    __tmp_reg__ = 0
    __zero_reg__ = 1
        .global __do_copy_data
        .global __do_clear_bss
        .text
    .global main
        .type   main, @function
    main:
        push __tmp_reg__
        in r28,__SP_L__
        in r29,__SP_H__
    /* prologue: function */
    /* frame size = 1 */
        ldi r24,lo8(1)
        std Y+1,r24
    .L2:
        rjmp .L2
        .size   main, .-main
    

    在我看来,这个示例程序的大小(6条指令或12个字节)和速度都是最佳的。llvm是否有任何等效属性?(clang版本'3.2(trunk 160228)(基于LLVM 3.2svn)'既不知道OS_任务,也不知道OS_main的任何信息)。

    安东在他的评论中多少提到了这个问题的答案:问题不在LLVM中,而是在你的AVR目标中。例如,下面是一个等效的程序,它通过Clang和LLVM为其他目标运行:

    % cat test.c
    __attribute__((noreturn)) int main() {
      volatile unsigned char res = 1;
      while (1) {}
    }
    
    % ./bin/clang -c -o - -S -Oz test.c  # I'm on an x86-64 machine
    <snip>
    main:                                   # @main
            .cfi_startproc
    # BB#0:                                 # %entry
            movb    $1, -1(%rsp)
    .LBB0_1:                                # %while.body
                                            # =>This Inner Loop Header: Depth=1
            jmp     .LBB0_1
    .Ltmp0:
            .size   main, .Ltmp0-main
            .cfi_endproc
    
    % ./bin/clang -c -o - --target=armv6-unknown-linux-gnueabi -S -Oz test.c
    <snip>
    main:
            sub     sp, sp, #4
            mov     r0, #1
            strb    r0, [sp, #3]
    .LBB0_1:
            b       .LBB0_1
    .Ltmp0:
            .size   main, .Ltmp0-main
    
    % ./bin/clang -c -o - --target=powerpc64-unknown-linux-gnu -S -Oz test.c
    <snip>
    main:
            .align  3
            .quad   .L.main
            .quad   .TOC.@tocbase
            .quad   0
            .text
    .L.main:
            li 3, 1
            stb 3, -9(1)
    .LBB0_1:
            b .LBB0_1
            .long   0
            .quad   0
    .Ltmp0:
            .size   main, .Ltmp0-.L.main
    
    %cat test.c
    __属性(noreturn))int main(){
    易失性无符号字符res=1;
    而(1){}
    }
    %/bin/clang-c-o--S-Oz测试。c#我在x86-64机器上
    main:#@main
    .cfi_startproc
    #BB#0:#%条目
    movb$1,-1(%rsp)
    .LBB0_1:#%while.body
    #=>此内部循环标题:深度=1
    jmp.LBB0_1
    .Ltmp0:
    .size main、.Ltmp0 main
    .cfi_endproc
    %./bin/clang-c-o----target=armv6未知linux gnueabi-S-Oz test.c
    主要内容:
    副警司,警司,#4
    mov r0,#1
    strb r0[sp,#3]
    .LBB0_1:
    b.LBB0_1
    .Ltmp0:
    .size main、.Ltmp0 main
    %./bin/clang-c-o----target=powerpc64未知linux gnu-S-Oz test.c
    主要内容:
    .对齐3
    四号,左主
    .quad.TOC@tocbase
    .quad 0
    .文本
    .L.main:
    李3,1
    机顶盒3,-9(1)
    .LBB0_1:
    b.LBB0_1
    .long 0
    .quad 0
    .Ltmp0:
    .size main、.Ltmp0-.L.main
    
    正如您可以看到的,对于这三个目标,生成的唯一代码是保留堆栈空间(如果需要,它不在x86-64上)并在堆栈上设置值。我认为这是最低限度的

    也就是说,如果你真的找到专业人士
        .file   "test.c"
    __SREG__ = 0x3f
    __SP_H__ = 0x3e
    __SP_L__ = 0x3d
    __CCP__  = 0x34
    __tmp_reg__ = 0
    __zero_reg__ = 1
        .global __do_copy_data
        .global __do_clear_bss
        .text
    .global main
        .type   main, @function
    main:
        push __tmp_reg__
        in r28,__SP_L__
        in r29,__SP_H__
    /* prologue: function */
    /* frame size = 1 */
        ldi r24,lo8(1)
        std Y+1,r24
    .L2:
        rjmp .L2
        .size   main, .-main
    
    % cat test.c
    __attribute__((noreturn)) int main() {
      volatile unsigned char res = 1;
      while (1) {}
    }
    
    % ./bin/clang -c -o - -S -Oz test.c  # I'm on an x86-64 machine
    <snip>
    main:                                   # @main
            .cfi_startproc
    # BB#0:                                 # %entry
            movb    $1, -1(%rsp)
    .LBB0_1:                                # %while.body
                                            # =>This Inner Loop Header: Depth=1
            jmp     .LBB0_1
    .Ltmp0:
            .size   main, .Ltmp0-main
            .cfi_endproc
    
    % ./bin/clang -c -o - --target=armv6-unknown-linux-gnueabi -S -Oz test.c
    <snip>
    main:
            sub     sp, sp, #4
            mov     r0, #1
            strb    r0, [sp, #3]
    .LBB0_1:
            b       .LBB0_1
    .Ltmp0:
            .size   main, .Ltmp0-main
    
    % ./bin/clang -c -o - --target=powerpc64-unknown-linux-gnu -S -Oz test.c
    <snip>
    main:
            .align  3
            .quad   .L.main
            .quad   .TOC.@tocbase
            .quad   0
            .text
    .L.main:
            li 3, 1
            stb 3, -9(1)
    .LBB0_1:
            b .LBB0_1
            .long   0
            .quad   0
    .Ltmp0:
            .size   main, .Ltmp0-.L.main