提问人:GKann 提问时间:7/5/2023 最后编辑:GKann 更新时间:7/15/2023 访问量:142
现代 C++ 编译器的内存锯齿有多糟糕?
How bad is memory aliasing with modern C++ compilers?
问:
我正在尝试了解内存混叠的影响以及如何改进我的代码以避免它。我正在重写我的缓存一致性实体组件系统,我想考虑内存别名。
我的主要来源是Christer Ericson在GDC 2003上的演讲,因此我想知道他所描述的问题是否以某种方式被现代C++编译器缓解了。
具体来说,现代 C++ 编译器是否像 Christer 所说的那样遭受内存混叠的影响,尤其是对于成员变量访问(由于隐含的“this”ptr)?
#include <stdlib.h>
class TestList
{
public:
TestList()
{
// atoi here to avoid compiler optimization around hardcoded 20
count = atoi("20");
data = new int64_t[count];
}
int64_t count;
int64_t* data;
void ClearOptimized();
void ClearNonOptimized();
};
// Not inlined on purpose
void TestList::ClearOptimized()
{
// According to Christer, this avoids aliasing even for
// simple compilers, because we are aiding the compiler
// to identify that there is no aliasing in the iteration.
for (int64_t i = 0, size = count; i < size; ++i)
{
data[i] = 0;
}
}
void TestList::ClearNonOptimized()
{
// According to Christer the compiler doesn't know
// if 'count' is aliasing with data... A smart compiler
// should be able to identify it might be aliased for
// the first element only, but all other iterations can't
// so it will unroll the first element of the loop into a
// separated range check.
for (int64_t i = 0; i < count; ++i)
{
data[i] = 0;
}
}
int main()
{
TestList listA;
listA.ClearNonOptimized();
TestList listB;
listB.ClearOptimized();
return listA.data[listA.count-1] + listB.data[listB.count-1];
}
我浏览了一些网站,这些网站表明现代编译器仍然存在大多数问题,尽管现在我们似乎有更好的工具来避免混叠(例如类型双关)。
我尝试通过使用上述代码查看编译器资源管理器来验证这一点。但是我发现很难推理汇编代码......具有最高优化标志的 GCC 和 Clang 似乎每次都在进行额外的 ptr 访问。
铛:
TestList::ClearOptimized(): # @TestList::ClearOptimized()
push rax
mov rdx, qword ptr [rdi]
test rdx, rdx
jle .LBB0_2
mov rdi, qword ptr [rdi + 8]
shl rdx, 3
xor esi, esi
call memset
.LBB0_2:
pop rax
ret
TestList::ClearNonOptimized(): # @TestList::ClearNonOptimized()
cmp qword ptr [rdi], 0
jle .LBB1_3
mov rax, qword ptr [rdi + 8]
xor ecx, ecx
.LBB1_2: # =>This Inner Loop Header: Depth=1
mov qword ptr [rax + 8*rcx], 0
add rcx, 1
cmp rcx, qword ptr [rdi] <=== Is this due to memory aliasing?
jl .LBB1_2
.LBB1_3:
ret
海湾合作委员会:
TestList::ClearOptimized():
mov rdx, QWORD PTR [rdi]
test rdx, rdx
jle .L6
mov rdi, QWORD PTR [rdi+8]
sal rdx, 3
xor esi, esi
jmp memset
.L6:
ret
TestList::ClearNonOptimized():
cmp QWORD PTR [rdi], 0
jle .L8
mov rdx, QWORD PTR [rdi+8]
xor eax, eax
.L10:
mov QWORD PTR [rdx+rax*8], 0
add rax, 1
cmp QWORD PTR [rdi], rax <=== Is this due to memory aliasing?
jg .L10
.L8:
ret
我没看错吗?这是否意味着它将获取缓存中的信息,而不是从寄存器中使用它?
答: 暂无答案
上一个:C 中整数变量的 1s 补码表示
下一个:LLVM 中的内存别名
评论
-fno-strict-aliasing
*(uint32_t*)my_float
memcpy
std::bit_cast
__attribute__((may_alias))
aligned(1)
memcpy
memcpy(p, q, sizeof(int))