[C11-atomic] [patch] gimple atomic statements

Andrew MacLeod amacleod@redhat.com
Thu Apr 26 18:51:00 GMT 2012


On 04/05/2012 05:14 AM, Richard Guenther wrote:
>
> Ok.  Remember that you should use non-tree things if you can in GIMPLE
> land.  This probably means that both the size and the memmodel "operands"
> should be
>
> + struct GTY(()) gimple_statement_atomic
> + {
> +   /* [ WORD 1-8 ]  */
> +   struct gimple_statement_with_memory_ops_base membase;
> +
> +   /* [ WORD 9 ] */
> +   enum gimple_atomic_kind kind;
> +
>       enum gimple_atomic_memmodel memmodel;
>
>       unsigned size;
>
> and not be trees in the ops array.  Even more, both kind and memmodel
> should probably go in membase.base.subcode

I'm using subcode now for for the fetch_op and op_fetch operation when 
we actually need a tree code for plus, sub, and, etc...  so I am 
utilizing that field. Since the 'kind' field is present in ALL node, and 
the tree code was only needed in some, it looked cleaner to utilize the 
subcode field for the 'sometimes' field so that it wouldnt be an obvious 
wasted field in all the non-fetch nodes.  In the end it amounts to the 
same thing, but just looked cleaner :-)   I could change if it you felt 
strongly about it and use subcode for the kind and create a tree_code 
field in the object for the operation.

Since integral atomics are always of an unsigned type ,  I could switch 
over and use 'unsigned size' instead of 'tree fntype' for them (I will 
rename it), but then things may  be more complicated when dealing with 
generic atomics...  those can be structure or array types and I was 
planning to allow leaving the type in case I discover something useful I 
can do with it.  It may ultimately turn out that the real type isn't 
going to matter, in which case I will remove it and replace it with an 
unsigned int for size.

And the reason memmodel is a tree is because, as ridiculous as it seems, 
it can ultimately be a runtime value.    Even barring that, it shows up 
as a variable after inlining before various propagation engines run, 
especially in the  C++ templates.  So it must be a tree.

>> I was actually thinking about doing it during gimplification... I hadnt
>> gotten as far as figuring out what to do with the functions from the front
>> end yet.  I dont know that code well, but I was in fact hoping there was a
>> way to 'recognize' the function names easily and avoid built in functions
>> completely...
> Heh ... you'd still need a GENERIC representation then.  Possibly
> a ATOMIC_OP tree may do.
possibly...   or maybe a single generic atomic_builtin with a kind and a 
variable list of  parameters.

> well, the names must remain exposed and recognizable since they are 'out
> there'.  Maybe under the covers I can just leave them as normal calls and
> then during gimplification simply recognize the names and generate
> GIMPLE_ATOMIC statements directly from the CALL_EXPR.  That would be ideal.
>   That way there are no builtins any more.
> I suppose my question was whether the frontends need to do sth about the
> __atomic keyword or if that is simply translated to some type flag - or
> is that keyword applying to operations, not to objects or types?
>
The _Atomic keyword is a type modifier like const or volatile.  So 
during gimplification I'll also look for all occurrences of variables in 
normal expressions which have that bit set in the type,  then translate 
the expression to utilize the new gimple atomic node.  so

_Atomic int var = 0;
  var += 4;
  foo (var);

would become

  __atomic_add_fetch (&var, 4, SEQ_CST);
  D.123 = __atomic_load (&var, SEQ_CST);
foo (D.123);




>>
>>>> So bottom line, a GIMPLE_ATOMIC statement is just an object that is much
>>>> easier to work with.
>>> Yes, I see that it is easier to work with for you.  All other statements
>>> will
>>> see GIMPLE_ATOMICs as blockers for their work though, even if they
>>> already deal with calls just fine - that's why I most of the time suggest
>>> to use builtins (or internal fns) to do things (I bet you forgot to update
>>> enough predicates ...).  Can GIMPLE_ATOMICs throw with
>>> -fnon-call-exceptions?
>>> I suppose yes.  One thing you missed at least ;)
>>
>> Not that I am aware of, they are 'noexcept'.  But I'm sure I've missed more
>> than a few things so far.  Im pretty early in the process :-)
> What about compare-exchange on a pointer dereference? The pointer
> dereference surely can trap, so it can throw with -fnon-call-exceptions.  No?
in theory *any* gimple atomic operation could end up being expanded as a 
library call, so I will have to ensure they are treated as calls because 
of things like that.

