跟踪位操作的优化机会?

Chr*_*mer 12 c c++ optimization 64-bit bit-manipulation

你觉得函数haswon有优化的余地吗(见下文)?

我认为,从不断变化的参数类型__int64,以unsigned __int64取得该函数更快,所以我thougt也许还有优化的机会.

更详细: 我正在写一个连接四游戏.最近我使用了Profiler Very Sleepy,并认识到函数haswon使用了大部分的cpu-time.该功能使用连接四板的位板表示给一个玩家.我在fourstones基准测试的源代码中发现了这个函数.位板表示如下:

.  .  .  .  .  .  .  TOP
5 12 19 26 33 40 47
4 11 18 25 32 39 46
3 10 17 24 31 38 45
2  9 16 23 30 37 44
1  8 15 22 29 36 43
0  7 14 21 28 35 42  BOTTOM
Run Code Online (Sandbox Code Playgroud)

功能:

// return whether newboard includes a win
bool haswon(unsigned __int64 newboard)
{
    unsigned __int64 y = newboard & (newboard >> 6);
    if (y & (y >> 2 * 6)) // check \ diagonal
        return true;
    y = newboard & (newboard >> 7);
    if (y & (y >> 2 * 7)) // check horizontal -
        return true;
    y = newboard & (newboard >> 8);
    if (y & (y >> 2 * 8)) // check / diagonal
        return true;
    y = newboard & (newboard >> 1);
    if (y & (y >> 2))     // check vertical |
        return true;
    return false;
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

编辑: CPU是x86,32位架构,我正在使用Visual Studio 2008 Express Edition中的编译器.优化标志是/ O2/Oi/GL.

我尝试了Ben Jackson建议的函数haswon2.来自Microsoft Compiler的程序集,以及发行版本(/ O2/Oi/GL)的默认优化标志,几乎没有显示运行时差异.看起来VC-Compiler与gcc相比无法利用它不能严格按顺序评估每个条件.

结果: haswon原文: 赢了

来自Ben Jackson的haswon2: haswon2

编辑2:haswon的 集会:

00401A10  mov         eax,dword ptr [esp+4] 
00401A14  mov         ecx,dword ptr [esp+8] 
00401A18  push        ebx  
00401A19  push        esi  
00401A1A  push        edi  
00401A1B  mov         edx,eax 
00401A1D  mov         edi,ecx 
00401A1F  shrd        edx,edi,6 
00401A23  mov         esi,edx 
00401A25  shr         edi,6 
00401A28  and         esi,eax 
00401A2A  and         edi,ecx 
00401A2C  mov         edx,esi 
00401A2E  mov         ebx,edi 
00401A30  shrd        edx,ebx,0Ch 
00401A34  shr         ebx,0Ch 
00401A37  and         edx,esi 
00401A39  and         ebx,edi 
00401A3B  or          edx,ebx 
00401A3D  je          `anonymous namespace'::haswon+35h (401A45h) 
00401A3F  mov         al,1 
00401A41  pop         edi  
00401A42  pop         esi  
00401A43  pop         ebx  
00401A44  ret              
00401A45  mov         edx,eax 
00401A47  mov         edi,ecx 
00401A49  shrd        edx,edi,7 
00401A4D  mov         esi,edx 
00401A4F  shr         edi,7 
00401A52  and         esi,eax 
00401A54  and         edi,ecx 
00401A56  mov         edx,esi 
00401A58  mov         ebx,edi 
00401A5A  shrd        edx,ebx,0Eh 
00401A5E  shr         ebx,0Eh 
00401A61  and         edx,esi 
00401A63  and         ebx,edi 
00401A65  or          edx,ebx 
00401A67  jne         `anonymous namespace'::haswon+2Fh (401A3Fh) 
00401A69  mov         edx,eax 
00401A6B  mov         edi,ecx 
00401A6D  shrd        edx,edi,8 
00401A71  mov         esi,edx 
00401A73  shr         edi,8 
00401A76  and         esi,eax 
00401A78  and         edi,ecx 
00401A7A  mov         edx,esi 
00401A7C  mov         ebx,edi 
00401A7E  shrd        edx,ebx,10h 
00401A82  shr         ebx,10h 
00401A85  and         edx,esi 
00401A87  and         ebx,edi 
00401A89  or          edx,ebx 
00401A8B  jne         `anonymous namespace'::haswon+2Fh (401A3Fh) 
00401A8D  mov         edx,eax 
00401A8F  mov         esi,ecx 
00401A91  shrd        edx,esi,1 
00401A95  shr         esi,1 
00401A97  and         esi,ecx 
00401A99  and         edx,eax 
00401A9B  mov         eax,edx 
00401A9D  mov         ecx,esi 
00401A9F  shrd        eax,ecx,2 
00401AA3  shr         ecx,2 
00401AA6  and         eax,edx 
00401AA8  and         ecx,esi 
00401AAA  or          eax,ecx 
00401AAC  jne         `anonymous namespace'::haswon+2Fh (401A3Fh) 
00401AAE  pop         edi  
00401AAF  pop         esi  
00401AB0  xor         al,al 
00401AB2  pop         ebx  
00401AB3  ret    
Run Code Online (Sandbox Code Playgroud)

Ben*_*son 17

这个版本背后的想法是避免严格的测试顺序(中间返回强制编译器按顺序逐个评估条件)以及与多个if语句关联的分支:

// return whether newboard includes a win
bool haswon2(uint64_t newboard)
{
    uint64_t y = newboard & (newboard >> 6);
    uint64_t z = newboard & (newboard >> 7);
    uint64_t w = newboard & (newboard >> 8);
    uint64_t x = newboard & (newboard >> 1);
    return (y & (y >> 2 * 6)) | // check \ diagonal
           (z & (z >> 2 * 7)) | // check horizontal -
           (w & (w >> 2 * 8)) | // check / diagonal
           (x & (x >> 2));      // check vertical |
}
Run Code Online (Sandbox Code Playgroud)

通过适当的优化级别,您可以将w,x,y和z视为移位值的"别名".这意味着最终的return语句会将整个操作抛入一个大汤中供编译器使用.在我的系统上,此版本仅占原始运行时的65%(包括每次生成随机位置的开销).如果董事会主要是非赢家,它可能会赢得更大的比例.

查看每个(从gcc -O3)原始版本的反汇编实际上更短,因此在紧密内循环中缺少分支可能真的有帮助.