On Thu, Jul 27, 2023 at 07:06:03PM +0000, Joseph Myers wrote: > I think there should be tests for _Atomic _BitInt types. Hopefully atomic > compound assignment just works via the logic for compare-and-exchange > loops, but does e.g. atomic_fetch_add work with _Atomic _BitInt types?
So, there are 2 issues. One is something I haven't seen being handled for C at all so far, but handled for C++ - padding bits. Already e.g. x86 long double has some padding bits - 16 bits on ia32, 48 bits on x86_64, when one does _Atomic long double l; ... l += 2.0; it will sometimes work and sometimes hang forever. Similarly atomic_compare_exchange with structs which contain padding (unions with padding bits are lost case, there is nothing that can be reliably done for that, because we don't know at runtime what is the active union member if any). And _BitInt if it doesn't use all bits in all containing limbs has padding as well (and psABI doesn't say it is sign or zero extended). The C++ way of dealing with this is using __builtin_clear_padding, done on atomic stores/updates of the atomic memory (padding is cleared if any on the value to be stored, or on the expected and desired values). I don't know enough about the C atomic requirements whether that is feasible for it as well, or whether it is possible to make the padding bits partially or fully set somehow non-atomically without invoking UB and then make it never match. If one ignores this or deals with it, then _Atomic _BitInt(15) a; _Atomic(_BitInt(15)) b; _Atomic _BitInt(115) c; _Atomic _BitInt(192) d; _Atomic _BitInt(575) e; _BitInt(575) f; int main () { a += 1wb; b -= 2wb; c += 3wb; d += 4wb; e -= 5wb; // f = __atomic_fetch_add (&e, 54342985743985743985743895743834298574985734895743895734895wb, __ATOMIC_SEQ_CST); } compiles fine with the patch set. And another issue is that while __atomic_load, __atomic_store, __atomic_exchange and __atomic_compare_exchange work on arbitrary _BitInt sizes, others like __atomic_fetch_add only support _BitInt or other integral types which have size of 1, 2, 4, 8 or 16 bytes, others emit an error in c-family/c-common.cc (sync_resolve_size). So, either resolve_overloaded_builtin should for the case when pointer is pointer to _BitInt which doesn't have 1, 2, 4, 8 or 16 bytes size lower those into a loop using __atomic_compare_exchange (or perhaps also if there is padding), or <stdatomic.h> should do that. Thoughts on that? Jakub