Do GCC和Clang优化逐场结构副本
Do GCC and Clang optimize field-by-field struct copy?
例如。给定
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
替换(尤其是如果结构有更多字段)。
两个版本都会产生同等代码吗?
如果我们复制到的结构比
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:这样的技巧允许看到优化,但禁止编译器在"战斗"代码中省略结果。取这个。
相关文章:
- 如何循环打印顶点结构
- 通过方法访问结构
- 使用不带参数的函数访问结构元素
- 预处理器:插入结构名称中的前一个行号
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么添加析构函数(甚至是空的)会破坏我的结构,该结构使用 ref 转发和折叠来保存 ref 或值的副本?
- 为什么基于范围的 for 循环中的结构化绑定只是一个副本而不是引用?
- 如何让指针的深层副本将内部结构发送到内核?
- 标准库容器结构是否存储副本或引用?
- Do GCC和Clang优化逐场结构副本
- 结构C 的深副本
- 创建 AVPacket 结构的副本
- 结构中的 CUDA 设备功能指针,没有静态指针或符号副本
- 为什么要根据副本修改源结构
- 构造函数初始化列表中的 C 结构副本C++
- 删除结构的成员,并将其重新制作为其他内容的副本,而不使用 new
- 在使用auto时初始化结构会导致VS 2013中的副本
- 创建自定义" string "(结构)副本
- 如何在不使用副本的情况下更改QJson层次结构中的QJsonObject值
- 面试编码-将指向节点结构的指针作为参数,并返回传入数据结构的完整副本