This is an archive of the discontinued LLVM Phabricator instance.

[clang codegen] Assume arguments of __atomic_* are aligned.
AbandonedPublic

Authored by efriedma on Apr 12 2022, 4:07 PM.

Details

Summary

This seems weird, but it's necessary to match gcc, and avoid unnecessary calls to libatomic from libstdc++ <atomic>.

Fixes https://github.com/llvm/llvm-project/issues/54790 .

Diff Detail

Event Timeline

efriedma created this revision.Apr 12 2022, 4:07 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 12 2022, 4:07 PM
Herald added a subscriber: StephenFan. · View Herald Transcript
efriedma requested review of this revision.Apr 12 2022, 4:07 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 12 2022, 4:07 PM

I disagree with this on principle -- IMO, it is basically a historical bug in GCC that it ignores the type alignment, and we should NOT try to match that -- it's dangerous.

We ought to resolve the bug via other fixes:

  • As a workaround: add alignas(uint64_t) to the affected struct in lld. (is GHashCell the only one?)
  • Fix __builtin_addressof in Clang to propagate alignment in the same way & does (they ought to act equivalently; I think a new stanza in CodeGenFunction::EmitPointerWithAlignment will fix that).
  • Ask GCC to modify libstdc++ so that __builtin_addressof is called directly, instead of going through std::__addressof.

In addition to not liking the intended change, I think this implementation is wrong -- and will be treacherous to attempt to fix -- because I'm pretty sure GCC's implementation doesn't assume particular alignments in general; if it decides it _cannot_ emit inline atomics (based on the size and target's configuration), then no extra alignment is assumed. (And note that Clang's idea of MaxPromoteWidth is unrelated to which sizes of atomics GCC inlines.)

Kobzol added a subscriber: Kobzol.Apr 13 2022, 2:11 AM

I disagree with this on principle -- IMO, it is basically a historical bug in GCC that it ignores the type alignment, and we should NOT try to match that -- it's dangerous.

gcc has always behaved this way, and I don't see any indication they intend to change it. I mean, you can call it a bug, but at the end of the day the bug reports will land in our bugtracker, not gcc's.

As a workaround: add alignas(uint64_t) to the affected struct in lld. (is GHashCell the only one?)

I think that's the only one, at least according to git grep std::atomic; I guess that works. (Assuming you meant alignas(sizeof(uint64_t)).)

Ask GCC to modify libstdc++ so that __builtin_addressof is called directly, instead of going through std::__addressof.

Even if gcc did this today, it would take years to reach people on Linux.

I guess this is motivation to implement namespaced builtins...?

IMO, it is basically a historical bug in GCC that it ignores the type alignment

Do you have any comments related to this issue by gcc devs that this is a "known" bug?

cc @jakubjelinek @msebor @jwakely

The GCC documentation really ought to specify what alignment assumptions these functions make, if any. But they control the specification here, so if they're making alignment assumptions, then I agree we probably ought to make the same assumptions.

Have we verified that this is the rule that GCC uses? Is it true even if e.g. the pointer expression is the address of a variable with a known alignment, or if the pointer has an explicitly-aligned type (e.g. with an aligned typedef)?

Have we verified that this is the rule that GCC uses? Is it true even if e.g. the pointer expression is the address of a variable with a known alignment, or if the pointer has an explicitly-aligned type (e.g. with an aligned typedef)?

As far as I can tell, if the type's size is a power of two, and there's an inline atomic sequence available, gcc will use an inline sequence that assumes the address is naturally aligned. Otherwise, it makes the libcall. I've tried a variety of ways of writing the operation; alignment doesn't matter at all, no matter what the alignment actually is.

Oddly, __atomic_is_lock_free/__atomic_always_lock_free do care about the alignment, though.

I disagree with this on principle -- IMO, it is basically a historical bug in GCC that it ignores the type alignment, and we should NOT try to match that -- it's dangerous.

gcc has always behaved this way, and I don't see any indication they intend to change it. I mean, you can call it a bug, but at the end of the day the bug reports will land in our bugtracker, not gcc's.

Have we had many other such bug reports?

On the other hand, I have seen many cases where people wrote code using the __atomic_* APIs, and pass arguments which are underaligned on some platforms (though not the one the code was developed on). Having it be silently non-atomic (which is what typically happens with misaligned atomic instructions) is just...really nasty.

Ask GCC to modify libstdc++ so that __builtin_addressof is called directly, instead of going through std::__addressof.

Even if gcc did this today, it would take years to reach people on Linux.

True, but the behavior in the meantime is correct. And given the apparent lack of widespread issues, I'm not sure it much matters.

rsmith added a subscriber: rsmith.Apr 15 2022, 1:56 PM

Do you have any comments related to this issue by gcc devs that this is a "known" bug?

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87237#c1, from someone in the GCC MAINTAINERS file, suggests that this is either a GCC bug or a GCC documentation bug.

efriedma abandoned this revision.Apr 18 2022, 10:02 AM

Opened https://github.com/llvm/llvm-project/issues/54963 to more specifically track the clang issue.

With b27430f, it should be easy enough to special-case calls to std::__addressof in CodeGenFunction::EmitPointerWithAlignment, so we can just do that, I guess.