繁体   English   中英

C ++ Lambda生成的ASM代码

[英]C++ Lambda Generated ASM code

我有以下初始C ++代码:

class Lambda
{
public:
    int compute(int &value){
        auto get = [&value]() -> int {
            return 11 * value;
        };
        return get();
    }
};

int main(){
    Lambda lambda;
    int value = 77;
    return lambda.compute(value);
}

使用clang编译(使用-O1)生成ASM以下:

main: # @main
  push rax
  mov dword ptr [rsp + 4], 77
  mov rdi, rsp
  lea rsi, [rsp + 4]
  call Lambda::compute(int&)
  pop rcx
  ret
Lambda::compute(int&): # @Lambda::compute(int&)
  push rax
  mov qword ptr [rsp], rsi
  mov rdi, rsp
  call Lambda::compute(int&)::{lambda()#1}::operator()() const
  pop rcx
  ret
Lambda::compute(int&)::{lambda()#1}::operator()() const: # @Lambda::compute(int&)::{lambda()#1}::operator()() const
  mov rax, qword ptr [rdi]
  mov eax, dword ptr [rax]
  lea ecx, [rax + 4*rax]
  lea eax, [rax + 2*rcx]
  ret

问题:

  1. 什么是出现在ASM中的{lambda()#1} 据我所知,它可能是一个封装函数对象(即lambda体)的闭包。 请确认是否如此。
  2. 是否每次触发compute()都会生成一个新的闭包? 或者是同一个实例?
  1. 它是您在compute声明的lambda函数的主体(实现)。
  2. 是的,每次调用计算,概念和实践(在此优化级别1 )时,都会在堆栈上创建一个新的闭包,并使用指向该闭包的指针调用关联的lambda函数(作为rdi传递,即作为第一个以同样的方式作为参数this指出用于一个成员函数)。

1 “在此优化级别”部分非常重要。 这里没有任何东西实际上需要编译器生成闭包或单独的lambda函数。 例如,在-O2 ,clang 优化所有这些,并直接在main()中将答案作为常量返回。 即使在-O1 gcc也会进行相同的优化。

  1. 是的,调用lambda函数将需要生成一个闭包[除非编译器可以推断它实际上没有被使用]
  2. 通过此优化,每次调用都将调用compute ,而compute又调用内部函数get() ,它是compute函数中的lambda函数。 让编译器优化到更高的程度,对于这种情况,将优化呼叫 - 在我的尝试中,它将完全删除整个调用-O2 ,并且只返回预先计算的常量847 - 正如您所期望的那样。 对于更复杂的情况,它可能会或可能不会内联lambda部分但保持外部调用,反之亦然。 这在很大程度上取决于所涉及的功能内部的具体细节。

    为了清楚起见,编译器完全按照你的要求执行:调用函数compute ,然后调用函数get

添加

    int value2 = 88;
    int tmp = lambda.compute(value2);

进入原始问题的main函数基本上对生成的代码产生了这种改变(在Linux上使用clang ++):

main:                                   # @main
    pushq   %rbx
    subq    $16, %rsp
    movl    $77, 12(%rsp)
    ## new line to set value2
    movl    $88, 8(%rsp)
    movq    %rsp, %rbx
    ## New line, passing reference of `value2` to lambda.compute
    leaq    8(%rsp), %rsi
    movq    %rbx, %rdi
    ## Call lambda.compute
    callq   _ZN6Lambda7computeERi
    ## Same as before.
    leaq    12(%rsp), %rsi
    movq    %rbx, %rdi
    callq   _ZN6Lambda7computeERi
    addq    $16, %rsp
    popq    %rbx
    retq

生成的代码为

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM