c++ - 内联函数是如何编译成汇编的?

标签 c++ assembly visual-c++ inline

我有一些循环更新值的 C++ 代码,出于好奇,我想看看构成主体循环的程序集。这让我尝试了一些内联在编译后的样子(编译器是带有 O2 的 MSVC)。

但是,当我将指令集与实际内联后的指令集进行比较时,我对自己的发现感到有些困惑。这是一些上下文:

template<typename T>
struct ClassWithInline
{
    Values *v;

    ClassWithInline(Values *v) : v{ v } {}
    T inlineMe(T * const c) const
    {
        // some function of *c, using v->some_constants
    }
};

Values 对象只是包含常量的东西。 ClassWithInline 是另一个对象 Owner 的成员,并且 owner 有一个函数 callTheInline:

struct Owner
{

    ClassWithInline<double> a;
    Values *v;

    Owner(Values *v) : a{ ClassWithInline<double>(v) }, v{ v } {}
    void callTheInline()
    {
        double *ptr = new double[100];
        double *dptr = new double[100];

        size_t the_end = std::floor(1000 + log(100000));

        for (size_t n = 0; n < the_end; ++n)
        {
            dptr[n] = a.inlineMe(ptr + n);
        }

        ClassWithInline<double> b(v);
        for (size_t n = 0; n < the_end; ++n)
        {
            dptr[n] = b.inlineMe(ptr + n);
        }
    }
};

(不稳定的结束迭代数是为了让编译器在编译时不知道循环的大小并引入一些其他优化。)

现在,当我查看为那些 for 循环生成的程序集时,它们截然不同;事实上,从 a 调用 inlineMe 的汇编指令是原来的两倍。我该如何弥合这种差异?

a.inlineMe(ptr + n);

