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

Reply via email to