【问题标题】:How to get llvm to use the 'OR' instruction for speedup如何让 llvm 使用“或”指令进行加速
【发布时间】:2021-08-04 22:10:01
【问题描述】:

我有一些 C 代码基本上可以归结为:

    *p_Bool3 = *p_Bool1 || *p_Bool2;

其中 p_Bool1、p_Bool2 和 p_Bool3 为“bool *”。

clang++ 给了我这个使用 O2 的 X86 程序集(O3 没有区别,我只是使用 O2,因为那是实际项目中使用的):

mov eax, dword ptr [esp + 12]
    mov edx, dword ptr [esp + 4]
    mov cl, 1
    cmp byte ptr [edx], 0
    je  LBB1_1
    mov byte ptr [eax], cl
    ret
LBB1_1: 
    mov ecx, dword ptr [esp + 8]
    mov cl, byte ptr [ecx]
    mov byte ptr [eax], cl
    ret

实际的程序稍微复杂一些,包含一堆 ob get 和 set 函数以及一些重载的运算符,但它基本上是使用 O2 的相同汇编代码:

001de515  mov         al, 0x01 
001de517  mov         ecx, dword ptr ds:[edi+0x00000628] 
001de51d  cmp         byte ptr ds:[ecx], 0x00000000 
001de520  jne         0x001DE52E 
001de522  mov         eax, dword ptr ds:[edi+0x0000065C] 
001de528  cmp         byte ptr ds:[eax], 0x00000000 
001de52b  setne       al 
001de52e  mov         ecx, dword ptr ds:[edi+0x000005EC] 
001de534  mov         byte ptr ds:[ecx], al 

现在我有一些参考代码在相同的硬件/系统上运行速度提高了 75%,如下所示:

0100121e  lea         ebx, dword ptr ds:[esi+0x10280005] 
01001224  mov         al, byte ptr ds:[ebx] 
01001226  lea         ebx, dword ptr ds:[esi+0x10280006] 
0100122c  or          al, byte ptr ds:[ebx] 
0100122e  lea         ebx, dword ptr ds:[esi+0x10280004] 
01001234  mov         byte ptr ds:[ebx], al 

如何让 clang 只使用“或”指令并更快?

【问题讨论】:

    标签: assembly optimization x86 llvm


    【解决方案1】:

    您是否尝试过使用*p_Bool3 = *p_Bool1 | *p_Bool2 中的 OR 运算符?编译器无法自行生成它,因为如果 p_Bool1 为真,则不允许取消引用 p_Bool2

    如果你不能在这里使用| 运算符,它也应该首先手动取消引用指针,告诉编译器允许这样做:

    bool tmp1 = *p_Bool1, tmp2 = *p_Bool2;
    
    *p_Bool3 = tmp1 || tmp2;
    

    【讨论】:

    • 是否需要同时设置tmp1tmp2*p_Bool3 = *p_Bool1 || tmp2 会起作用,还是会像@Jérôme Richard 所描述的那样有副作用的风险?
    • 哇,我不敢相信我还没有尝试过'|'运算符,我实际上认为,我应该使用 '||'布尔运算符,因此它可以更快。我确实更喜欢您的第二个建议,因为我使用的是“正确”运算符并且仍然可以快速获得结果。局部变量被优化器完全删除。
    • @sj95126 否 tmp1 当然可以,但无论如何使用 | 运算符可能是更好的解决方案。它不仅摆脱了跳转,还可能避免额外的指令来规范化结果。
    • @sj95126:请参阅Boolean values as 8 bit in compilers. Are operations on them inefficient? - 编译器并不总是充分利用 ABI 保证 bool 是整数 0 或 1,并且有时会浪费指令重新布尔化。
    【解决方案2】:

    || 运算符使用的左/右表达式被惰性评估。由于间接可能会导致副作用(例如页面错误、硬件影响),因此编译器需要使用条件来防止副作用在不应发生时发生。

    为避免此问题,您可以使用| 运算符。 Here 就是一个例子。

    【讨论】:

      猜你喜欢
      • 2018-08-31
      • 1970-01-01
      • 1970-01-01
      • 2012-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多