diff options
-rw-r--r-- | gcc/ada/ChangeLog | 24 | ||||
-rw-r--r-- | gcc/ada/fe.h | 16 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/Make-lang.in | 2 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/gigi.h | 6 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/trans.c | 154 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/utils2.c | 107 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/atomic6_1.adb | 39 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/atomic6_2.adb | 45 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/atomic6_3.adb | 58 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/atomic6_4.adb | 45 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/atomic6_5.adb | 38 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/atomic6_6.adb | 39 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/atomic6_7.adb | 40 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/atomic6_8.adb | 37 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/atomic6_pkg.ads | 34 |
16 files changed, 671 insertions, 25 deletions
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 51b2719..83b31547 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,27 @@ +2011-11-10 Eric Botcazou <ebotcazou@adacore.com> + + * 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. + 2011-11-07 Olivier Hainque <hainque@adacore.com> * sigtramp-ppcvxw.c: Add general comments. diff --git a/gcc/ada/fe.h b/gcc/ada/fe.h index 18b1461..fe6b22d 100644 --- a/gcc/ada/fe.h +++ b/gcc/ada/fe.h @@ -92,13 +92,15 @@ extern void Set_Identifier_Casing (Char *, const Char *); /* err_vars: */ -#define Error_Msg_Node_2 err_vars__error_msg_node_2 -#define Error_Msg_Uint_1 err_vars__error_msg_uint_1 -#define Error_Msg_Uint_2 err_vars__error_msg_uint_2 - -extern Entity_Id Error_Msg_Node_2; -extern Uint Error_Msg_Uint_1; -extern Uint Error_Msg_Uint_2; +#define Error_Msg_Node_2 err_vars__error_msg_node_2 +#define Error_Msg_Uint_1 err_vars__error_msg_uint_1 +#define Error_Msg_Uint_2 err_vars__error_msg_uint_2 +#define Serious_Errors_Detected err_vars__serious_errors_detected + +extern Entity_Id Error_Msg_Node_2; +extern Uint Error_Msg_Uint_1; +extern Uint Error_Msg_Uint_2; +extern Nat Serious_Errors_Detected; /* exp_ch11: */ diff --git a/gcc/ada/gcc-interface/Make-lang.in b/gcc/ada/gcc-interface/Make-lang.in index 221d326..3ff28a6 100644 --- a/gcc/ada/gcc-interface/Make-lang.in +++ b/gcc/ada/gcc-interface/Make-lang.in @@ -1297,7 +1297,7 @@ ada/utils.o : ada/gcc-interface/utils.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(COMPILER) -c $(ALL_COMPILERFLAGS) -I.. $(ALL_CPPFLAGS) $< -o $@ ada/utils2.o : ada/gcc-interface/utils2.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(TREE_H) $(FLAGS_H) output.h $(TREE_INLINE_H) \ + $(TM_H) $(TREE_H) $(FLAGS_H) toplev.h output.h $(TREE_INLINE_H) \ ada/gcc-interface/ada.h ada/types.h ada/atree.h ada/elists.h ada/namet.h \ ada/nlists.h ada/snames.h ada/stringt.h ada/uintp.h ada/fe.h ada/sinfo.h \ ada/einfo.h $(ADA_TREE_H) ada/gcc-interface/gigi.h diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h index 1439261..e22c444 100644 --- a/gcc/ada/gcc-interface/gigi.h +++ b/gcc/ada/gcc-interface/gigi.h @@ -804,6 +804,12 @@ extern unsigned int known_alignment (tree exp); of 2. */ extern bool value_factor_p (tree value, HOST_WIDE_INT factor); +/* Build an atomic load for the underlying atomic object in SRC. */ +extern tree build_atomic_load (tree src); + +/* Build an atomic store from SRC to the underlying atomic object in DEST. */ +extern tree build_atomic_store (tree dest, tree src); + /* 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 MODIFY_EXPR and ARRAY_REF, RESULT_TYPE may be 0 diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index 1f43f4d..8a74e6c 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -3300,6 +3300,60 @@ Subprogram_Body_to_gnu (Node_Id gnat_node) mark_out_of_scope (Defining_Unit_Name (Specification (gnat_node))); } +/* Return true if GNAT_NODE requires atomic synchronization. */ + +static bool +atomic_sync_required_p (Node_Id gnat_node) +{ + const Node_Id gnat_parent = Parent (gnat_node); + Node_Kind kind; + unsigned char attr_id; + + /* First, scan the node to find the Atomic_Sync_Required flag. */ + kind = Nkind (gnat_node); + if (kind == N_Type_Conversion || kind == N_Unchecked_Type_Conversion) + { + gnat_node = Expression (gnat_node); + kind = Nkind (gnat_node); + } + + switch (kind) + { + case N_Expanded_Name: + case N_Explicit_Dereference: + case N_Identifier: + case N_Indexed_Component: + case N_Selected_Component: + if (!Atomic_Sync_Required (gnat_node)) + return false; + break; + + default: + return false; + } + + /* Then, scan the parent to find out cases where the flag is irrelevant. */ + kind = Nkind (gnat_parent); + switch (kind) + { + case N_Attribute_Reference: + attr_id = Get_Attribute_Id (Attribute_Name (gnat_parent)); + /* Do not mess up machine code insertions. */ + if (attr_id == Attr_Asm_Input || attr_id == Attr_Asm_Output) + return false; + break; + + case N_Object_Renaming_Declaration: + /* Do not generate a function call as a renamed object. */ + return false; + + default: + break; + } + + return true; +} + /* Create a temporary variable with PREFIX and TYPE, and return it. */ static tree @@ -3334,10 +3388,13 @@ create_init_temporary (const char *prefix, tree gnu_init, tree *gnu_init_stmt, or an N_Procedure_Call_Statement, to a GCC tree, which is returned. GNU_RESULT_TYPE_P is a pointer to where we should place the result type. If GNU_TARGET is non-null, this must be a function call on the RHS of a - N_Assignment_Statement and the result is to be placed into that object. */ + N_Assignment_Statement and the result is to be placed into that object. + If, in addition, ATOMIC_SYNC is true, then the assignment to GNU_TARGET + requires atomic synchronization. */ static tree -call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) +call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, + bool atomic_sync) { const bool function_call = (Nkind (gnat_node) == N_Function_Call); const bool returning_value = (function_call && !gnu_target); @@ -3433,6 +3490,11 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) tree gnu_formal_type = gnat_to_gnu_type (Etype (gnat_formal)); const bool is_true_formal_parm = gnu_formal && TREE_CODE (gnu_formal) == PARM_DECL; + const bool is_by_ref_formal_parm + = is_true_formal_parm + && (DECL_BY_REF_P (gnu_formal) + || DECL_BY_COMPONENT_PTR_P (gnu_formal) + || DECL_BY_DESCRIPTOR_P (gnu_formal)); /* In the Out or In Out case, we must suppress conversions that yield an lvalue but can nevertheless cause the creation of a temporary, because we need the real object in this case, either to pass its @@ -3462,10 +3524,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) /* If we are passing a non-addressable parameter by reference, pass the address of a copy. In the Out or In Out case, set up to copy back out after the call. */ - if (is_true_formal_parm - && (DECL_BY_REF_P (gnu_formal) - || DECL_BY_COMPONENT_PTR_P (gnu_formal) - || DECL_BY_DESCRIPTOR_P (gnu_formal)) + if (is_by_ref_formal_parm && (gnu_name_type = gnat_to_gnu_type (Etype (gnat_name))) && !addressable_p (gnu_name, gnu_name_type)) { @@ -3569,6 +3628,14 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) /* Start from the real object and build the actual. */ gnu_actual = gnu_name; + /* If this is an atomic access of an In or In Out parameter for which + synchronization is required, build the atomic load. */ + if (is_true_formal_parm + && !is_by_ref_formal_parm + && Ekind (gnat_formal) != E_Out_Parameter + && atomic_sync_required_p (gnat_actual)) + gnu_actual = build_atomic_load (gnu_actual); + /* If this was a procedure call, we may not have removed any padding. So do it here for the part we will use as an input, if any. */ if (Ekind (gnat_formal) != E_Out_Parameter @@ -3865,8 +3932,11 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) gnu_result = convert (TREE_TYPE (gnu_actual), gnu_result); } - gnu_result = build_binary_op (MODIFY_EXPR, NULL_TREE, - gnu_actual, gnu_result); + if (atomic_sync_required_p (gnat_actual)) + gnu_result = build_atomic_store (gnu_actual, gnu_result); + else + gnu_result = build_binary_op (MODIFY_EXPR, NULL_TREE, + gnu_actual, gnu_result); set_expr_location_from_node (gnu_result, gnat_node); append_to_statement_list (gnu_result, &gnu_stmt_list); gnu_cico_list = TREE_CHAIN (gnu_cico_list); @@ -3919,8 +3989,11 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) else op_code = MODIFY_EXPR; - gnu_call - = build_binary_op (op_code, NULL_TREE, gnu_target, gnu_call); + if (atomic_sync) + gnu_call = build_atomic_store (gnu_target, gnu_call); + else + gnu_call + = build_binary_op (op_code, NULL_TREE, gnu_target, gnu_call); set_expr_location_from_node (gnu_call, gnat_parent); append_to_statement_list (gnu_call, &gnu_stmt_list); } @@ -4494,6 +4567,26 @@ lhs_or_actual_p (Node_Id gnat_node) return false; } +/* Return true if either GNAT_NODE or a view of GNAT_NODE is on the LHS + of an assignment or an actual parameter of a call. */ + +static bool +present_in_lhs_or_actual_p (Node_Id gnat_node) +{ + Node_Kind kind; + + if (lhs_or_actual_p (gnat_node)) + return true; + + kind = Nkind (Parent (gnat_node)); + + if ((kind == N_Type_Conversion || kind == N_Unchecked_Type_Conversion) + && lhs_or_actual_p (Parent (gnat_node))) + return true; + + return false; +} + /* Return true if GNAT_NODE, an unchecked type conversion, is a no-op as far as gigi is concerned. This is used to avoid conversions on the LHS. */ @@ -4613,6 +4706,12 @@ gnat_to_gnu (Node_Id gnat_node) case N_Operator_Symbol: case N_Defining_Identifier: gnu_result = Identifier_to_gnu (gnat_node, &gnu_result_type); + + /* If this is an atomic access on the RHS for which synchronization is + required, build the atomic load. */ + if (atomic_sync_required_p (gnat_node) + && !present_in_lhs_or_actual_p (gnat_node)) + gnu_result = build_atomic_load (gnu_result); break; case N_Integer_Literal: @@ -4897,6 +4996,12 @@ gnat_to_gnu (Node_Id gnat_node) gnu_result = gnat_to_gnu (Prefix (gnat_node)); gnu_result_type = get_unpadded_type (Etype (gnat_node)); gnu_result = build_unary_op (INDIRECT_REF, NULL_TREE, gnu_result); + + /* If this is an atomic access on the RHS for which synchronization is + required, build the atomic load. */ + if (atomic_sync_required_p (gnat_node) + && !present_in_lhs_or_actual_p (gnat_node)) + gnu_result = build_atomic_load (gnu_result); break; case N_Indexed_Component: @@ -4963,9 +5068,15 @@ gnat_to_gnu (Node_Id gnat_node) gnu_result = build_binary_op (ARRAY_REF, NULL_TREE, gnu_result, gnu_expr); } - } - gnu_result_type = get_unpadded_type (Etype (gnat_node)); + gnu_result_type = get_unpadded_type (Etype (gnat_node)); + + /* If this is an atomic access on the RHS for which synchronization is + required, build the atomic load. */ + if (atomic_sync_required_p (gnat_node) + && !present_in_lhs_or_actual_p (gnat_node)) + gnu_result = build_atomic_load (gnu_result); + } break; case N_Slice: @@ -5110,8 +5221,13 @@ gnat_to_gnu (Node_Id gnat_node) (Parent (gnat_node))); } - gcc_assert (gnu_result); gnu_result_type = get_unpadded_type (Etype (gnat_node)); + + /* If this is an atomic access on the RHS for which synchronization is + required, build the atomic load. */ + if (atomic_sync_required_p (gnat_node) + && !present_in_lhs_or_actual_p (gnat_node)) + gnu_result = build_atomic_load (gnu_result); } break; @@ -5618,7 +5734,8 @@ gnat_to_gnu (Node_Id gnat_node) N_Raise_Storage_Error); else if (Nkind (Expression (gnat_node)) == N_Function_Call) gnu_result - = call_to_gnu (Expression (gnat_node), &gnu_result_type, gnu_lhs); + = call_to_gnu (Expression (gnat_node), &gnu_result_type, gnu_lhs, + atomic_sync_required_p (Name (gnat_node))); else { gnu_rhs @@ -5629,8 +5746,11 @@ gnat_to_gnu (Node_Id gnat_node) gnu_rhs = emit_range_check (gnu_rhs, Etype (Name (gnat_node)), gnat_node); - gnu_result - = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_lhs, gnu_rhs); + if (atomic_sync_required_p (Name (gnat_node))) + gnu_result = build_atomic_store (gnu_lhs, gnu_rhs); + else + gnu_result + = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_lhs, gnu_rhs); /* If the type being assigned is an array type and the two sides are not completely disjoint, play safe and use memmove. But don't do @@ -5880,7 +6000,7 @@ gnat_to_gnu (Node_Id gnat_node) case N_Function_Call: case N_Procedure_Call_Statement: - gnu_result = call_to_gnu (gnat_node, &gnu_result_type, NULL_TREE); + gnu_result = call_to_gnu (gnat_node, &gnu_result_type, NULL_TREE, false); break; /************************/ 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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9615be5..e988797 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2011-11-10 Eric Botcazou <ebotcazou@adacore.com> + + * gnat.dg/atomic6_1.adb: New test. + * gnat.dg/atomic6_2.adb: Likewise. + * gnat.dg/atomic6_3.adb: Likewise. + * gnat.dg/atomic6_4.adb: Likewise. + * gnat.dg/atomic6_5.adb: Likewise. + * gnat.dg/atomic6_6.adb: Likewise. + * gnat.dg/atomic6_7.adb: Likewise. + * gnat.dg/atomic6_8.adb: Likewise. + * gnat.dg/atomic6_pkg.ads: New helper. + 2011-11-10 Jakub Jelinek <jakub@redhat.com> PR middle-end/51077 diff --git a/gcc/testsuite/gnat.dg/atomic6_1.adb b/gcc/testsuite/gnat.dg/atomic6_1.adb new file mode 100644 index 0000000..714ceb6 --- /dev/null +++ b/gcc/testsuite/gnat.dg/atomic6_1.adb @@ -0,0 +1,39 @@ +-- { dg-do compile } +-- { dg-options "-fdump-tree-gimple" } + +with Atomic6_Pkg; use Atomic6_Pkg; + +procedure Atomic6_1 is + Temp : Integer; +begin + + Counter1 := Counter2; + + Timer1 := Timer2; + + Counter1 := Int(Timer1); + Timer1 := Integer(Counter1); + + Temp := Integer(Counter1); + Counter1 := Int(Temp); + + Temp := Timer1; + Timer1 := Temp; + +end; + +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter1" 2 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter2" 1 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer1" 2 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer2" 1 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*ptr" 0 "gimple"} } + +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter1" 3 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer1" 3 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*ptr" 0 "gimple"} } + +-- { dg-final { cleanup-tree-dump "gimple" } } diff --git a/gcc/testsuite/gnat.dg/atomic6_2.adb b/gcc/testsuite/gnat.dg/atomic6_2.adb new file mode 100644 index 0000000..4ecef9b --- /dev/null +++ b/gcc/testsuite/gnat.dg/atomic6_2.adb @@ -0,0 +1,45 @@ +-- { dg-do compile } +-- { dg-options "-fdump-tree-gimple" } + +with Atomic6_Pkg; use Atomic6_Pkg; + +procedure Atomic6_2 is + Temp : Integer; +begin + + Counter1 := Counter1 + Counter2; + + Timer1 := Timer1 + Timer2; + + Counter1 := Counter1 + Int(Timer1); + Timer1 := Timer1 + Integer(Counter1); + + Temp := Integer(Counter1) + Timer1; + Counter1 := Int(Timer1) + Int(Temp); + Timer1 := Integer(Counter1) + Temp; + + if Counter1 /= Counter2 then + raise Program_Error; + end if; + + if Timer1 /= Timer2 then + raise Program_Error; + end if; + +end; + +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter1" 6 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter2" 2 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer1" 6 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer2" 2 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*ptr" 0 "gimple"} } + +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter1" 3 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer1" 3 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*ptr" 0 "gimple"} } + +-- { dg-final { cleanup-tree-dump "gimple" } } diff --git a/gcc/testsuite/gnat.dg/atomic6_3.adb b/gcc/testsuite/gnat.dg/atomic6_3.adb new file mode 100644 index 0000000..86b6d81 --- /dev/null +++ b/gcc/testsuite/gnat.dg/atomic6_3.adb @@ -0,0 +1,58 @@ +-- { dg-do compile } +-- { dg-options "-fdump-tree-gimple" } + +with Atomic6_Pkg; use Atomic6_Pkg; + +procedure Atomic6_3 is + + function F (I : Integer) return Integer is + begin + return I; + end; + + function F2 return Integer is + begin + return Integer(Counter1); + end; + + function F3 return Integer is + begin + return Timer1; + end; + + Temp : Integer; +begin + + Counter1 := Int(F(Integer(Counter2))); + + Timer1 := F(Timer2); + + Counter1 := Int(F(Timer1)); + Timer1 := F(Integer(Counter1)); + + Temp := F(Integer(Counter1)); + Counter1 := Int(F(Temp)); + + Temp := F(Timer1); + Timer1 := F(Temp); + + Temp := F2; + Temp := F3; + +end; + +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter1" 3 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter2" 1 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer1" 3 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer2" 1 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*ptr" 0 "gimple"} } + +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter1" 3 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer1" 3 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*ptr" 0 "gimple"} } + +-- { dg-final { cleanup-tree-dump "gimple" } } diff --git a/gcc/testsuite/gnat.dg/atomic6_4.adb b/gcc/testsuite/gnat.dg/atomic6_4.adb new file mode 100644 index 0000000..cf960fb --- /dev/null +++ b/gcc/testsuite/gnat.dg/atomic6_4.adb @@ -0,0 +1,45 @@ +-- { dg-do compile } +-- { dg-options "-fdump-tree-gimple" } + +with Atomic6_Pkg; use Atomic6_Pkg; + +procedure Atomic6_4 is + + procedure P (I1 : out Integer; I2 : in Integer) is + begin + I1 := I2; + end; + + Temp : Integer; +begin + + P (Integer(Counter1), Integer(Counter2)); + + P (Timer1, Timer2); + + P (Integer(Counter1), Timer1); + P (Timer1, Integer(Counter1)); + + P (Temp, Integer(Counter1)); + P (Integer(Counter1), Temp); + + P (Temp, Timer1); + P (Timer1, Temp); + +end; + +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter1" 2 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter2" 1 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer1" 2 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer2" 1 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*ptr" 0 "gimple"} } + +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter1" 3 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer1" 3 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*ptr" 0 "gimple"} } + +-- { dg-final { cleanup-tree-dump "gimple" } } diff --git a/gcc/testsuite/gnat.dg/atomic6_5.adb b/gcc/testsuite/gnat.dg/atomic6_5.adb new file mode 100644 index 0000000..5490f3a --- /dev/null +++ b/gcc/testsuite/gnat.dg/atomic6_5.adb @@ -0,0 +1,38 @@ +-- { dg-do compile } +-- { dg-options "-fdump-tree-gimple" } + +with Atomic6_Pkg; use Atomic6_Pkg; + +procedure Atomic6_5 is + type Arr is array (Integer range 1 .. 4) of Boolean; + A : Arr; + B : Boolean; +begin + + A (Integer(Counter1)) := True; + B := A (Timer1); + + declare + pragma Suppress (Index_Check); + begin + A (Integer(Counter1)) := True; + B := A (Timer1); + end; + +end; + +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter1" 2 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer1" 2 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*ptr" 0 "gimple"} } + +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter1" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer1" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*ptr" 0 "gimple"} } + +-- { dg-final { cleanup-tree-dump "gimple" } } diff --git a/gcc/testsuite/gnat.dg/atomic6_6.adb b/gcc/testsuite/gnat.dg/atomic6_6.adb new file mode 100644 index 0000000..2c217f6 --- /dev/null +++ b/gcc/testsuite/gnat.dg/atomic6_6.adb @@ -0,0 +1,39 @@ +-- { dg-do compile } +-- { dg-options "-fdump-tree-gimple" } + +with Atomic6_Pkg; use Atomic6_Pkg; + +procedure Atomic6_6 is + Temp : Integer; +begin + + Counter(1) := Counter(2); + + Timer(1) := Timer(2); + + Counter(1) := Int(Timer(1)); + Timer(1) := Integer(Counter(1)); + + Temp := Integer(Counter(1)); + Counter(1) := Int(Temp); + + Temp := Timer(1); + Timer(1) := Temp; + +end; + +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter\\\[1" 2 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter\\\[2" 1 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer\\\[1" 2 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer\\\[2" 1 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*ptr" 0 "gimple"} } + +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter\\\[1" 3 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter\\\[2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer\\\[1" 3 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer\\\[2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*ptr" 0 "gimple"} } + +-- { dg-final { cleanup-tree-dump "gimple" } } diff --git a/gcc/testsuite/gnat.dg/atomic6_7.adb b/gcc/testsuite/gnat.dg/atomic6_7.adb new file mode 100644 index 0000000..8b48bf5 --- /dev/null +++ b/gcc/testsuite/gnat.dg/atomic6_7.adb @@ -0,0 +1,40 @@ +-- { dg-do compile } +-- { dg-options "-fdump-tree-gimple" } + +with Atomic6_Pkg; use Atomic6_Pkg; + +procedure Atomic6_7 is + My_Atomic : R; + Temp : Integer; +begin + + My_Atomic.Counter1 := Counter2; + + My_Atomic.Timer1 := Timer2; + + My_Atomic.Counter1 := Int(My_Atomic.Timer1); + My_Atomic.Timer1 := Integer(My_Atomic.Counter1); + + Temp := Integer(My_Atomic.Counter1); + My_Atomic.Counter1 := Int(Temp); + + Temp := My_Atomic.Timer1; + My_Atomic.Timer1 := Temp; + +end; + +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&my_atomic.counter1" 2 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter2" 1 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&my_atomic.timer1" 2 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer2" 1 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*ptr" 0 "gimple"} } + +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&my_atomic.counter1" 3 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&my_atomic.timer1" 3 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*ptr" 0 "gimple"} } + +-- { dg-final { cleanup-tree-dump "gimple" } } diff --git a/gcc/testsuite/gnat.dg/atomic6_8.adb b/gcc/testsuite/gnat.dg/atomic6_8.adb new file mode 100644 index 0000000..7d39396 --- /dev/null +++ b/gcc/testsuite/gnat.dg/atomic6_8.adb @@ -0,0 +1,37 @@ +-- { dg-do compile } +-- { dg-options "-fdump-tree-gimple" } + +with Atomic6_Pkg; use Atomic6_Pkg; + +procedure Atomic6_8 is + Ptr : Int_Ptr := new Int; + Temp : Integer; +begin + + Ptr.all := Counter1; + + Counter1 := Ptr.all; + + Ptr.all := Int(Timer1); + Timer1 := Integer(Ptr.all); + + Temp := Integer(Ptr.all); + Ptr.all := Int(Temp); + +end; + +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter1" 1 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__counter2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer1" 1 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&atomic6_pkg__timer2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_load\[^\n\r\]*ptr" 3 "gimple"} } + +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter1" 1 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__counter2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer1" 1 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&atomic6_pkg__timer2" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*&temp" 0 "gimple"} } +-- { dg-final { scan-tree-dump-times "atomic_store\[^\n\r\]*ptr" 3 "gimple"} } + +-- { dg-final { cleanup-tree-dump "gimple" } } diff --git a/gcc/testsuite/gnat.dg/atomic6_pkg.ads b/gcc/testsuite/gnat.dg/atomic6_pkg.ads new file mode 100644 index 0000000..aad2435 --- /dev/null +++ b/gcc/testsuite/gnat.dg/atomic6_pkg.ads @@ -0,0 +1,34 @@ +package Atomic6_Pkg is + + type Int is new Integer; + pragma Atomic (Int); + + Counter1 : Int; + Counter2 : Int; + + Timer1 : Integer; + pragma Atomic (Timer1); + + Timer2 : Integer; + pragma Atomic (Timer2); + + type Arr1 is array (1..8) of Int; + Counter : Arr1; + + type Arr2 is array (1..8) of Integer; + pragma Atomic_Components (Arr2); + Timer : Arr2; + + type R is record + Counter1 : Int; + Timer1 : Integer; + pragma Atomic (Timer1); + Counter2 : Int; + Timer2 : Integer; + pragma Atomic (Timer2); + Dummy : Integer; + end record; + + type Int_Ptr is access all Int; + +end Atomic6_Pkg; |