000000013F642094  mov         rbp,rbx  
000000013F642097  mov         qword ptr [rsp+20h],r15  
000000013F64209C  sub         rbp,rsi  
000000013F64209F  lea         r15,[r9-3]  
000000013F6420A3  mov         r14,rsi  
000000013F6420A6  lea         r10,[rbx+8]  
000000013F6420AA  sub         r14,rbx  
000000013F6420AD  nop         dword ptr [rax]  
000000013F6420B0  mov         rcx,qword ptr [rdi]  
000000013F6420B3  lea         rdx,[r14+r10]  
000000013F6420B7  movsd       xmm0,mmword ptr [r10-8]  
000000013F6420BD  movsd       xmm1,mmword ptr [rdx+rbp-10h]  
000000013F6420C3  addsd       xmm1,mmword ptr [r10]  
000000013F6420C8  movsd       xmm2,mmword ptr [rdi+8]  
000000013F6420CD  lea         rax,[rcx+r8]  
000000013F6420D1  mulsd       xmm0,xmm3  
000000013F6420D5  mulsd       xmm2,xmm2  
000000013F6420D9  addsd       xmm1,mmword ptr [rbx+rax*8]  
000000013F6420DE  mov         rax,r8  
000000013F6420E1  sub         rax,rcx  
000000013F6420E4  addsd       xmm1,mmword ptr [rbx+rax*8]  
000000013F6420E9  subsd       xmm1,xmm0  
000000013F6420ED  divsd       xmm1,xmm2  
000000013F6420F1  movsd       mmword ptr [r14+r10-8],xmm1  
000000013F6420F8  movsd       xmm1,mmword ptr [r10+8]  
000000013F6420FE  addsd       xmm1,mmword ptr [r10-8]  
000000013F642104  mov         rcx,qword ptr [rdi]  
000000013F642107  movsd       xmm0,mmword ptr [r10]  
000000013F64210C  movsd       xmm2,mmword ptr [rdi+8]  
000000013F642111  mulsd       xmm0,xmm3  
000000013F642115  lea         rax,[rcx+r8]  
000000013F642119  mulsd       xmm2,xmm2  
000000013F64211D  addsd       xmm1,mmword ptr [rbx+rax*8+8]  
000000013F642123  mov         rax,r8  
000000013F642126  sub         rax,rcx  
000000013F642129  addsd       xmm1,mmword ptr [rbx+rax*8+8]  
000000013F64212F  subsd       xmm1,xmm0  
000000013F642133  divsd       xmm1,xmm2  
000000013F642137  movsd       mmword ptr [rdx],xmm1  
000000013F64213B  movsd       xmm1,mmword ptr [r10+10h]  
000000013F642141  addsd       xmm1,mmword ptr [r10]  
000000013F642146  mov         rcx,qword ptr [rdi]  
000000013F642149  movsd       xmm0,mmword ptr [r10+8]  
000000013F64214F  movsd       xmm2,mmword ptr [rdi+8]  
000000013F642154  mulsd       xmm0,xmm3  
000000013F642158  lea         rax,[rcx+r8]  
000000013F64215C  mulsd       xmm2,xmm2  
000000013F642160  addsd       xmm1,mmword ptr [rbx+rax*8+10h]  
000000013F642166  mov         rax,r8  
000000013F642169  sub         rax,rcx  
000000013F64216C  addsd       xmm1,mmword ptr [rbx+rax*8+10h]  
000000013F642172  subsd       xmm1,xmm0  
000000013F642176  divsd       xmm1,xmm2  
000000013F64217A  movsd       mmword ptr [r14+r10+8],xmm1  
000000013F642181  movsd       xmm1,mmword ptr [r10+18h]  
000000013F642187  addsd       xmm1,mmword ptr [r10+8]  
000000013F64218D  mov         rcx,qword ptr [rdi]  
000000013F642190  movsd       xmm0,mmword ptr [r10+10h]  
000000013F642196  movsd       xmm2,mmword ptr [rdi+8]  
000000013F64219B  mulsd       xmm0,xmm3  
000000013F64219F  lea         rax,[rcx+r8]  
000000013F6421A3  mulsd       xmm2,xmm2  
000000013F6421A7  addsd       xmm1,mmword ptr [rbx+rax*8+18h]  
000000013F6421AD  mov         rax,r8  
000000013F6421B0  add         r8,4  
000000013F6421B4  sub         rax,rcx  
000000013F6421B7  addsd       xmm1,mmword ptr [rbx+rax*8+18h]  
000000013F6421BD  subsd       xmm1,xmm0  
000000013F6421C1  divsd       xmm1,xmm2  
000000013F6421C5  movsd       mmword ptr [r14+r10+10h],xmm1  
000000013F6421CC  add         r10,20h  
000000013F6421D0  cmp         r8,r15  
000000013F6421D3  jb          Owner::callTheInline+0B0h (013F6420B0h) 

b.inlineMe(ptr + n);

