Llvm 如何告诉clang不要将寄存器保存到堆栈? 目标
我目前正在试用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)处的内存中。当然,还有我们无尽的循环: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”来生成程序集输出,并对其进行优化以获得最小的尺寸。我的问题是不必要地保存寄
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
这里发生的是:
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