neodreamerus 发表于 2015-01-05 15:47

寄存器传参和栈传参相比似乎没什么太大优势

有个问题有点困惑我,一般的说法是寄存器传参比栈传参效率高一点,
但是我感觉寄存器传参和栈传参相比似乎没什么太大优势。


比如递归函数factorial(n) = n!
你用寄存器传参数n给factorial, factorial(n)在调用factorial(n-1),
还是会将n压栈,还不如传参的时候直接压栈呢?


一般来说程序里一个函数function的实现代码里总会调用其他函数,特别是标准库函数,
那个通过寄存器传给function的参数很可能会被压入栈内,不如调用function之前直接将该参数
压入栈内。

zsszss0000 发表于 2015-01-05 18:08

我觉得你这样想是不对的
其一:
之所以使用寄存器传递参数,是因为对于CPU来说,寄存器的速度肯定要比内存块,对于可能经常访问的变量,肯定是寄存器中直接计算比较好。
func(int a)
{
      for(a=0;a<1000;a++)
      {
            //执行某些操作
      }
}
那么肯定每次访问a的时候,你都去内存中访问a的速度不如直接去寄存器中访问的速度要快。

其二:寄存器传递参数的使用范围是少量的参数,你的意思是递归问题无法进行寄存器传参数,这块编译器怎么实现的我不知道
但是,可以想象一下,如果每个通过递归传的参数,都压栈,之后再出栈是否可以。这样如果函数中间大量使用到该参数的话是否可以进行优化呢?

zhaohongjian000 发表于 2015-01-06 09:01

你举得例子完全说错了。factorial(n)调用factorial(n-1)时需要把参数取到寄存器中,做-1操作,重新入栈。
如果仍然把n入栈,岂不是仍然调用的factorial(n)?

后面的例子也一样,只要需要对参数做运算,就要把参数从栈中拿出刀寄存器中。就算是直接向下传递,也是
先取出来再传递。

yulihua49 发表于 2015-01-06 11:09

neodreamerus 发表于 2015-01-05 15:47 static/image/common/back.gif
有个问题有点困惑我,一般的说法是寄存器传参比栈传参效率高一点,
但是我感觉寄存器传参和栈传参相比似乎 ...
这是标准,人家制定了ABI,你就必须遵守。

雷男 发表于 2015-01-06 15:31

本帖最后由 雷男 于 2015-01-06 15:47 编辑

麻烦问下如何使用寄存器进行传参?宏定义设置?汇编?跟操作系统相关?__attribute__((regparm(n)))?

yulihua49 发表于 2015-01-07 15:34

雷男 发表于 2015-01-06 15:31 static/image/common/back.gif
麻烦问下如何使用寄存器进行传参?宏定义设置?汇编?跟操作系统相关?__attribute__((regparm(n)))?
编译器弄的,跟你没关系。除非你想在不同的语言间接口,或者写汇编小函数。

neodreamerus 发表于 2015-01-08 21:10

回复 3# zhaohongjian000


兄弟,你一直在说栈传参。
你没见过寄存器传参的吗?x86-64的C函数传参前4个是通过寄存器传的。
下面是个例子
factorial:
        pushq        %rbp
        movq        %rsp, %rbp
        subq        $16, %rsp
        movl        %edi, -4(%rbp)
        cmpl        $1, -4(%rbp)
        jne        .L2
        movl        $1, %eax
        jmp        .L3
.L2:
        movl        -4(%rbp), %eax
        subl        $1, %eax
        movl        %eax, %edi
        call        factorial
        imull        -4(%rbp), %eax
.L3:
        leave
        ret


.LC0:
        .string        "%d\n"
        .text
        .globl        main
        .type        main, @function

main:
        pushq        %rbp
        movq        %rsp, %rbp
        subq        $16, %rsp
        movl        %edi, -4(%rbp)
        movq        %rsi, -16(%rbp)
        movl        $4, %edi
        call        factorial
        movl        %eax, %esi
        movl        $.LC0, %edi
        movl        $0, %eax
        call        printf
        leave
        ret

neodreamerus 发表于 2015-01-08 21:47

本帖最后由 neodreamerus 于 2015-01-08 22:20 编辑

回复 2# zsszss0000


你说的第一点我也理解。但是我问的问题的意思是:类似你举得例子这种简单情况太少了,大部分函数会调用其他函数。用寄存器传参会有一些好处,但是感觉很多时候这种优势并不明显。


第二点嘛,自己写个简单的程序编译一下就知道了。x86-64下函数的前4个参数都是寄存器传参的。我写的程序里,在call指令之前参数放到edi,
然后call。然后在factorial函数内部由于edi要被用于另外的函数calling,所以edi的值又被压入栈中。
#include <stdio.h>



int factorial(int n) {



      if ( n == 1 ) return 1;



      return n*factorial(n-1);

}



int main(int argc, char* argv[]) {



      printf("%d\n", factorial(4));

}


编译成

        .file        "a.c"
        .text
        .globl        factorial
        .type        factorial, @function
factorial:
.LFB0:
        pushq        %rbp
        movq        %rsp, %rbp
        subq        $16, %rsp
        movl        %edi, -4(%rbp)
        cmpl        $1, -4(%rbp)
        jne        .L2
        movl        $1, %eax
        jmp        .L3
.L2:
        movl        -4(%rbp), %eax
        subl        $1, %eax
        movl        %eax, %edi
        call        factorial
        imull        -4(%rbp), %eax
.L3:
        leave
        ret
.LFE0:
        .size        factorial, .-factorial
        .section        .rodata
.LC0:
        .string        "%d\n"
        .text
        .globl        main
        .type        main, @function


main:
        pushq        %rbp
        movq        %rsp, %rbp
        subq        $16, %rsp
        movl        %edi, -4(%rbp)
        movq        %rsi, -16(%rbp)
        movl        $4, %edi
        call        factorial
        movl        %eax, %esi
        movl        $.LC0, %edi
        movl        $0, %eax
        call        printf
        leave
        ret


zhaohongjian000 发表于 2015-01-09 09:07

回复 7# neodreamerus


    没听懂我在说什么?都会自己看汇编了就自己分析吧。x86-32是通过栈传递的,对比一下吧。其他几个我见过的,ARM32、ARM64,MIPS都是通过寄存器传递参数的。

hellioncu 发表于 2015-01-09 09:11

现在很少有需要直接写汇编的时候,这种就让编译器去优化好了
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: 寄存器传参和栈传参相比似乎没什么太大优势