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