Using BUILT_IN_ATOMIC_...
Andrew MacLeod
amacleod@redhat.com
Wed Jul 9 12:40:00 GMT 2014
On 07/09/2014 02:17 AM, Tobias Burnus wrote:
> Hello all,
>
> I am trying to use BUILT_IN_ATOMIC_..., but it does not quite work. I
> am calling them as:
>
> tmp = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD_4);
> tmp = build_call_expr_loc (input_location, tmp, 2, atom.expr, ...
>
> That gives the following dump:
>
> __atomic_store_n (&i, 5, 0);
> __atomic_store_n (&i, (integer(kind=4)) *k, 0);
> j = (integer(kind=4)) __atomic_load_4 (&i, 0);
> __atomic_add_fetch (&i, 5, 0);
>
>
> The "__atomic_load_4" works, but the "__atomic_store_n" and
> "__atomic_add_fetch" lead to link-time errors:
>
> fo4o.f90:(.text+0x44): undefined reference to `__atomic_store_n'
> fo4o.f90:(.text+0x73): undefined reference to `__atomic_add_fetch'
>
>
> The issue with `__atomic_store_n', I can solve by replacing it by,
> e.g., BUILT_IN_ATOMIC_STORE_4. However, how does one properly use
> __atomic_add_fetch alias BUILT_IN_ATOMIC_ADD_FETCH_N, given that there
> is no _4 version of it?
>
A lot of the specialized processing is handled by the parser. I tried
to move this to the middle end once upon a time, and the various
frustrations leaded me to the frontend/middle end separation project.
so, all the _N variations do not exist as actual functions that can be
called. They are shorthand for the parser to determine the size of the
object at compile time and call the appropriate _1, _2, _4, _8 or _16
routine. From the middle end, you ought to be able to call the correct
one directly since you should know the size of the object.
Since the front end "handles" the resolving of type size for _N
variations of the functions, the middle end uses those symbols to
represent the generic versions of the function. The generic versions
are the ones which simply take a buffer and a size, and operate on an
arbitrary number bytes (ie a 32 byte structure for instance). These
are usually implemented in libatomic via locks.
There are _{1,2,4,8,16} variations of BUILT_IN_ATOMIC_ADD_FETCH...
There is no *generic* version tho which is what you get when you try
calling the function without any _N variation. Performing an integral
operation on non-integral sizes makes no sense and is not supported in
the middle end.
So you need to explicitly set your BUILT_IN size decl. The parser
(From c-family/c-common.c::resolve_overloaded_builtin) figures that out
via something like:
fncode = (enum built_in_function)((int)BUILT_IN_ATOMIC_ADD_FETCH_N +
exact_log2 (n) + 1);
new_function = builtin_decl_explicit (fncode);
Probably ought to be a small function to do this :-P
>
> Additionally, if one wants to fetch the old value (e.g. with
> __atomic_add_fetch), how does one properly use the function result?
> The problem is that TREE_TYPE() doesn't automatically match the type
> of the first argument. Ignoring the type issue in the front end and
> simply calling MODIFY_EXPR will lead to a gimplify.c ICE.
The types of the builtin functions are explicitly unsigned integral
types, you probably need to convert the result to the type you want.
the arguments are also expected to be unsigned (The front end converts
them), except for the first one which needs to be a pointer to the
unsigned type. I expect you can get away without the parameter types
being exact as long as they are all the right size... sinc all the
checking is in the front end :-)
Hope that helps.
Andrew
More information about the Gcc
mailing list