diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2011-11-10 19:45:17 +0000 |
---|---|---|
committer | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2011-11-10 19:45:17 +0000 |
commit | 033ba5bf9cbcdfb60cccbf61796b19b792de0ac9 (patch) | |
tree | 5894e158f9de464a9516a560a37795fd3caeab43 /gcc/ada/gcc-interface/utils2.c | |
parent | 8b01bdb087c5112274565d75c9db2250440ee044 (diff) | |
download | gcc-033ba5bf9cbcdfb60cccbf61796b19b792de0ac9.zip gcc-033ba5bf9cbcdfb60cccbf61796b19b792de0ac9.tar.gz gcc-033ba5bf9cbcdfb60cccbf61796b19b792de0ac9.tar.bz2 |
fe.h (Serious_Errors_Detected): New macro.
* fe.h (Serious_Errors_Detected): New macro.
* gcc-interface/gigi.h (build_atomic_load): Declare.
(build_atomic_store): Likewise.
* gcc-interface/trans.c (atomic_sync_required_p): New predicate.
(call_to_gnu): Add ATOMIC_SYNC parameter. Use local variable.
Build an atomic load for an In or In Out parameter if needed.
Build an atomic store for the assignment of an Out parameter if needed.
Build an atomic store to the target if ATOMIC_SYNC is true.
(present_in_lhs_or_actual_p): New predicate.
(gnat_to_gnu) <N_Identifier>: Build an atomic load if needed.
<N_Explicit_Dereference>: Likewise.
<N_Indexed_Component>: Likewise.
<N_Selected_Component>: Likewise.
<N_Assignment_Statement>: Adjust call to call_to_gnu.
Build an atomic store to the LHS if needed.
<N_Function_Call>: Adjust call to call_to_gnu.
* gcc-interface/utils2.c: Include toplev.h.
(resolve_atomic_size): New static function.
(build_atomic_load): New function.
(build_atomic_store): Likewise.
* gcc-interface/Make-lang.in (ada/utils2.o): Add toplev.h.
From-SVN: r181267
Diffstat (limited to 'gcc/ada/gcc-interface/utils2.c')
-rw-r--r-- | gcc/ada/gcc-interface/utils2.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/gcc/ada/gcc-interface/utils2.c b/gcc/ada/gcc-interface/utils2.c index 4075a27..c303e2f 100644 --- a/gcc/ada/gcc-interface/utils2.c +++ b/gcc/ada/gcc-interface/utils2.c @@ -29,6 +29,7 @@ #include "tm.h" #include "tree.h" #include "flags.h" +#include "toplev.h" #include "ggc.h" #include "output.h" #include "tree-inline.h" @@ -590,6 +591,112 @@ nonbinary_modular_operation (enum tree_code op_code, tree type, tree lhs, return convert (type, result); } +/* This page contains routines that implement the Ada semantics with regard + to atomic objects. They are fully piggybacked on the middle-end support + for atomic loads and stores. + + *** Memory barriers and volatile objects *** + + We implement the weakened form of the C.6(16) clause that was introduced + in Ada 2012 (AI05-117). Earlier forms of this clause wouldn't have been + implementable without significant performance hits on modern platforms. + + We also take advantage of the requirements imposed on shared variables by + 9.10 (conditions for sequential actions) to have non-erroneous execution + and consider that C.6(16) and C.6(17) only prescribe an uniform order of + volatile updates with regard to sequential actions, i.e. with regard to + reads or updates of atomic objects. + + As such, an update of an atomic object by a task requires that all earlier + accesses to volatile objects have completed. Similarly, later accesses to + volatile objects cannot be reordered before the update of the atomic object. + So, memory barriers both before and after the atomic update are needed. + + For a read of an atomic object, to avoid seeing writes of volatile objects + by a task earlier than by the other tasks, a memory barrier is needed before + the atomic read. Finally, to avoid reordering later reads or updates of + volatile objects to before the atomic read, a barrier is needed after the + atomic read. + + So, memory barriers are needed before and after atomic reads and updates. + And, in order to simplify the implementation, we use full memory barriers + in all cases, i.e. we enforce sequential consistency for atomic accesses. */ + +/* Return the size of TYPE, which must be a positive power of 2. */ + +static unsigned int +resolve_atomic_size (tree type) +{ + unsigned HOST_WIDE_INT size = tree_low_cst (TYPE_SIZE_UNIT (type), 1); + + if (size == 1 || size == 2 || size == 4 || size == 8 || size == 16) + return size; + + /* We shouldn't reach here without having already detected that the size + isn't compatible with an atomic access. */ + gcc_assert (Serious_Errors_Detected); + + return 0; +} + +/* Build an atomic load for the underlying atomic object in SRC. */ + +tree +build_atomic_load (tree src) +{ + tree ptr_type + = build_pointer_type + (build_qualified_type (void_type_node, TYPE_QUAL_VOLATILE)); + tree mem_model = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST); + tree orig_src = src; + tree type = TREE_TYPE (src); + tree t, val; + unsigned int size; + int fncode; + + src = remove_conversions (src, false); + size = resolve_atomic_size (TREE_TYPE (src)); + if (size == 0) + return orig_src; + + fncode = (int) BUILT_IN_ATOMIC_LOAD_N + exact_log2 (size) + 1; + t = builtin_decl_implicit ((enum built_in_function) fncode); + + src = build_unary_op (ADDR_EXPR, ptr_type, src); + val = build_call_expr (t, 2, src, mem_model); + + return unchecked_convert (type, val, true); +} + +/* Build an atomic store from SRC to the underlying atomic object in DEST. */ + +tree +build_atomic_store (tree dest, tree src) +{ + tree ptr_type + = build_pointer_type + (build_qualified_type (void_type_node, TYPE_QUAL_VOLATILE)); + tree mem_model = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST); + tree orig_dest = dest; + tree t, int_type; + unsigned int size; + int fncode; + + dest = remove_conversions (dest, false); + size = resolve_atomic_size (TREE_TYPE (dest)); + if (size == 0) + return build_binary_op (MODIFY_EXPR, NULL_TREE, orig_dest, src); + + fncode = (int) BUILT_IN_ATOMIC_STORE_N + exact_log2 (size) + 1; + t = builtin_decl_implicit ((enum built_in_function) fncode); + int_type = gnat_type_for_size (BITS_PER_UNIT * size, 1); + + dest = build_unary_op (ADDR_EXPR, ptr_type, dest); + src = unchecked_convert (int_type, src, true); + + return build_call_expr (t, 3, dest, src, mem_model); +} + /* Make a binary operation of kind OP_CODE. RESULT_TYPE is the type desired for the result. Usually the operation is to be performed in that type. For INIT_EXPR and MODIFY_EXPR, RESULT_TYPE must be |