llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
27.96k stars 11.54k forks source link

Confusing misaligned atomic operation warning #46291

Open tschuett opened 4 years ago

tschuett commented 4 years ago
Bugzilla Link 46947
Version trunk
OS All
CC @zygoloid

Extended Description

For the following code, I get an error: repro.cpp:13:3: warning: misaligned atomic operation may incur significant performance penalty [-Watomic-alignment] __atomic_load(&foo->bar, &dummy, __ATOMIC_RELAXED);

clang believes that the pointer is 8 byte aligned, but foo->bar is actually 16 byte aligned.

include

struct Foo { struct Bar { uint64_t a; uint64_t b; }; Bar bar; };

void braz(Foo *foo) { Foo::Bar dummy; __atomic_load(&foo->bar, &dummy, __ATOMIC_RELAXED); }

ec04fc15-fa35-46f2-80e1-5d271f2ef708 commented 4 years ago

Listing the alignment and access size (== expected alignment) in the warning seems like a good idea.

tschuett commented 4 years ago

Maybe extend the warning: The pointer is 8 byte aligned, while the value requires an alignment of 16 bytes.

tschuett commented 4 years ago

I read through the source code and finally found the ASTRecordLayout. Then I realized that it is aligned on Foo::Bar::a, which is only 8 bytes. The 16 bytes is my misunderstanding.

But the error makes it hard to find the root cause. The root cause is not even visible in the expression: __atomic_load(&foo->bar, &dummy, __ATOMIC_RELAXED); It is foo->bar.a.

ec04fc15-fa35-46f2-80e1-5d271f2ef708 commented 4 years ago

clang believes that the pointer is 8 byte aligned, but foo->bar is actually 16 byte aligned.

Why do you believe that to be the case?

tschuett commented 4 years ago

"misaligned atomic operation may incur significant performance penalty" This sentence is always true, but it is not actionable. It does not help me to solve the problem.

tschuett commented 4 years ago

I am starting to understand the problem. Foo is aligned on Foo::Bar::a. Thus the alignment of Foo is 8 bytes. Foo * is not aligned on Foo::Bar. But the error message is still confusing as it took me a while to find out what is misaligned.

The following solves my problem.

struct Foo { struct alignas (16) Bar { uint64_t a; uint64_t b; }; Bar bar; };

tschuett commented 4 years ago

Even void braz(Foo foo) { Foo::Bar dummy; __atomic_load((Foo::Bar )foo, &dummy, __ATOMIC_RELAXED); }

gives warnings.

tschuett commented 4 years ago

I added printf statements to CGAtomic.cpp and the inferred alignment is 8 bytes and sizeChars is 16 byte.