C ++ CPU寄存器使用
-
11-09-2019 - |
题
在C ++中,本地变量总是分配在栈上。栈是允许的内存,你的应用程序能够占据的一部分。该内存保存在您的RAM(如果没有交换到磁盘)。现在,做一个C ++编译器总是创建存储在栈上的局部变量的汇编代码?
举个例子,下面的简单的代码:
int foo( int n ) {
return ++n;
}
在MIPS汇编代码,这可能是这样的:
foo:
addi $v0, $a0, 1
jr $ra
正如你所看到的,我并不需要在所有使用堆栈代替n。将C ++编译器识别,并直接使用该CPU的寄存器?
编辑:哇,非常感谢您几乎是即时的和广泛的答案! foo的函数体当然应该return ++n;
,不return n++;
。 :)
解决方案
免责声明:我不知道MIPS,但我知道有些X86,我认为原则应该是一样的..
在通常的函数调用约定,编译器将n
的值推送到堆栈上以将其传递给函数foo
。然而,有fastcall
约定,您可以使用来告诉GCC通过寄存器传递值来代替。 (MSVC也有这个选项,但我不知道它的语法是什么。)
test.cpp:
int foo1 (int n) { return ++n; }
int foo2 (int n) __attribute__((fastcall));
int foo2 (int n) {
return ++n;
}
编译上面g++ -O3 -fomit-frame-pointer -c test.cpp
,我获得foo1
:
mov eax,DWORD PTR [esp+0x4]
add eax,0x1
ret
可以看到,它读取在从堆栈的值。
和这里的foo2
:
lea eax,[ecx+0x1]
ret
现在它直接从寄存器取值。
当然,如果你内联函数,编译器会做一个简单的加法在较大的函数体,无论调用约定的指定。但是,当你不能得到它内联,这会发生。
2免责声明:我不是说你应该不断地在事后的编译器。这可能是在大多数情况下,实际的和必要的。但不要以为它产生完美的代码。
修改1:如果你正在谈论普通本地变量(未函数参数),然后是,编译器将在寄存器或其认为合适的栈上分配它们
修改2:的看来,调用约定是体系结构特异性的,和MIPS将通过在堆栈上的前四个参数,如理查德宁顿在他的回答已表示。所以你的情况,你不必指定额外的属性(这实际上是一个特定的x86属性。)
其他提示
是。没有规则“变量总是在堆栈上分配”。 C ++标准没有提到一个stack.It不认为一个堆栈中存在,或寄存器存在。它只是说,代码应该如何表现,它不应该如何实现。
在编译器只存储在堆栈变量时,它必须 - 当他们不得不忍受过去的函数调用,例如,或者如果你试图把他们的地址
。编译器并不笨。 ;)
是,一个良好的,优化的C / C ++将优化这一点。即使的 MUCH 的更多:在这里看到:费利克斯·冯·Leitners编译调查。
一个普通的C / C ++编译器不会把每一个变量在堆栈上了。与您foo()
功能的问题可能是可变可以得到通过堆栈的函数(你的系统的ABI(硬件/ OS),定义了)通过。
在C的register
关键字,您可以给编译器的提示的,这可能会是很好的一个变量保存在寄存器中。样品:
register int x = 10;
但要记住:编译器是免费不保存x
在寄存器中,如果要
答案是肯定的,也许。它依赖于编译器,优化级,和所述目标处理器。
在MIPS的情况下,前四个参数中,如果小,在寄存器传递和返回值被在寄存器返回。所以,你的例子有没有要求分配堆栈上的任何东西。
其实,真理比小说还离奇。在你的情况的参数原样返回:返回的值是n的++运算符之前:
foo:
.frame $sp,0,$ra
.mask 0x00000000,0
.fmask 0x00000000,0
addu $2, $zero, $4
jr $ra
nop
由于您的例子foo
功能是标识功能(它只是返回它的参数),我的C ++编译器(VS 2008)完全消除此函数调用。如果我将其更改为:
int foo( int n ) {
return ++n;
}
,编译器内联这个与
lea edx, [eax+1]
是,这些寄存器在C中使用++。的MDR(存储器数据寄存器)中包含的数据被获取并存储。例如,检索单元123的内容,我们将加载值123(二进制)插入MAR并执行提取操作。当操作完成后,细胞123的内容的副本将在MDR。到值98存储到小区4中,我们加载一个4到MAR和一个98到MDR和执行存储。当操作完成单元4的内容将被设置为98,通过丢弃不管在那里以前。数据和地址寄存器与他们合作来实现这一目标。在C ++中也一样,当我们初始化一个变种具有值或询问它的值,同样的现象发生的情况。
和,还有一两件事,现代编译器也进行寄存器分配,这是有点超过存储器分配得更快。