c++ - 结构和包含相同字节的原始变量哪个更快?

标签 c++ assembly optimization low-level

下面是一段代码示例:

#include <stdint.h> 
#include <iostream>

typedef struct {
    uint16_t low;
    uint16_t high;
} __attribute__((packed)) A;

typedef uint32_t B;

int main() {
    //simply to make the answer unknowable at compile time
    uint16_t input;
    cin >> input;
    A a = {15,input};
    B b = 0x000f0000 + input;
    //a equals b
    int resultA = a.low-a.high;
    int resultB = b&0xffff - (b>>16)&0xffff;
    //use the variables so the optimiser doesn't get rid of everything
    return resultA+resultB;
}

resultA 和 resultB 计算完全相同的东西 - 但哪个更快(假设您在编译时不知道答案)。

我尝试使用 Compiler Explorer 来查看输出,我得到了一些东西 - 但无论我尝试什么,任何优化都比我聪明并优化了整个计算(起初,它优化了所有东西,因为它没有被使用) - 我尝试使用 cin 使答案在运行时不可知,但后来我什至无法弄清楚它是如何得到答案的(我认为它仍然设法在编译时弄清楚?)

这是没有优化标志的 Compiler Explorer 的输出:

        push    rbp
        mov     rbp, rsp
        sub     rsp, 32
        mov     dword ptr [rbp - 4], 0
        movabs  rdi, offset std::cin
        lea     rsi, [rbp - 6]
        call    std::basic_istream<char, std::char_traits<char> >::operator>>(unsigned short&)
        mov     word ptr [rbp - 16], 15
        mov     ax, word ptr [rbp - 6]
        mov     word ptr [rbp - 14], ax
        movzx   eax, word ptr [rbp - 6]
        add     eax, 983040
        mov     dword ptr [rbp - 20], eax
Begin calculating result A
        movzx   eax, word ptr [rbp - 16]
        movzx   ecx, word ptr [rbp - 14]
        sub     eax, ecx
        mov     dword ptr [rbp - 24], eax
End of calculation
Begin calculating result B
        mov     eax, dword ptr [rbp - 20]
        mov     edx, dword ptr [rbp - 20]
        shr     edx, 16
        mov     ecx, 65535
        sub     ecx, edx
        and     eax, ecx
        and     eax, 65535
        mov     dword ptr [rbp - 28], eax
End of calculation
        mov     eax, dword ptr [rbp - 24]
        add     eax, dword ptr [rbp - 28]
        add     rsp, 32
        pop     rbp
        ret

我也会发布 -O1 输出,但我无法理解它(我对低级汇编的东西很陌生)。

main:                                   # @main
        push    rax
        lea     rsi, [rsp + 6]
        mov     edi, offset std::cin
        call    std::basic_istream<char, std::char_traits<char> >::operator>>(unsigned short&)
        movzx   ecx, word ptr [rsp + 6]
        mov     eax, ecx
        and     eax, -16
        sub     eax, ecx
        add     eax, 15
        pop     rcx
        ret

需要考虑的事情。虽然对整数进行操作稍微困难一些,但与结构相比,简单地将其作为整数访问更容易(我认为你必须用位移位转换?)。这有什么不同吗?

这最初是在内存上下文中出现的,我看到有人将内存地址映射到具有低位和高位字段的结构。我认为这不可能比简单地使用正确大小的整数并在需要低位或高位时进行位移更快。在这种特定情况下 - 哪个更快?

[为什么我把C加到标签列表里了?虽然我使用的示例代码是在 C++ 中,但结构与变量的概念也非常适用于 C]

最佳答案

除了某些 ABI 要求以不同于整数的方式传递结构这一事实之外,不会有任何区别。

现在,两个 16 位整数和一个 32 位整数之间存在重要的语义差异。如果你添加到低 16 位 int,它不会“溢出”到高位,而如果你添加到 32 位 int 的低 16 位,它会。这种可能行为的差异(即使您自己“知道”它不会在您的代码中发生)可能会改变您的编译器生成的汇编代码,并影响性能。

如果没有实际测试或对实际确切问题的完整描述,将无法知道这两者中哪一个会导致更快的结果。所以这是一个折腾。

这意味着唯一真正关心的是 ABI。这意味着,如果不对整个程序进行优化,采用 struct 的函数和采用具有相同二进制布局的 int 的函数将对数据位置有不同的假设。

但这只对按值的单个参数有影响。

90/10 规则适用; 90% 的代码运行时间少于 10%。这很可能不会对您的关键路径产生影响。

关于c++ - 结构和包含相同字节的原始变量哪个更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75097238/

相关文章:

c++ - 我们如何在函数声明中使用函数参数?

c++ - 避免由 C++ 包含 header 引起的循环引用

c++ - 激活填料和盐

java - 这些陈述之一有好处吗

c++ - 如何更改 QT 中信号和插槽的时序?

c++ - 尝试在 cpp 模块中使用汇编代码时出现链接器错误

组装作业

c - 组装时如何返回?

optimization - Haskell:列表/向量/数组性能调优

mysql 查询优化