在汇编代码中查找不必要的缓冲区副本

时间:2011-04-26 15:34:09

标签: c++ optimization assembly windows-mobile arm

我正在使用Visual Studio 2008 C ++ for Windows Mobile 6 ARMV4I,我正在尝试学习读取VS生成的ARM汇编代码,以最大限度地减少应用程序中不需要的缓冲区副本。所以,我创建了一个如下所示的测试应用程序:

#include <vector>

typedef std::vector< BYTE > Buf;

class Foo
{
public:
    Foo( Buf b ) { b_.swap( b ); };
private:
    Buf b_;
};

Buf Create()
{
    Buf b( 1024 );
    b[ 0 ] = 0x0001;
    return b;
}

int _tmain( int argc, _TCHAR* argv[] )
{
    Foo f( Create() );
    return 0;
}

我想了解Create返回的缓冲区是否在被赋予Foo构造函数时被复制,或者编译器是否能够优化该副本。在启用了优化的发布版本中,这会生成如下所示的程序集:

class Foo
{
public:
    Foo( Buf b ) { b_.swap( b ); };
0001112C  stmdb       sp!, {r4 - r7, lr} 
00011130  mov         r7, r0 
00011134  mov         r3, #0 
00011138  str         r3, this 
0001113C  str         r3, [r7, #4] 
00011140  str         r3, [r7, #8] 
00011144  ldr         r3, this 
00011148  ldr         r2, this 
0001114C  mov         r5, r7 
00011150  mov         r4, r1 
00011154  str         r3, this, #4 
00011158  str         r2, this, #4 
0001115C  mov         r6, r1 
00011160  ldr         r2, this 
00011164  ldr         r3, this 
00011168  mov         lr, r7 
0001116C  str         r3, this 
00011170  str         r2, this 
00011174  ldr         r2, [lr, #8]! 
00011178  ldr         r3, [r6, #8]! 
0001117C  str         r3, this 
00011180  str         r2, this 
00011184  ldr         r3, this 
00011188  movs        r0, r3 
0001118C  beq         |Foo::Foo + 0x84 ( 111b0h )| 
00011190  ldr         r3, [r1, #8] 
00011194  sub         r1, r3, r0 
00011198  cmp         r1, #0x80 
0001119C  bls         |Foo::Foo + 0x80 ( 111ach )| 
000111A0  bl          000112D4 
000111A4  mov         r0, r7 
000111A8  ldmia       sp!, {r4 - r7, pc} 
000111AC  bl          |stlp_std::__node_alloc::_M_deallocate ( 11d2ch )| 
000111B0  mov         r0, r7 
000111B4  ldmia       sp!, {r4 - r7, pc} 
--- ...\stlport\stl\_vector.h -----------------------------
// snip!
--- ...\asm_test.cpp
    private:
        Buf b_;
    };

Buf Create()
{
00011240  stmdb       sp!, {r4, lr} 
00011244  mov         r4, r0 
    Buf b( 1024 );
00011248  mov         r1, #1, 22 
0001124C  bl          |    
    b[ 0 ] = 0x0001;
00011250  ldr         r3, [r4] 
00011254  mov         r2, #1 
    return b;
}

int _tmain( int argc, _TCHAR* argv[] )
{
00011264  str         lr, [sp, #-4]! 
00011268  sub         sp, sp, #0x18 
    Foo f( Create() );
0001126C  add         r0, sp, #0xC 
00011270  bl          |Create ( 11240h )| 
00011274  mov         r1, r0 
00011278  add         r0, sp, #0 
0001127C  bl          |Foo::Foo ( 1112ch )| 
    return 0;
00011280  ldr         r0, argc 
00011284  cmp         r0, #0 
00011288  beq         |wmain + 0x44 ( 112a8h )| 
0001128C  ldr         r3, [sp, #8] 
00011290  sub         r1, r3, r0 
00011294  cmp         r1, #0x80 
00011298  bls         |wmain + 0x40 ( 112a4h )| 
0001129C  bl          000112D4 
000112A0  b           |wmain + 0x44 ( 112a8h )| 
000112A4  bl          |stlp_std::__node_alloc::_M_deallocate ( 11d2ch )| 
000112A8  mov         r0, #0 
}

我可以在汇编代码中查找哪些模式来了解Buf结构的复制位置?

2 个答案:

答案 0 :(得分:0)

分析Create非常简单,因为代码太短了。 NRVO显然已在此处应用,因为return语句不生成任何指令,返回值在r0内就地构建。

Foo::Foo传递值传递参数的副本稍微难以分析,但在调用CreateFoo::Foo之间的代码非常少必须进行复制,并且不会对std::vector进行深层复制。因此看起来该副本也已被删除。另一种可能性是Foo::Foo的自定义调用约定,其中参数实际上通过引用传递并复制到函数内部。你需要一个能够进行更深入的ARM装配分析的人,我要排除它。

答案 1 :(得分:-2)

将复制缓冲区;你正在使用c ++的pass by value语义;没有编译器会为您优化。它的复制方式将取决于std :: vector的复制构造函数。