Do GCC和Clang优化逐场结构副本

Do GCC and Clang optimize field-by-field struct copy?

本文关键字:结构 副本 优化 GCC Clang Do      更新时间:2023-10-16

例如。给定

typedef struct A {
    int a;
    int b;
    int c;
} A;
typedef struct B {
    int d;
    int e;
    int f;
} B;
void f(B& b1, A& a2) {
    b1.d = a2.a;
    b1.e = a2.b;
    b1.f = a2.c;
}

f可以用memcpy替换(尤其是如果结构有更多字段)。

  1. 两个版本都会产生同等代码吗?

  2. 如果我们复制到的结构比A少的字段怎么办?即。

    typedef struct C {
        int g;
        int h;
    } C;
    void h(C& c1, A& a2) {
        c1.g = a2.a;
        c1.h = a2.b;
    }
    

我很感兴趣,因为我正在生成包括这样的结构副本的代码,通常会更改字段的顺序,我想知道是否应该特别治疗这些情况。

c标签包括,因为我期望C中的行为是相同的(Modulo Pointers而不是引用)。

根据godbolt.org,x86-64 gcc 6.2 with -o2产生

mov eax, DWORD PTR [rsi]
mov DWORD PTR [rdi], eax
mov eax, DWORD PTR [rsi+4]
mov DWORD PTR [rdi+4], eax
mov eax, DWORD PTR [rsi+8]
mov DWORD PTR [rdi+8], eax

对于逐场复制,

mov rax, QWORD PTR [rsi]
mov QWORD PTR [rdi], rax
mov eax, DWORD PTR [rsi+8]
mov DWORD PTR [rdi+8], eax

memcpy。Clang和ICC都有类似的差异。有点令人失望。

您的测试柜不会加载并存储足够的内存以进行转换至memcpy值得。使用两倍的成员:

typedef struct A { int a, b, c, p, q, r; } A;
typedef struct B { int d, e, f, s, t, u; } B;
void f(B& b1, A& a2) {
  b1.d = a2.a;
  b1.e = a2.b;
  b1.f = a2.c;
  b1.s = a2.p;
  b1.t = a2.q;
  b1.u = a2.r;
}

... LLVM优化代码:

f(B&, A&):                             # @f(B&, A&)
        movups  (%rsi), %xmm0
        movups  %xmm0, (%rdi)
        movl    16(%rsi), %eax
        movl    %eax, 16(%rdi)
        movl    20(%rsi), %eax
        movl    %eax, 20(%rdi)
        retq

...带有一个未对齐的16字节加载/存储,复制前四个成员。

一般答案:取决于。作为一个免费功能,它通常会生成与std::memmove相似的代码(使用临时变量来避免可能的重叠,请参见文档),但是在内置后可以将其折叠成std::memcpy,并具有可能的优化(例如,通过SSE)。

编辑:

您可以看到完全优化的输出,并尝试通过使用volatile变量尝试GCC.GCC.godbolt:这样的技巧允许看到优化,但禁止编译器在"战斗"代码中省略结果。取这个。