000000013F6422A4  movsd       xmm1,mmword ptr [rcx+r10*8-10h]  
000000013F6422AB  addsd       xmm1,mmword ptr [rdx+rcx]  
000000013F6422B0  movsd       xmm0,mmword ptr [rdx+rcx-8]  
000000013F6422B6  mulsd       xmm0,xmm3  
000000013F6422BA  addsd       xmm1,mmword ptr [rcx+r8*8-8]  
000000013F6422C1  addsd       xmm1,mmword ptr [rcx-8]  
000000013F6422C6  subsd       xmm1,xmm0  
000000013F6422CA  divsd       xmm1,xmm5  
000000013F6422CE  movsd       mmword ptr [rdi+rcx-8],xmm1  
000000013F6422D4  movsd       xmm2,mmword ptr [rdx+rcx-8]  
000000013F6422DA  addsd       xmm2,mmword ptr [rdx+rcx+8]  
000000013F6422E0  movsd       xmm0,mmword ptr [rdx+rcx]  
000000013F6422E5  mulsd       xmm0,xmm3  
000000013F6422E9  addsd       xmm2,mmword ptr [rcx+r8*8]  
000000013F6422EF  addsd       xmm2,mmword ptr [rcx]  
000000013F6422F3  subsd       xmm2,xmm0  
000000013F6422F7  divsd       xmm2,xmm5  
000000013F6422FB  movsd       mmword ptr [rdi+rcx],xmm2  
000000013F642300  movsd       xmm0,mmword ptr [rdx+rcx+8]  
000000013F642306  movsd       xmm1,mmword ptr [rdx+rcx]  
000000013F64230B  addsd       xmm1,mmword ptr [rcx+rbp]  
000000013F642310  mulsd       xmm0,xmm3  
000000013F642314  addsd       xmm1,mmword ptr [rcx+r8*8+8]  
000000013F64231B  addsd       xmm1,mmword ptr [rcx+8]  
000000013F642320  subsd       xmm1,xmm0  
000000013F642324  divsd       xmm1,xmm5  
000000013F642328  movsd       mmword ptr [rdi+rcx+8],xmm1  
000000013F64232E  movsd       xmm2,mmword ptr [rcx+r10*8+18h]  
000000013F642335  addsd       xmm2,mmword ptr [rdx+rcx+8]  
000000013F64233B  movsd       xmm0,mmword ptr [rcx+rbp]  
000000013F642340  mulsd       xmm0,xmm3  
000000013F642344  addsd       xmm2,mmword ptr [rcx+r8*8+10h]  
000000013F64234B  addsd       xmm2,mmword ptr [rcx+10h]  
000000013F642350  subsd       xmm2,xmm0  
000000013F642354  divsd       xmm2,xmm5  
000000013F642358  movsd       mmword ptr [r14+rcx],xmm2  
000000013F64235E  add         rcx,20h  
000000013F642362  sub         rax,1  
000000013F642366  jne         Owner::callTheInline+2A4h (013F6422A4h)  

最佳答案

函数的内联具有三个主要作用:

  • 它消除了函数调用开销。
  • 它允许编译器跨越函数的边界进行优化。
  • 它允许编译器对传递给函数的硬编码参数做出硬性假设。这包括指向成员函数的 this 指针。

内联总是发生在 C++ 代码被翻译成汇编之前。编译器本质上将内联函数视为将被调用函数的源代码插入到调用位置。几乎。 (实际上,编译器通常将内联函数编译成一个普通的普通函数,并为其分配弱链接,但这不会在进一步的内联过程中使用。这里不感兴趣。)

在您的示例中,aOwner 的成员,b 是堆栈上的局部变量。 ab 都保持状态v

要寻址a,编译器需要通过Owner 的this 指针来寻址它。要寻址b,编译器不需要使用Owner 的this 指针,它只是在堆栈上。仅此一项就已经在指令数量上产生了很大的差异。实际上,这还取决于是否允许编译器内联 callTheInline() 以及编译器对 Owner 实例的存储了解多少。

a.v 的值在函数 callTheInline() 结束后仍然存在,而 b 不会在该函数结束后持续存在。这可能允许编译器省略某些计算。但是 b.v 不会持续到函数结束之后,这允许编译器省略计算 inlineMe()

关于c++ - 内联函数是如何编译成汇编的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54772936/

相关文章:

c - 为什么将 char 传递给函数会改变它在 c 中的值?

assembly - 当前程序状态寄存器异常模式

c++ - Visual Studio : How to specify different runtime libraries for the linker?(/MTd、MDd 等)

c++ - 内存排序、指令重新排序和缺少 happens-before 关系

c++ - 在多核盒子上使用忙循环应用程序

C++ 从值数组中保存图像的快速方法

assembly - MIPS - 释放动态分配的空间(堆)

c++ - 在 IMMDeviceEnumerator 上调用 SAFE_RELEASE 时崩溃

c++ - 当我在顶点着色器中有 "out"时,OpenGL 不绘制

c++ - 处理运行时类型未知的模板