These are all things I will focus on once all the basic functionality is 
there.  This patch is not meant to be fully flushed out, I just wanted 
some eyes on it before I checked it into the branch so i dont carry this 
huge patch set around when making changes.  When I get things functional 
in the branch  I'll revisit all this and any of the other implementation 
comments I don't get to and then submit another patch for review.
>
> + /* Return the expression field of atomic operation GS.  */
> +
> + static inline tree
> + gimple_atomic_expr (const_gimple gs)
> + {
> +   GIMPLE_CHECK (gs, GIMPLE_ATOMIC);
> +   gcc_assert (gimple_atomic_has_expr (gs));
> +   return gimple_op (gs, 2);
> + }
>
> err - what's "expression" in this context?  I hope it's not an arbitrary
> tcc_expression tree?!

Its just the 'expression' parameter of atomic operations which have it, 
like  store , fetch_add, or exchange. It would normally be an SSA_NAME 
or const.  I suppose we coud call it 'value' or something if expression 
is confusing.


>
> + /* Return the arithmetic operation tree code for atomic operation GS.  */
> +
> + static inline enum tree_code
> + gimple_atomic_op_code (const_gimple gs)
> + {
> +   GIMPLE_CHECK (gs, GIMPLE_ATOMIC);
> +   gcc_assert (gimple_atomic_kind (gs) == GIMPLE_ATOMIC_FETCH_OP ||
> +             gimple_atomic_kind (gs) == GIMPLE_ATOMIC_OP_FETCH);
> +   return (enum tree_code) gs->gsbase.subcode;
> + }
>
> now, what was it with this "expression" thing again?  Btw, ||s go to the
> next line.  subcode should be the atomic kind - it seems that you glob
> too much into GIMPLE_ATOMIC and that you maybe should sub-class
> GIMPLE_ATOMIC properly via the subcode field.  You'd have an
> gimple_atomic_base which fences could use for example.

I was trying to make it simple and utilize the variable length ops array 
to handle the variable stuff :-) It took many attempts to arrive at this 
layout.

They don't really break down well into sub-components.  I wanted to use 
a single routine to access a given field for all atomic kinds, so 
gimple_atomic_target(),  gimple_atomic_lhs(), and gimple_atomic_expr() 
just work .  The problem is that they don't break down into a tree 
structure, but more of a multiple-inheritance type thing.

LOAD has a LHS and a TARGET, no EXPR
STORE has no LHS, but has a TARGET and EXPR
EXCHANGE has a LHS, a TARGET and an EXPR
FENCE has no target or anything else.
COMPARE_EXCHANGE has 2 LHS, a TARGET, and an EXPR, not to mention an 
additional memorder

I set it up so that the variable length array always stores a given 
parameter at the same offset, and also allows for contiguous trees in 
the array to represent all the LHS or RHS parameters for easy generic 
operand scanning or whatever.  And each statement type only allocated 
the right amount of memory required.

I planned to add a comment to the description showing the layout of the 
various nodes:
/*
   LOAD         | ORDER | TARGET | LHS  |
    STORE        | ORDER | TARGET | EXPR |
    EXCHANGE     | ORDER | TARGET | EXPR | LHS      |
    COMPARE_EXCHG| ORDER | TARGET | EXPR | EXPECTED | FAIL_ORDER | LHS2 
| LHS1 |
    FETCH        | ORDER | TARGET | EXPR | LHS      |
    TEST_AND_SET | ORDER | TARGET | LHS  |
    CLEAR        | ORDER | TARGET |
    FENCE        | ORDER |


This allows all the RHS values to be contiguous for bulk processing like 
operands, and located at the same index for an easy access routine.  The 
LHS is viewed from right to left, and allows more than 1 value  as 
required by compare_exchange.  They also are contiguous for generic 
access, and a single LHS routine can also be used to access those values.
*/

Is that OK?     it seemed better than trying to map it to some sort of 
hierarchical structure it doesn't really fit into.

Andrew





More information about the Gcc-patches mailing list