[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Tinycc-devel] [PATCH] stdatomic: ld/st/xchg/cmpxchg on simple types

From: Michael Matz
Subject: Re: [Tinycc-devel] [PATCH] stdatomic: ld/st/xchg/cmpxchg on simple types
Date: Thu, 25 Mar 2021 20:33:58 +0100 (CET)
User-agent: Alpine 2.21 (LSU 202 2017-01-01)


On Mon, 22 Mar 2021, Dmitry Selyutin wrote:

      "is it really the same type?"

A bit ambiguous wording. What I mean is that, for a naturally-aligned type
N, the corresponding call can be generated to routine __atomic_X_N. The code
generator doesn't need to care whether types in the _implementation_ of
__atomic_X_N must literally match those passed; if the semantics match, this
is enough. And, indeed, the code below...

    #include <stdatomic.h>
    #include <stdint.h>

    struct combo {
        uint16_t lo;
        uint16_t hi;

    struct combo xchg(_Atomic(struct combo) *atom, struct combo value)
        return atomic_exchange(atom, value);

...causes the compiler to generate the same code as if it operated on
gcc and clang for x86 inline this code, and this is explicitly allowed by
the documentation, with some additional remarks.
It appears to me that the documentation speaks of code generation. We could
have emitted a call, and this also would have been OK.

I think at this point we have managed to talk past each other. You do seem to agree that the size specific __atomic_X_N "functions" are an implementation detail, and hence how and if they are implemented in TCC doesn't matter (much). In the broader sense you agree that how exactly the secret sauce of atomics is implemented doesn't matter.

So, what's left to decide is how to deal with generic functions, here the <stdatomic.h> ones that can accept and return rvalues of arbitrary (including struct) type, ideally in a way that doesn't add much code to TCC.

grischka proposed a compact way involving no compiler changes at all, and I basically tried to find out why you didn't want to go that route, given that this would be an implementation detail.

(FWIW, in the full glory the generic implementation of e.g. atomic_load would need statement expressions, a special typeof and a temporary:

#define atomic_load(p) ({T(*p) r; __atomic_load_impl(p, &r, sizeof(r)); r; })

where T(*p) is basically __typeof__(*p) but removes _Atomic, that could be another extension, or further games with _Generic. )

Now, given that the above hackery would enable the features without any TCC compiler help it's reasonable to ask what kind of compiler changes are required to make the hackery a bit nicer, without having to implement everything in it.

Maybe it also turns out that your current approach is in fact the nicest one (it certainly generates better code than the above). But there's certainly duplication between parse_atomic and the function call parser. So maybe another way that could be rectified is by adding an extension to TCC that would allow to declare the generic functions directly, ala:

  _Generic atomic_load(const volatile _Atomic _Generic *p);

with the following semantic: _Generic is a valid (unqualified?) base type, and when used in function decls there must be at least one argument with it, and all mentions need to refer to the same type at calls. This would also allow to implement the type generic math functions nicely (<tgmath.h>). (I'm using the same keyword as for the generic selection, possibly that's a bad idea :) ). You would also have to extend the function call parser somewhat (and of course the type parser and matcher), but it would be a general change that wouldn't need amendements in the compiler whenever a new generic function is added to some new standard. That still leaves the question how to make the connection between this decl and which functions are ultimately called (and how), and maybe that deserves hardcoding in the compiler for now to be done in the same way as the above macro hackery would do by hand. Not really thought through completely, but merely meant as idea trigger.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]